annot-server/static/js/lib.js
changeset 84 d7c5bffdd2d8
child 117 c0034b35c44e
equal deleted inserted replaced
83:9be99c2fb279 84:d7c5bffdd2d8
       
     1 /*!
       
     2  * jQuery JavaScript Library v2.1.1
       
     3  * http://jquery.com/
       
     4  *
       
     5  * Includes Sizzle.js
       
     6  * http://sizzlejs.com/
       
     7  *
       
     8  * Copyright 2005, 2014 jQuery Foundation, Inc. and other contributors
       
     9  * Released under the MIT license
       
    10  * http://jquery.org/license
       
    11  *
       
    12  * Date: 2014-05-01T17:11Z
       
    13  */
       
    14 
       
    15 (function( global, factory ) {
       
    16 
       
    17 	if ( typeof module === "object" && typeof module.exports === "object" ) {
       
    18 		// For CommonJS and CommonJS-like environments where a proper window is present,
       
    19 		// execute the factory and get jQuery
       
    20 		// For environments that do not inherently posses a window with a document
       
    21 		// (such as Node.js), expose a jQuery-making factory as module.exports
       
    22 		// This accentuates the need for the creation of a real window
       
    23 		// e.g. var jQuery = require("jquery")(window);
       
    24 		// See ticket #14549 for more info
       
    25 		module.exports = global.document ?
       
    26 			factory( global, true ) :
       
    27 			function( w ) {
       
    28 				if ( !w.document ) {
       
    29 					throw new Error( "jQuery requires a window with a document" );
       
    30 				}
       
    31 				return factory( w );
       
    32 			};
       
    33 	} else {
       
    34 		factory( global );
       
    35 	}
       
    36 
       
    37 // Pass this if window is not defined yet
       
    38 }(typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
       
    39 
       
    40 // Can't do this because several apps including ASP.NET trace
       
    41 // the stack via arguments.caller.callee and Firefox dies if
       
    42 // you try to trace through "use strict" call chains. (#13335)
       
    43 // Support: Firefox 18+
       
    44 //
       
    45 
       
    46 var arr = [];
       
    47 
       
    48 var slice = arr.slice;
       
    49 
       
    50 var concat = arr.concat;
       
    51 
       
    52 var push = arr.push;
       
    53 
       
    54 var indexOf = arr.indexOf;
       
    55 
       
    56 var class2type = {};
       
    57 
       
    58 var toString = class2type.toString;
       
    59 
       
    60 var hasOwn = class2type.hasOwnProperty;
       
    61 
       
    62 var support = {};
       
    63 
       
    64 
       
    65 
       
    66 var
       
    67 	// Use the correct document accordingly with window argument (sandbox)
       
    68 	document = window.document,
       
    69 
       
    70 	version = "2.1.1",
       
    71 
       
    72 	// Define a local copy of jQuery
       
    73 	jQuery = function( selector, context ) {
       
    74 		// The jQuery object is actually just the init constructor 'enhanced'
       
    75 		// Need init if jQuery is called (just allow error to be thrown if not included)
       
    76 		return new jQuery.fn.init( selector, context );
       
    77 	},
       
    78 
       
    79 	// Support: Android<4.1
       
    80 	// Make sure we trim BOM and NBSP
       
    81 	rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
       
    82 
       
    83 	// Matches dashed string for camelizing
       
    84 	rmsPrefix = /^-ms-/,
       
    85 	rdashAlpha = /-([\da-z])/gi,
       
    86 
       
    87 	// Used by jQuery.camelCase as callback to replace()
       
    88 	fcamelCase = function( all, letter ) {
       
    89 		return letter.toUpperCase();
       
    90 	};
       
    91 
       
    92 jQuery.fn = jQuery.prototype = {
       
    93 	// The current version of jQuery being used
       
    94 	jquery: version,
       
    95 
       
    96 	constructor: jQuery,
       
    97 
       
    98 	// Start with an empty selector
       
    99 	selector: "",
       
   100 
       
   101 	// The default length of a jQuery object is 0
       
   102 	length: 0,
       
   103 
       
   104 	toArray: function() {
       
   105 		return slice.call( this );
       
   106 	},
       
   107 
       
   108 	// Get the Nth element in the matched element set OR
       
   109 	// Get the whole matched element set as a clean array
       
   110 	get: function( num ) {
       
   111 		return num != null ?
       
   112 
       
   113 			// Return just the one element from the set
       
   114 			( num < 0 ? this[ num + this.length ] : this[ num ] ) :
       
   115 
       
   116 			// Return all the elements in a clean array
       
   117 			slice.call( this );
       
   118 	},
       
   119 
       
   120 	// Take an array of elements and push it onto the stack
       
   121 	// (returning the new matched element set)
       
   122 	pushStack: function( elems ) {
       
   123 
       
   124 		// Build a new jQuery matched element set
       
   125 		var ret = jQuery.merge( this.constructor(), elems );
       
   126 
       
   127 		// Add the old object onto the stack (as a reference)
       
   128 		ret.prevObject = this;
       
   129 		ret.context = this.context;
       
   130 
       
   131 		// Return the newly-formed element set
       
   132 		return ret;
       
   133 	},
       
   134 
       
   135 	// Execute a callback for every element in the matched set.
       
   136 	// (You can seed the arguments with an array of args, but this is
       
   137 	// only used internally.)
       
   138 	each: function( callback, args ) {
       
   139 		return jQuery.each( this, callback, args );
       
   140 	},
       
   141 
       
   142 	map: function( callback ) {
       
   143 		return this.pushStack( jQuery.map(this, function( elem, i ) {
       
   144 			return callback.call( elem, i, elem );
       
   145 		}));
       
   146 	},
       
   147 
       
   148 	slice: function() {
       
   149 		return this.pushStack( slice.apply( this, arguments ) );
       
   150 	},
       
   151 
       
   152 	first: function() {
       
   153 		return this.eq( 0 );
       
   154 	},
       
   155 
       
   156 	last: function() {
       
   157 		return this.eq( -1 );
       
   158 	},
       
   159 
       
   160 	eq: function( i ) {
       
   161 		var len = this.length,
       
   162 			j = +i + ( i < 0 ? len : 0 );
       
   163 		return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );
       
   164 	},
       
   165 
       
   166 	end: function() {
       
   167 		return this.prevObject || this.constructor(null);
       
   168 	},
       
   169 
       
   170 	// For internal use only.
       
   171 	// Behaves like an Array's method, not like a jQuery method.
       
   172 	push: push,
       
   173 	sort: arr.sort,
       
   174 	splice: arr.splice
       
   175 };
       
   176 
       
   177 jQuery.extend = jQuery.fn.extend = function() {
       
   178 	var options, name, src, copy, copyIsArray, clone,
       
   179 		target = arguments[0] || {},
       
   180 		i = 1,
       
   181 		length = arguments.length,
       
   182 		deep = false;
       
   183 
       
   184 	// Handle a deep copy situation
       
   185 	if ( typeof target === "boolean" ) {
       
   186 		deep = target;
       
   187 
       
   188 		// skip the boolean and the target
       
   189 		target = arguments[ i ] || {};
       
   190 		i++;
       
   191 	}
       
   192 
       
   193 	// Handle case when target is a string or something (possible in deep copy)
       
   194 	if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
       
   195 		target = {};
       
   196 	}
       
   197 
       
   198 	// extend jQuery itself if only one argument is passed
       
   199 	if ( i === length ) {
       
   200 		target = this;
       
   201 		i--;
       
   202 	}
       
   203 
       
   204 	for ( ; i < length; i++ ) {
       
   205 		// Only deal with non-null/undefined values
       
   206 		if ( (options = arguments[ i ]) != null ) {
       
   207 			// Extend the base object
       
   208 			for ( name in options ) {
       
   209 				src = target[ name ];
       
   210 				copy = options[ name ];
       
   211 
       
   212 				// Prevent never-ending loop
       
   213 				if ( target === copy ) {
       
   214 					continue;
       
   215 				}
       
   216 
       
   217 				// Recurse if we're merging plain objects or arrays
       
   218 				if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
       
   219 					if ( copyIsArray ) {
       
   220 						copyIsArray = false;
       
   221 						clone = src && jQuery.isArray(src) ? src : [];
       
   222 
       
   223 					} else {
       
   224 						clone = src && jQuery.isPlainObject(src) ? src : {};
       
   225 					}
       
   226 
       
   227 					// Never move original objects, clone them
       
   228 					target[ name ] = jQuery.extend( deep, clone, copy );
       
   229 
       
   230 				// Don't bring in undefined values
       
   231 				} else if ( copy !== undefined ) {
       
   232 					target[ name ] = copy;
       
   233 				}
       
   234 			}
       
   235 		}
       
   236 	}
       
   237 
       
   238 	// Return the modified object
       
   239 	return target;
       
   240 };
       
   241 
       
   242 jQuery.extend({
       
   243 	// Unique for each copy of jQuery on the page
       
   244 	expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),
       
   245 
       
   246 	// Assume jQuery is ready without the ready module
       
   247 	isReady: true,
       
   248 
       
   249 	error: function( msg ) {
       
   250 		throw new Error( msg );
       
   251 	},
       
   252 
       
   253 	noop: function() {},
       
   254 
       
   255 	// See test/unit/core.js for details concerning isFunction.
       
   256 	// Since version 1.3, DOM methods and functions like alert
       
   257 	// aren't supported. They return false on IE (#2968).
       
   258 	isFunction: function( obj ) {
       
   259 		return jQuery.type(obj) === "function";
       
   260 	},
       
   261 
       
   262 	isArray: Array.isArray,
       
   263 
       
   264 	isWindow: function( obj ) {
       
   265 		return obj != null && obj === obj.window;
       
   266 	},
       
   267 
       
   268 	isNumeric: function( obj ) {
       
   269 		// parseFloat NaNs numeric-cast false positives (null|true|false|"")
       
   270 		// ...but misinterprets leading-number strings, particularly hex literals ("0x...")
       
   271 		// subtraction forces infinities to NaN
       
   272 		return !jQuery.isArray( obj ) && obj - parseFloat( obj ) >= 0;
       
   273 	},
       
   274 
       
   275 	isPlainObject: function( obj ) {
       
   276 		// Not plain objects:
       
   277 		// - Any object or value whose internal [[Class]] property is not "[object Object]"
       
   278 		// - DOM nodes
       
   279 		// - window
       
   280 		if ( jQuery.type( obj ) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
       
   281 			return false;
       
   282 		}
       
   283 
       
   284 		if ( obj.constructor &&
       
   285 				!hasOwn.call( obj.constructor.prototype, "isPrototypeOf" ) ) {
       
   286 			return false;
       
   287 		}
       
   288 
       
   289 		// If the function hasn't returned already, we're confident that
       
   290 		// |obj| is a plain object, created by {} or constructed with new Object
       
   291 		return true;
       
   292 	},
       
   293 
       
   294 	isEmptyObject: function( obj ) {
       
   295 		var name;
       
   296 		for ( name in obj ) {
       
   297 			return false;
       
   298 		}
       
   299 		return true;
       
   300 	},
       
   301 
       
   302 	type: function( obj ) {
       
   303 		if ( obj == null ) {
       
   304 			return obj + "";
       
   305 		}
       
   306 		// Support: Android < 4.0, iOS < 6 (functionish RegExp)
       
   307 		return typeof obj === "object" || typeof obj === "function" ?
       
   308 			class2type[ toString.call(obj) ] || "object" :
       
   309 			typeof obj;
       
   310 	},
       
   311 
       
   312 	// Evaluates a script in a global context
       
   313 	globalEval: function( code ) {
       
   314 		var script,
       
   315 			indirect = eval;
       
   316 
       
   317 		code = jQuery.trim( code );
       
   318 
       
   319 		if ( code ) {
       
   320 			// If the code includes a valid, prologue position
       
   321 			// strict mode pragma, execute code by injecting a
       
   322 			// script tag into the document.
       
   323 			if ( code.indexOf("use strict") === 1 ) {
       
   324 				script = document.createElement("script");
       
   325 				script.text = code;
       
   326 				document.head.appendChild( script ).parentNode.removeChild( script );
       
   327 			} else {
       
   328 			// Otherwise, avoid the DOM node creation, insertion
       
   329 			// and removal by using an indirect global eval
       
   330 				indirect( code );
       
   331 			}
       
   332 		}
       
   333 	},
       
   334 
       
   335 	// Convert dashed to camelCase; used by the css and data modules
       
   336 	// Microsoft forgot to hump their vendor prefix (#9572)
       
   337 	camelCase: function( string ) {
       
   338 		return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
       
   339 	},
       
   340 
       
   341 	nodeName: function( elem, name ) {
       
   342 		return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
       
   343 	},
       
   344 
       
   345 	// args is for internal usage only
       
   346 	each: function( obj, callback, args ) {
       
   347 		var value,
       
   348 			i = 0,
       
   349 			length = obj.length,
       
   350 			isArray = isArraylike( obj );
       
   351 
       
   352 		if ( args ) {
       
   353 			if ( isArray ) {
       
   354 				for ( ; i < length; i++ ) {
       
   355 					value = callback.apply( obj[ i ], args );
       
   356 
       
   357 					if ( value === false ) {
       
   358 						break;
       
   359 					}
       
   360 				}
       
   361 			} else {
       
   362 				for ( i in obj ) {
       
   363 					value = callback.apply( obj[ i ], args );
       
   364 
       
   365 					if ( value === false ) {
       
   366 						break;
       
   367 					}
       
   368 				}
       
   369 			}
       
   370 
       
   371 		// A special, fast, case for the most common use of each
       
   372 		} else {
       
   373 			if ( isArray ) {
       
   374 				for ( ; i < length; i++ ) {
       
   375 					value = callback.call( obj[ i ], i, obj[ i ] );
       
   376 
       
   377 					if ( value === false ) {
       
   378 						break;
       
   379 					}
       
   380 				}
       
   381 			} else {
       
   382 				for ( i in obj ) {
       
   383 					value = callback.call( obj[ i ], i, obj[ i ] );
       
   384 
       
   385 					if ( value === false ) {
       
   386 						break;
       
   387 					}
       
   388 				}
       
   389 			}
       
   390 		}
       
   391 
       
   392 		return obj;
       
   393 	},
       
   394 
       
   395 	// Support: Android<4.1
       
   396 	trim: function( text ) {
       
   397 		return text == null ?
       
   398 			"" :
       
   399 			( text + "" ).replace( rtrim, "" );
       
   400 	},
       
   401 
       
   402 	// results is for internal usage only
       
   403 	makeArray: function( arr, results ) {
       
   404 		var ret = results || [];
       
   405 
       
   406 		if ( arr != null ) {
       
   407 			if ( isArraylike( Object(arr) ) ) {
       
   408 				jQuery.merge( ret,
       
   409 					typeof arr === "string" ?
       
   410 					[ arr ] : arr
       
   411 				);
       
   412 			} else {
       
   413 				push.call( ret, arr );
       
   414 			}
       
   415 		}
       
   416 
       
   417 		return ret;
       
   418 	},
       
   419 
       
   420 	inArray: function( elem, arr, i ) {
       
   421 		return arr == null ? -1 : indexOf.call( arr, elem, i );
       
   422 	},
       
   423 
       
   424 	merge: function( first, second ) {
       
   425 		var len = +second.length,
       
   426 			j = 0,
       
   427 			i = first.length;
       
   428 
       
   429 		for ( ; j < len; j++ ) {
       
   430 			first[ i++ ] = second[ j ];
       
   431 		}
       
   432 
       
   433 		first.length = i;
       
   434 
       
   435 		return first;
       
   436 	},
       
   437 
       
   438 	grep: function( elems, callback, invert ) {
       
   439 		var callbackInverse,
       
   440 			matches = [],
       
   441 			i = 0,
       
   442 			length = elems.length,
       
   443 			callbackExpect = !invert;
       
   444 
       
   445 		// Go through the array, only saving the items
       
   446 		// that pass the validator function
       
   447 		for ( ; i < length; i++ ) {
       
   448 			callbackInverse = !callback( elems[ i ], i );
       
   449 			if ( callbackInverse !== callbackExpect ) {
       
   450 				matches.push( elems[ i ] );
       
   451 			}
       
   452 		}
       
   453 
       
   454 		return matches;
       
   455 	},
       
   456 
       
   457 	// arg is for internal usage only
       
   458 	map: function( elems, callback, arg ) {
       
   459 		var value,
       
   460 			i = 0,
       
   461 			length = elems.length,
       
   462 			isArray = isArraylike( elems ),
       
   463 			ret = [];
       
   464 
       
   465 		// Go through the array, translating each of the items to their new values
       
   466 		if ( isArray ) {
       
   467 			for ( ; i < length; i++ ) {
       
   468 				value = callback( elems[ i ], i, arg );
       
   469 
       
   470 				if ( value != null ) {
       
   471 					ret.push( value );
       
   472 				}
       
   473 			}
       
   474 
       
   475 		// Go through every key on the object,
       
   476 		} else {
       
   477 			for ( i in elems ) {
       
   478 				value = callback( elems[ i ], i, arg );
       
   479 
       
   480 				if ( value != null ) {
       
   481 					ret.push( value );
       
   482 				}
       
   483 			}
       
   484 		}
       
   485 
       
   486 		// Flatten any nested arrays
       
   487 		return concat.apply( [], ret );
       
   488 	},
       
   489 
       
   490 	// A global GUID counter for objects
       
   491 	guid: 1,
       
   492 
       
   493 	// Bind a function to a context, optionally partially applying any
       
   494 	// arguments.
       
   495 	proxy: function( fn, context ) {
       
   496 		var tmp, args, proxy;
       
   497 
       
   498 		if ( typeof context === "string" ) {
       
   499 			tmp = fn[ context ];
       
   500 			context = fn;
       
   501 			fn = tmp;
       
   502 		}
       
   503 
       
   504 		// Quick check to determine if target is callable, in the spec
       
   505 		// this throws a TypeError, but we will just return undefined.
       
   506 		if ( !jQuery.isFunction( fn ) ) {
       
   507 			return undefined;
       
   508 		}
       
   509 
       
   510 		// Simulated bind
       
   511 		args = slice.call( arguments, 2 );
       
   512 		proxy = function() {
       
   513 			return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
       
   514 		};
       
   515 
       
   516 		// Set the guid of unique handler to the same of original handler, so it can be removed
       
   517 		proxy.guid = fn.guid = fn.guid || jQuery.guid++;
       
   518 
       
   519 		return proxy;
       
   520 	},
       
   521 
       
   522 	now: Date.now,
       
   523 
       
   524 	// jQuery.support is not used in Core but other projects attach their
       
   525 	// properties to it so it needs to exist.
       
   526 	support: support
       
   527 });
       
   528 
       
   529 // Populate the class2type map
       
   530 jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
       
   531 	class2type[ "[object " + name + "]" ] = name.toLowerCase();
       
   532 });
       
   533 
       
   534 function isArraylike( obj ) {
       
   535 	var length = obj.length,
       
   536 		type = jQuery.type( obj );
       
   537 
       
   538 	if ( type === "function" || jQuery.isWindow( obj ) ) {
       
   539 		return false;
       
   540 	}
       
   541 
       
   542 	if ( obj.nodeType === 1 && length ) {
       
   543 		return true;
       
   544 	}
       
   545 
       
   546 	return type === "array" || length === 0 ||
       
   547 		typeof length === "number" && length > 0 && ( length - 1 ) in obj;
       
   548 }
       
   549 var Sizzle =
       
   550 /*!
       
   551  * Sizzle CSS Selector Engine v1.10.19
       
   552  * http://sizzlejs.com/
       
   553  *
       
   554  * Copyright 2013 jQuery Foundation, Inc. and other contributors
       
   555  * Released under the MIT license
       
   556  * http://jquery.org/license
       
   557  *
       
   558  * Date: 2014-04-18
       
   559  */
       
   560 (function( window ) {
       
   561 
       
   562 var i,
       
   563 	support,
       
   564 	Expr,
       
   565 	getText,
       
   566 	isXML,
       
   567 	tokenize,
       
   568 	compile,
       
   569 	select,
       
   570 	outermostContext,
       
   571 	sortInput,
       
   572 	hasDuplicate,
       
   573 
       
   574 	// Local document vars
       
   575 	setDocument,
       
   576 	document,
       
   577 	docElem,
       
   578 	documentIsHTML,
       
   579 	rbuggyQSA,
       
   580 	rbuggyMatches,
       
   581 	matches,
       
   582 	contains,
       
   583 
       
   584 	// Instance-specific data
       
   585 	expando = "sizzle" + -(new Date()),
       
   586 	preferredDoc = window.document,
       
   587 	dirruns = 0,
       
   588 	done = 0,
       
   589 	classCache = createCache(),
       
   590 	tokenCache = createCache(),
       
   591 	compilerCache = createCache(),
       
   592 	sortOrder = function( a, b ) {
       
   593 		if ( a === b ) {
       
   594 			hasDuplicate = true;
       
   595 		}
       
   596 		return 0;
       
   597 	},
       
   598 
       
   599 	// General-purpose constants
       
   600 	strundefined = typeof undefined,
       
   601 	MAX_NEGATIVE = 1 << 31,
       
   602 
       
   603 	// Instance methods
       
   604 	hasOwn = ({}).hasOwnProperty,
       
   605 	arr = [],
       
   606 	pop = arr.pop,
       
   607 	push_native = arr.push,
       
   608 	push = arr.push,
       
   609 	slice = arr.slice,
       
   610 	// Use a stripped-down indexOf if we can't use a native one
       
   611 	indexOf = arr.indexOf || function( elem ) {
       
   612 		var i = 0,
       
   613 			len = this.length;
       
   614 		for ( ; i < len; i++ ) {
       
   615 			if ( this[i] === elem ) {
       
   616 				return i;
       
   617 			}
       
   618 		}
       
   619 		return -1;
       
   620 	},
       
   621 
       
   622 	booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
       
   623 
       
   624 	// Regular expressions
       
   625 
       
   626 	// Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
       
   627 	whitespace = "[\\x20\\t\\r\\n\\f]",
       
   628 	// http://www.w3.org/TR/css3-syntax/#characters
       
   629 	characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
       
   630 
       
   631 	// Loosely modeled on CSS identifier characters
       
   632 	// An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors
       
   633 	// Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
       
   634 	identifier = characterEncoding.replace( "w", "w#" ),
       
   635 
       
   636 	// Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
       
   637 	attributes = "\\[" + whitespace + "*(" + characterEncoding + ")(?:" + whitespace +
       
   638 		// Operator (capture 2)
       
   639 		"*([*^$|!~]?=)" + whitespace +
       
   640 		// "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
       
   641 		"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace +
       
   642 		"*\\]",
       
   643 
       
   644 	pseudos = ":(" + characterEncoding + ")(?:\\((" +
       
   645 		// To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
       
   646 		// 1. quoted (capture 3; capture 4 or capture 5)
       
   647 		"('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
       
   648 		// 2. simple (capture 6)
       
   649 		"((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +
       
   650 		// 3. anything else (capture 2)
       
   651 		".*" +
       
   652 		")\\)|)",
       
   653 
       
   654 	// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
       
   655 	rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
       
   656 
       
   657 	rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
       
   658 	rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
       
   659 
       
   660 	rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ),
       
   661 
       
   662 	rpseudo = new RegExp( pseudos ),
       
   663 	ridentifier = new RegExp( "^" + identifier + "$" ),
       
   664 
       
   665 	matchExpr = {
       
   666 		"ID": new RegExp( "^#(" + characterEncoding + ")" ),
       
   667 		"CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
       
   668 		"TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
       
   669 		"ATTR": new RegExp( "^" + attributes ),
       
   670 		"PSEUDO": new RegExp( "^" + pseudos ),
       
   671 		"CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
       
   672 			"*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
       
   673 			"*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
       
   674 		"bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
       
   675 		// For use in libraries implementing .is()
       
   676 		// We use this for POS matching in `select`
       
   677 		"needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
       
   678 			whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
       
   679 	},
       
   680 
       
   681 	rinputs = /^(?:input|select|textarea|button)$/i,
       
   682 	rheader = /^h\d$/i,
       
   683 
       
   684 	rnative = /^[^{]+\{\s*\[native \w/,
       
   685 
       
   686 	// Easily-parseable/retrievable ID or TAG or CLASS selectors
       
   687 	rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
       
   688 
       
   689 	rsibling = /[+~]/,
       
   690 	rescape = /'|\\/g,
       
   691 
       
   692 	// CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
       
   693 	runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
       
   694 	funescape = function( _, escaped, escapedWhitespace ) {
       
   695 		var high = "0x" + escaped - 0x10000;
       
   696 		// NaN means non-codepoint
       
   697 		// Support: Firefox<24
       
   698 		// Workaround erroneous numeric interpretation of +"0x"
       
   699 		return high !== high || escapedWhitespace ?
       
   700 			escaped :
       
   701 			high < 0 ?
       
   702 				// BMP codepoint
       
   703 				String.fromCharCode( high + 0x10000 ) :
       
   704 				// Supplemental Plane codepoint (surrogate pair)
       
   705 				String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
       
   706 	};
       
   707 
       
   708 // Optimize for push.apply( _, NodeList )
       
   709 try {
       
   710 	push.apply(
       
   711 		(arr = slice.call( preferredDoc.childNodes )),
       
   712 		preferredDoc.childNodes
       
   713 	);
       
   714 	// Support: Android<4.0
       
   715 	// Detect silently failing push.apply
       
   716 	arr[ preferredDoc.childNodes.length ].nodeType;
       
   717 } catch ( e ) {
       
   718 	push = { apply: arr.length ?
       
   719 
       
   720 		// Leverage slice if possible
       
   721 		function( target, els ) {
       
   722 			push_native.apply( target, slice.call(els) );
       
   723 		} :
       
   724 
       
   725 		// Support: IE<9
       
   726 		// Otherwise append directly
       
   727 		function( target, els ) {
       
   728 			var j = target.length,
       
   729 				i = 0;
       
   730 			// Can't trust NodeList.length
       
   731 			while ( (target[j++] = els[i++]) ) {}
       
   732 			target.length = j - 1;
       
   733 		}
       
   734 	};
       
   735 }
       
   736 
       
   737 function Sizzle( selector, context, results, seed ) {
       
   738 	var match, elem, m, nodeType,
       
   739 		// QSA vars
       
   740 		i, groups, old, nid, newContext, newSelector;
       
   741 
       
   742 	if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
       
   743 		setDocument( context );
       
   744 	}
       
   745 
       
   746 	context = context || document;
       
   747 	results = results || [];
       
   748 
       
   749 	if ( !selector || typeof selector !== "string" ) {
       
   750 		return results;
       
   751 	}
       
   752 
       
   753 	if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
       
   754 		return [];
       
   755 	}
       
   756 
       
   757 	if ( documentIsHTML && !seed ) {
       
   758 
       
   759 		// Shortcuts
       
   760 		if ( (match = rquickExpr.exec( selector )) ) {
       
   761 			// Speed-up: Sizzle("#ID")
       
   762 			if ( (m = match[1]) ) {
       
   763 				if ( nodeType === 9 ) {
       
   764 					elem = context.getElementById( m );
       
   765 					// Check parentNode to catch when Blackberry 4.6 returns
       
   766 					// nodes that are no longer in the document (jQuery #6963)
       
   767 					if ( elem && elem.parentNode ) {
       
   768 						// Handle the case where IE, Opera, and Webkit return items
       
   769 						// by name instead of ID
       
   770 						if ( elem.id === m ) {
       
   771 							results.push( elem );
       
   772 							return results;
       
   773 						}
       
   774 					} else {
       
   775 						return results;
       
   776 					}
       
   777 				} else {
       
   778 					// Context is not a document
       
   779 					if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
       
   780 						contains( context, elem ) && elem.id === m ) {
       
   781 						results.push( elem );
       
   782 						return results;
       
   783 					}
       
   784 				}
       
   785 
       
   786 			// Speed-up: Sizzle("TAG")
       
   787 			} else if ( match[2] ) {
       
   788 				push.apply( results, context.getElementsByTagName( selector ) );
       
   789 				return results;
       
   790 
       
   791 			// Speed-up: Sizzle(".CLASS")
       
   792 			} else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) {
       
   793 				push.apply( results, context.getElementsByClassName( m ) );
       
   794 				return results;
       
   795 			}
       
   796 		}
       
   797 
       
   798 		// QSA path
       
   799 		if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
       
   800 			nid = old = expando;
       
   801 			newContext = context;
       
   802 			newSelector = nodeType === 9 && selector;
       
   803 
       
   804 			// qSA works strangely on Element-rooted queries
       
   805 			// We can work around this by specifying an extra ID on the root
       
   806 			// and working up from there (Thanks to Andrew Dupont for the technique)
       
   807 			// IE 8 doesn't work on object elements
       
   808 			if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
       
   809 				groups = tokenize( selector );
       
   810 
       
   811 				if ( (old = context.getAttribute("id")) ) {
       
   812 					nid = old.replace( rescape, "\\$&" );
       
   813 				} else {
       
   814 					context.setAttribute( "id", nid );
       
   815 				}
       
   816 				nid = "[id='" + nid + "'] ";
       
   817 
       
   818 				i = groups.length;
       
   819 				while ( i-- ) {
       
   820 					groups[i] = nid + toSelector( groups[i] );
       
   821 				}
       
   822 				newContext = rsibling.test( selector ) && testContext( context.parentNode ) || context;
       
   823 				newSelector = groups.join(",");
       
   824 			}
       
   825 
       
   826 			if ( newSelector ) {
       
   827 				try {
       
   828 					push.apply( results,
       
   829 						newContext.querySelectorAll( newSelector )
       
   830 					);
       
   831 					return results;
       
   832 				} catch(qsaError) {
       
   833 				} finally {
       
   834 					if ( !old ) {
       
   835 						context.removeAttribute("id");
       
   836 					}
       
   837 				}
       
   838 			}
       
   839 		}
       
   840 	}
       
   841 
       
   842 	// All others
       
   843 	return select( selector.replace( rtrim, "$1" ), context, results, seed );
       
   844 }
       
   845 
       
   846 /**
       
   847  * Create key-value caches of limited size
       
   848  * @returns {Function(string, Object)} Returns the Object data after storing it on itself with
       
   849  *	property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
       
   850  *	deleting the oldest entry
       
   851  */
       
   852 function createCache() {
       
   853 	var keys = [];
       
   854 
       
   855 	function cache( key, value ) {
       
   856 		// Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
       
   857 		if ( keys.push( key + " " ) > Expr.cacheLength ) {
       
   858 			// Only keep the most recent entries
       
   859 			delete cache[ keys.shift() ];
       
   860 		}
       
   861 		return (cache[ key + " " ] = value);
       
   862 	}
       
   863 	return cache;
       
   864 }
       
   865 
       
   866 /**
       
   867  * Mark a function for special use by Sizzle
       
   868  * @param {Function} fn The function to mark
       
   869  */
       
   870 function markFunction( fn ) {
       
   871 	fn[ expando ] = true;
       
   872 	return fn;
       
   873 }
       
   874 
       
   875 /**
       
   876  * Support testing using an element
       
   877  * @param {Function} fn Passed the created div and expects a boolean result
       
   878  */
       
   879 function assert( fn ) {
       
   880 	var div = document.createElement("div");
       
   881 
       
   882 	try {
       
   883 		return !!fn( div );
       
   884 	} catch (e) {
       
   885 		return false;
       
   886 	} finally {
       
   887 		// Remove from its parent by default
       
   888 		if ( div.parentNode ) {
       
   889 			div.parentNode.removeChild( div );
       
   890 		}
       
   891 		// release memory in IE
       
   892 		div = null;
       
   893 	}
       
   894 }
       
   895 
       
   896 /**
       
   897  * Adds the same handler for all of the specified attrs
       
   898  * @param {String} attrs Pipe-separated list of attributes
       
   899  * @param {Function} handler The method that will be applied
       
   900  */
       
   901 function addHandle( attrs, handler ) {
       
   902 	var arr = attrs.split("|"),
       
   903 		i = attrs.length;
       
   904 
       
   905 	while ( i-- ) {
       
   906 		Expr.attrHandle[ arr[i] ] = handler;
       
   907 	}
       
   908 }
       
   909 
       
   910 /**
       
   911  * Checks document order of two siblings
       
   912  * @param {Element} a
       
   913  * @param {Element} b
       
   914  * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
       
   915  */
       
   916 function siblingCheck( a, b ) {
       
   917 	var cur = b && a,
       
   918 		diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
       
   919 			( ~b.sourceIndex || MAX_NEGATIVE ) -
       
   920 			( ~a.sourceIndex || MAX_NEGATIVE );
       
   921 
       
   922 	// Use IE sourceIndex if available on both nodes
       
   923 	if ( diff ) {
       
   924 		return diff;
       
   925 	}
       
   926 
       
   927 	// Check if b follows a
       
   928 	if ( cur ) {
       
   929 		while ( (cur = cur.nextSibling) ) {
       
   930 			if ( cur === b ) {
       
   931 				return -1;
       
   932 			}
       
   933 		}
       
   934 	}
       
   935 
       
   936 	return a ? 1 : -1;
       
   937 }
       
   938 
       
   939 /**
       
   940  * Returns a function to use in pseudos for input types
       
   941  * @param {String} type
       
   942  */
       
   943 function createInputPseudo( type ) {
       
   944 	return function( elem ) {
       
   945 		var name = elem.nodeName.toLowerCase();
       
   946 		return name === "input" && elem.type === type;
       
   947 	};
       
   948 }
       
   949 
       
   950 /**
       
   951  * Returns a function to use in pseudos for buttons
       
   952  * @param {String} type
       
   953  */
       
   954 function createButtonPseudo( type ) {
       
   955 	return function( elem ) {
       
   956 		var name = elem.nodeName.toLowerCase();
       
   957 		return (name === "input" || name === "button") && elem.type === type;
       
   958 	};
       
   959 }
       
   960 
       
   961 /**
       
   962  * Returns a function to use in pseudos for positionals
       
   963  * @param {Function} fn
       
   964  */
       
   965 function createPositionalPseudo( fn ) {
       
   966 	return markFunction(function( argument ) {
       
   967 		argument = +argument;
       
   968 		return markFunction(function( seed, matches ) {
       
   969 			var j,
       
   970 				matchIndexes = fn( [], seed.length, argument ),
       
   971 				i = matchIndexes.length;
       
   972 
       
   973 			// Match elements found at the specified indexes
       
   974 			while ( i-- ) {
       
   975 				if ( seed[ (j = matchIndexes[i]) ] ) {
       
   976 					seed[j] = !(matches[j] = seed[j]);
       
   977 				}
       
   978 			}
       
   979 		});
       
   980 	});
       
   981 }
       
   982 
       
   983 /**
       
   984  * Checks a node for validity as a Sizzle context
       
   985  * @param {Element|Object=} context
       
   986  * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
       
   987  */
       
   988 function testContext( context ) {
       
   989 	return context && typeof context.getElementsByTagName !== strundefined && context;
       
   990 }
       
   991 
       
   992 // Expose support vars for convenience
       
   993 support = Sizzle.support = {};
       
   994 
       
   995 /**
       
   996  * Detects XML nodes
       
   997  * @param {Element|Object} elem An element or a document
       
   998  * @returns {Boolean} True iff elem is a non-HTML XML node
       
   999  */
       
  1000 isXML = Sizzle.isXML = function( elem ) {
       
  1001 	// documentElement is verified for cases where it doesn't yet exist
       
  1002 	// (such as loading iframes in IE - #4833)
       
  1003 	var documentElement = elem && (elem.ownerDocument || elem).documentElement;
       
  1004 	return documentElement ? documentElement.nodeName !== "HTML" : false;
       
  1005 };
       
  1006 
       
  1007 /**
       
  1008  * Sets document-related variables once based on the current document
       
  1009  * @param {Element|Object} [doc] An element or document object to use to set the document
       
  1010  * @returns {Object} Returns the current document
       
  1011  */
       
  1012 setDocument = Sizzle.setDocument = function( node ) {
       
  1013 	var hasCompare,
       
  1014 		doc = node ? node.ownerDocument || node : preferredDoc,
       
  1015 		parent = doc.defaultView;
       
  1016 
       
  1017 	// If no document and documentElement is available, return
       
  1018 	if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
       
  1019 		return document;
       
  1020 	}
       
  1021 
       
  1022 	// Set our document
       
  1023 	document = doc;
       
  1024 	docElem = doc.documentElement;
       
  1025 
       
  1026 	// Support tests
       
  1027 	documentIsHTML = !isXML( doc );
       
  1028 
       
  1029 	// Support: IE>8
       
  1030 	// If iframe document is assigned to "document" variable and if iframe has been reloaded,
       
  1031 	// IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936
       
  1032 	// IE6-8 do not support the defaultView property so parent will be undefined
       
  1033 	if ( parent && parent !== parent.top ) {
       
  1034 		// IE11 does not have attachEvent, so all must suffer
       
  1035 		if ( parent.addEventListener ) {
       
  1036 			parent.addEventListener( "unload", function() {
       
  1037 				setDocument();
       
  1038 			}, false );
       
  1039 		} else if ( parent.attachEvent ) {
       
  1040 			parent.attachEvent( "onunload", function() {
       
  1041 				setDocument();
       
  1042 			});
       
  1043 		}
       
  1044 	}
       
  1045 
       
  1046 	/* Attributes
       
  1047 	---------------------------------------------------------------------- */
       
  1048 
       
  1049 	// Support: IE<8
       
  1050 	// Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans)
       
  1051 	support.attributes = assert(function( div ) {
       
  1052 		div.className = "i";
       
  1053 		return !div.getAttribute("className");
       
  1054 	});
       
  1055 
       
  1056 	/* getElement(s)By*
       
  1057 	---------------------------------------------------------------------- */
       
  1058 
       
  1059 	// Check if getElementsByTagName("*") returns only elements
       
  1060 	support.getElementsByTagName = assert(function( div ) {
       
  1061 		div.appendChild( doc.createComment("") );
       
  1062 		return !div.getElementsByTagName("*").length;
       
  1063 	});
       
  1064 
       
  1065 	// Check if getElementsByClassName can be trusted
       
  1066 	support.getElementsByClassName = rnative.test( doc.getElementsByClassName ) && assert(function( div ) {
       
  1067 		div.innerHTML = "<div class='a'></div><div class='a i'></div>";
       
  1068 
       
  1069 		// Support: Safari<4
       
  1070 		// Catch class over-caching
       
  1071 		div.firstChild.className = "i";
       
  1072 		// Support: Opera<10
       
  1073 		// Catch gEBCN failure to find non-leading classes
       
  1074 		return div.getElementsByClassName("i").length === 2;
       
  1075 	});
       
  1076 
       
  1077 	// Support: IE<10
       
  1078 	// Check if getElementById returns elements by name
       
  1079 	// The broken getElementById methods don't pick up programatically-set names,
       
  1080 	// so use a roundabout getElementsByName test
       
  1081 	support.getById = assert(function( div ) {
       
  1082 		docElem.appendChild( div ).id = expando;
       
  1083 		return !doc.getElementsByName || !doc.getElementsByName( expando ).length;
       
  1084 	});
       
  1085 
       
  1086 	// ID find and filter
       
  1087 	if ( support.getById ) {
       
  1088 		Expr.find["ID"] = function( id, context ) {
       
  1089 			if ( typeof context.getElementById !== strundefined && documentIsHTML ) {
       
  1090 				var m = context.getElementById( id );
       
  1091 				// Check parentNode to catch when Blackberry 4.6 returns
       
  1092 				// nodes that are no longer in the document #6963
       
  1093 				return m && m.parentNode ? [ m ] : [];
       
  1094 			}
       
  1095 		};
       
  1096 		Expr.filter["ID"] = function( id ) {
       
  1097 			var attrId = id.replace( runescape, funescape );
       
  1098 			return function( elem ) {
       
  1099 				return elem.getAttribute("id") === attrId;
       
  1100 			};
       
  1101 		};
       
  1102 	} else {
       
  1103 		// Support: IE6/7
       
  1104 		// getElementById is not reliable as a find shortcut
       
  1105 		delete Expr.find["ID"];
       
  1106 
       
  1107 		Expr.filter["ID"] =  function( id ) {
       
  1108 			var attrId = id.replace( runescape, funescape );
       
  1109 			return function( elem ) {
       
  1110 				var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
       
  1111 				return node && node.value === attrId;
       
  1112 			};
       
  1113 		};
       
  1114 	}
       
  1115 
       
  1116 	// Tag
       
  1117 	Expr.find["TAG"] = support.getElementsByTagName ?
       
  1118 		function( tag, context ) {
       
  1119 			if ( typeof context.getElementsByTagName !== strundefined ) {
       
  1120 				return context.getElementsByTagName( tag );
       
  1121 			}
       
  1122 		} :
       
  1123 		function( tag, context ) {
       
  1124 			var elem,
       
  1125 				tmp = [],
       
  1126 				i = 0,
       
  1127 				results = context.getElementsByTagName( tag );
       
  1128 
       
  1129 			// Filter out possible comments
       
  1130 			if ( tag === "*" ) {
       
  1131 				while ( (elem = results[i++]) ) {
       
  1132 					if ( elem.nodeType === 1 ) {
       
  1133 						tmp.push( elem );
       
  1134 					}
       
  1135 				}
       
  1136 
       
  1137 				return tmp;
       
  1138 			}
       
  1139 			return results;
       
  1140 		};
       
  1141 
       
  1142 	// Class
       
  1143 	Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
       
  1144 		if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) {
       
  1145 			return context.getElementsByClassName( className );
       
  1146 		}
       
  1147 	};
       
  1148 
       
  1149 	/* QSA/matchesSelector
       
  1150 	---------------------------------------------------------------------- */
       
  1151 
       
  1152 	// QSA and matchesSelector support
       
  1153 
       
  1154 	// matchesSelector(:active) reports false when true (IE9/Opera 11.5)
       
  1155 	rbuggyMatches = [];
       
  1156 
       
  1157 	// qSa(:focus) reports false when true (Chrome 21)
       
  1158 	// We allow this because of a bug in IE8/9 that throws an error
       
  1159 	// whenever `document.activeElement` is accessed on an iframe
       
  1160 	// So, we allow :focus to pass through QSA all the time to avoid the IE error
       
  1161 	// See http://bugs.jquery.com/ticket/13378
       
  1162 	rbuggyQSA = [];
       
  1163 
       
  1164 	if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) {
       
  1165 		// Build QSA regex
       
  1166 		// Regex strategy adopted from Diego Perini
       
  1167 		assert(function( div ) {
       
  1168 			// Select is set to empty string on purpose
       
  1169 			// This is to test IE's treatment of not explicitly
       
  1170 			// setting a boolean content attribute,
       
  1171 			// since its presence should be enough
       
  1172 			// http://bugs.jquery.com/ticket/12359
       
  1173 			div.innerHTML = "<select msallowclip=''><option selected=''></option></select>";
       
  1174 
       
  1175 			// Support: IE8, Opera 11-12.16
       
  1176 			// Nothing should be selected when empty strings follow ^= or $= or *=
       
  1177 			// The test attribute must be unknown in Opera but "safe" for WinRT
       
  1178 			// http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
       
  1179 			if ( div.querySelectorAll("[msallowclip^='']").length ) {
       
  1180 				rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
       
  1181 			}
       
  1182 
       
  1183 			// Support: IE8
       
  1184 			// Boolean attributes and "value" are not treated correctly
       
  1185 			if ( !div.querySelectorAll("[selected]").length ) {
       
  1186 				rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
       
  1187 			}
       
  1188 
       
  1189 			// Webkit/Opera - :checked should return selected option elements
       
  1190 			// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
       
  1191 			// IE8 throws error here and will not see later tests
       
  1192 			if ( !div.querySelectorAll(":checked").length ) {
       
  1193 				rbuggyQSA.push(":checked");
       
  1194 			}
       
  1195 		});
       
  1196 
       
  1197 		assert(function( div ) {
       
  1198 			// Support: Windows 8 Native Apps
       
  1199 			// The type and name attributes are restricted during .innerHTML assignment
       
  1200 			var input = doc.createElement("input");
       
  1201 			input.setAttribute( "type", "hidden" );
       
  1202 			div.appendChild( input ).setAttribute( "name", "D" );
       
  1203 
       
  1204 			// Support: IE8
       
  1205 			// Enforce case-sensitivity of name attribute
       
  1206 			if ( div.querySelectorAll("[name=d]").length ) {
       
  1207 				rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
       
  1208 			}
       
  1209 
       
  1210 			// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
       
  1211 			// IE8 throws error here and will not see later tests
       
  1212 			if ( !div.querySelectorAll(":enabled").length ) {
       
  1213 				rbuggyQSA.push( ":enabled", ":disabled" );
       
  1214 			}
       
  1215 
       
  1216 			// Opera 10-11 does not throw on post-comma invalid pseudos
       
  1217 			div.querySelectorAll("*,:x");
       
  1218 			rbuggyQSA.push(",.*:");
       
  1219 		});
       
  1220 	}
       
  1221 
       
  1222 	if ( (support.matchesSelector = rnative.test( (matches = docElem.matches ||
       
  1223 		docElem.webkitMatchesSelector ||
       
  1224 		docElem.mozMatchesSelector ||
       
  1225 		docElem.oMatchesSelector ||
       
  1226 		docElem.msMatchesSelector) )) ) {
       
  1227 
       
  1228 		assert(function( div ) {
       
  1229 			// Check to see if it's possible to do matchesSelector
       
  1230 			// on a disconnected node (IE 9)
       
  1231 			support.disconnectedMatch = matches.call( div, "div" );
       
  1232 
       
  1233 			// This should fail with an exception
       
  1234 			// Gecko does not error, returns false instead
       
  1235 			matches.call( div, "[s!='']:x" );
       
  1236 			rbuggyMatches.push( "!=", pseudos );
       
  1237 		});
       
  1238 	}
       
  1239 
       
  1240 	rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
       
  1241 	rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
       
  1242 
       
  1243 	/* Contains
       
  1244 	---------------------------------------------------------------------- */
       
  1245 	hasCompare = rnative.test( docElem.compareDocumentPosition );
       
  1246 
       
  1247 	// Element contains another
       
  1248 	// Purposefully does not implement inclusive descendent
       
  1249 	// As in, an element does not contain itself
       
  1250 	contains = hasCompare || rnative.test( docElem.contains ) ?
       
  1251 		function( a, b ) {
       
  1252 			var adown = a.nodeType === 9 ? a.documentElement : a,
       
  1253 				bup = b && b.parentNode;
       
  1254 			return a === bup || !!( bup && bup.nodeType === 1 && (
       
  1255 				adown.contains ?
       
  1256 					adown.contains( bup ) :
       
  1257 					a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
       
  1258 			));
       
  1259 		} :
       
  1260 		function( a, b ) {
       
  1261 			if ( b ) {
       
  1262 				while ( (b = b.parentNode) ) {
       
  1263 					if ( b === a ) {
       
  1264 						return true;
       
  1265 					}
       
  1266 				}
       
  1267 			}
       
  1268 			return false;
       
  1269 		};
       
  1270 
       
  1271 	/* Sorting
       
  1272 	---------------------------------------------------------------------- */
       
  1273 
       
  1274 	// Document order sorting
       
  1275 	sortOrder = hasCompare ?
       
  1276 	function( a, b ) {
       
  1277 
       
  1278 		// Flag for duplicate removal
       
  1279 		if ( a === b ) {
       
  1280 			hasDuplicate = true;
       
  1281 			return 0;
       
  1282 		}
       
  1283 
       
  1284 		// Sort on method existence if only one input has compareDocumentPosition
       
  1285 		var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
       
  1286 		if ( compare ) {
       
  1287 			return compare;
       
  1288 		}
       
  1289 
       
  1290 		// Calculate position if both inputs belong to the same document
       
  1291 		compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?
       
  1292 			a.compareDocumentPosition( b ) :
       
  1293 
       
  1294 			// Otherwise we know they are disconnected
       
  1295 			1;
       
  1296 
       
  1297 		// Disconnected nodes
       
  1298 		if ( compare & 1 ||
       
  1299 			(!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
       
  1300 
       
  1301 			// Choose the first element that is related to our preferred document
       
  1302 			if ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
       
  1303 				return -1;
       
  1304 			}
       
  1305 			if ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
       
  1306 				return 1;
       
  1307 			}
       
  1308 
       
  1309 			// Maintain original order
       
  1310 			return sortInput ?
       
  1311 				( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
       
  1312 				0;
       
  1313 		}
       
  1314 
       
  1315 		return compare & 4 ? -1 : 1;
       
  1316 	} :
       
  1317 	function( a, b ) {
       
  1318 		// Exit early if the nodes are identical
       
  1319 		if ( a === b ) {
       
  1320 			hasDuplicate = true;
       
  1321 			return 0;
       
  1322 		}
       
  1323 
       
  1324 		var cur,
       
  1325 			i = 0,
       
  1326 			aup = a.parentNode,
       
  1327 			bup = b.parentNode,
       
  1328 			ap = [ a ],
       
  1329 			bp = [ b ];
       
  1330 
       
  1331 		// Parentless nodes are either documents or disconnected
       
  1332 		if ( !aup || !bup ) {
       
  1333 			return a === doc ? -1 :
       
  1334 				b === doc ? 1 :
       
  1335 				aup ? -1 :
       
  1336 				bup ? 1 :
       
  1337 				sortInput ?
       
  1338 				( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
       
  1339 				0;
       
  1340 
       
  1341 		// If the nodes are siblings, we can do a quick check
       
  1342 		} else if ( aup === bup ) {
       
  1343 			return siblingCheck( a, b );
       
  1344 		}
       
  1345 
       
  1346 		// Otherwise we need full lists of their ancestors for comparison
       
  1347 		cur = a;
       
  1348 		while ( (cur = cur.parentNode) ) {
       
  1349 			ap.unshift( cur );
       
  1350 		}
       
  1351 		cur = b;
       
  1352 		while ( (cur = cur.parentNode) ) {
       
  1353 			bp.unshift( cur );
       
  1354 		}
       
  1355 
       
  1356 		// Walk down the tree looking for a discrepancy
       
  1357 		while ( ap[i] === bp[i] ) {
       
  1358 			i++;
       
  1359 		}
       
  1360 
       
  1361 		return i ?
       
  1362 			// Do a sibling check if the nodes have a common ancestor
       
  1363 			siblingCheck( ap[i], bp[i] ) :
       
  1364 
       
  1365 			// Otherwise nodes in our document sort first
       
  1366 			ap[i] === preferredDoc ? -1 :
       
  1367 			bp[i] === preferredDoc ? 1 :
       
  1368 			0;
       
  1369 	};
       
  1370 
       
  1371 	return doc;
       
  1372 };
       
  1373 
       
  1374 Sizzle.matches = function( expr, elements ) {
       
  1375 	return Sizzle( expr, null, null, elements );
       
  1376 };
       
  1377 
       
  1378 Sizzle.matchesSelector = function( elem, expr ) {
       
  1379 	// Set document vars if needed
       
  1380 	if ( ( elem.ownerDocument || elem ) !== document ) {
       
  1381 		setDocument( elem );
       
  1382 	}
       
  1383 
       
  1384 	// Make sure that attribute selectors are quoted
       
  1385 	expr = expr.replace( rattributeQuotes, "='$1']" );
       
  1386 
       
  1387 	if ( support.matchesSelector && documentIsHTML &&
       
  1388 		( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
       
  1389 		( !rbuggyQSA     || !rbuggyQSA.test( expr ) ) ) {
       
  1390 
       
  1391 		try {
       
  1392 			var ret = matches.call( elem, expr );
       
  1393 
       
  1394 			// IE 9's matchesSelector returns false on disconnected nodes
       
  1395 			if ( ret || support.disconnectedMatch ||
       
  1396 					// As well, disconnected nodes are said to be in a document
       
  1397 					// fragment in IE 9
       
  1398 					elem.document && elem.document.nodeType !== 11 ) {
       
  1399 				return ret;
       
  1400 			}
       
  1401 		} catch(e) {}
       
  1402 	}
       
  1403 
       
  1404 	return Sizzle( expr, document, null, [ elem ] ).length > 0;
       
  1405 };
       
  1406 
       
  1407 Sizzle.contains = function( context, elem ) {
       
  1408 	// Set document vars if needed
       
  1409 	if ( ( context.ownerDocument || context ) !== document ) {
       
  1410 		setDocument( context );
       
  1411 	}
       
  1412 	return contains( context, elem );
       
  1413 };
       
  1414 
       
  1415 Sizzle.attr = function( elem, name ) {
       
  1416 	// Set document vars if needed
       
  1417 	if ( ( elem.ownerDocument || elem ) !== document ) {
       
  1418 		setDocument( elem );
       
  1419 	}
       
  1420 
       
  1421 	var fn = Expr.attrHandle[ name.toLowerCase() ],
       
  1422 		// Don't get fooled by Object.prototype properties (jQuery #13807)
       
  1423 		val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
       
  1424 			fn( elem, name, !documentIsHTML ) :
       
  1425 			undefined;
       
  1426 
       
  1427 	return val !== undefined ?
       
  1428 		val :
       
  1429 		support.attributes || !documentIsHTML ?
       
  1430 			elem.getAttribute( name ) :
       
  1431 			(val = elem.getAttributeNode(name)) && val.specified ?
       
  1432 				val.value :
       
  1433 				null;
       
  1434 };
       
  1435 
       
  1436 Sizzle.error = function( msg ) {
       
  1437 	throw new Error( "Syntax error, unrecognized expression: " + msg );
       
  1438 };
       
  1439 
       
  1440 /**
       
  1441  * Document sorting and removing duplicates
       
  1442  * @param {ArrayLike} results
       
  1443  */
       
  1444 Sizzle.uniqueSort = function( results ) {
       
  1445 	var elem,
       
  1446 		duplicates = [],
       
  1447 		j = 0,
       
  1448 		i = 0;
       
  1449 
       
  1450 	// Unless we *know* we can detect duplicates, assume their presence
       
  1451 	hasDuplicate = !support.detectDuplicates;
       
  1452 	sortInput = !support.sortStable && results.slice( 0 );
       
  1453 	results.sort( sortOrder );
       
  1454 
       
  1455 	if ( hasDuplicate ) {
       
  1456 		while ( (elem = results[i++]) ) {
       
  1457 			if ( elem === results[ i ] ) {
       
  1458 				j = duplicates.push( i );
       
  1459 			}
       
  1460 		}
       
  1461 		while ( j-- ) {
       
  1462 			results.splice( duplicates[ j ], 1 );
       
  1463 		}
       
  1464 	}
       
  1465 
       
  1466 	// Clear input after sorting to release objects
       
  1467 	// See https://github.com/jquery/sizzle/pull/225
       
  1468 	sortInput = null;
       
  1469 
       
  1470 	return results;
       
  1471 };
       
  1472 
       
  1473 /**
       
  1474  * Utility function for retrieving the text value of an array of DOM nodes
       
  1475  * @param {Array|Element} elem
       
  1476  */
       
  1477 getText = Sizzle.getText = function( elem ) {
       
  1478 	var node,
       
  1479 		ret = "",
       
  1480 		i = 0,
       
  1481 		nodeType = elem.nodeType;
       
  1482 
       
  1483 	if ( !nodeType ) {
       
  1484 		// If no nodeType, this is expected to be an array
       
  1485 		while ( (node = elem[i++]) ) {
       
  1486 			// Do not traverse comment nodes
       
  1487 			ret += getText( node );
       
  1488 		}
       
  1489 	} else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
       
  1490 		// Use textContent for elements
       
  1491 		// innerText usage removed for consistency of new lines (jQuery #11153)
       
  1492 		if ( typeof elem.textContent === "string" ) {
       
  1493 			return elem.textContent;
       
  1494 		} else {
       
  1495 			// Traverse its children
       
  1496 			for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
       
  1497 				ret += getText( elem );
       
  1498 			}
       
  1499 		}
       
  1500 	} else if ( nodeType === 3 || nodeType === 4 ) {
       
  1501 		return elem.nodeValue;
       
  1502 	}
       
  1503 	// Do not include comment or processing instruction nodes
       
  1504 
       
  1505 	return ret;
       
  1506 };
       
  1507 
       
  1508 Expr = Sizzle.selectors = {
       
  1509 
       
  1510 	// Can be adjusted by the user
       
  1511 	cacheLength: 50,
       
  1512 
       
  1513 	createPseudo: markFunction,
       
  1514 
       
  1515 	match: matchExpr,
       
  1516 
       
  1517 	attrHandle: {},
       
  1518 
       
  1519 	find: {},
       
  1520 
       
  1521 	relative: {
       
  1522 		">": { dir: "parentNode", first: true },
       
  1523 		" ": { dir: "parentNode" },
       
  1524 		"+": { dir: "previousSibling", first: true },
       
  1525 		"~": { dir: "previousSibling" }
       
  1526 	},
       
  1527 
       
  1528 	preFilter: {
       
  1529 		"ATTR": function( match ) {
       
  1530 			match[1] = match[1].replace( runescape, funescape );
       
  1531 
       
  1532 			// Move the given value to match[3] whether quoted or unquoted
       
  1533 			match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape );
       
  1534 
       
  1535 			if ( match[2] === "~=" ) {
       
  1536 				match[3] = " " + match[3] + " ";
       
  1537 			}
       
  1538 
       
  1539 			return match.slice( 0, 4 );
       
  1540 		},
       
  1541 
       
  1542 		"CHILD": function( match ) {
       
  1543 			/* matches from matchExpr["CHILD"]
       
  1544 				1 type (only|nth|...)
       
  1545 				2 what (child|of-type)
       
  1546 				3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
       
  1547 				4 xn-component of xn+y argument ([+-]?\d*n|)
       
  1548 				5 sign of xn-component
       
  1549 				6 x of xn-component
       
  1550 				7 sign of y-component
       
  1551 				8 y of y-component
       
  1552 			*/
       
  1553 			match[1] = match[1].toLowerCase();
       
  1554 
       
  1555 			if ( match[1].slice( 0, 3 ) === "nth" ) {
       
  1556 				// nth-* requires argument
       
  1557 				if ( !match[3] ) {
       
  1558 					Sizzle.error( match[0] );
       
  1559 				}
       
  1560 
       
  1561 				// numeric x and y parameters for Expr.filter.CHILD
       
  1562 				// remember that false/true cast respectively to 0/1
       
  1563 				match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
       
  1564 				match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
       
  1565 
       
  1566 			// other types prohibit arguments
       
  1567 			} else if ( match[3] ) {
       
  1568 				Sizzle.error( match[0] );
       
  1569 			}
       
  1570 
       
  1571 			return match;
       
  1572 		},
       
  1573 
       
  1574 		"PSEUDO": function( match ) {
       
  1575 			var excess,
       
  1576 				unquoted = !match[6] && match[2];
       
  1577 
       
  1578 			if ( matchExpr["CHILD"].test( match[0] ) ) {
       
  1579 				return null;
       
  1580 			}
       
  1581 
       
  1582 			// Accept quoted arguments as-is
       
  1583 			if ( match[3] ) {
       
  1584 				match[2] = match[4] || match[5] || "";
       
  1585 
       
  1586 			// Strip excess characters from unquoted arguments
       
  1587 			} else if ( unquoted && rpseudo.test( unquoted ) &&
       
  1588 				// Get excess from tokenize (recursively)
       
  1589 				(excess = tokenize( unquoted, true )) &&
       
  1590 				// advance to the next closing parenthesis
       
  1591 				(excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
       
  1592 
       
  1593 				// excess is a negative index
       
  1594 				match[0] = match[0].slice( 0, excess );
       
  1595 				match[2] = unquoted.slice( 0, excess );
       
  1596 			}
       
  1597 
       
  1598 			// Return only captures needed by the pseudo filter method (type and argument)
       
  1599 			return match.slice( 0, 3 );
       
  1600 		}
       
  1601 	},
       
  1602 
       
  1603 	filter: {
       
  1604 
       
  1605 		"TAG": function( nodeNameSelector ) {
       
  1606 			var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
       
  1607 			return nodeNameSelector === "*" ?
       
  1608 				function() { return true; } :
       
  1609 				function( elem ) {
       
  1610 					return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
       
  1611 				};
       
  1612 		},
       
  1613 
       
  1614 		"CLASS": function( className ) {
       
  1615 			var pattern = classCache[ className + " " ];
       
  1616 
       
  1617 			return pattern ||
       
  1618 				(pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
       
  1619 				classCache( className, function( elem ) {
       
  1620 					return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" );
       
  1621 				});
       
  1622 		},
       
  1623 
       
  1624 		"ATTR": function( name, operator, check ) {
       
  1625 			return function( elem ) {
       
  1626 				var result = Sizzle.attr( elem, name );
       
  1627 
       
  1628 				if ( result == null ) {
       
  1629 					return operator === "!=";
       
  1630 				}
       
  1631 				if ( !operator ) {
       
  1632 					return true;
       
  1633 				}
       
  1634 
       
  1635 				result += "";
       
  1636 
       
  1637 				return operator === "=" ? result === check :
       
  1638 					operator === "!=" ? result !== check :
       
  1639 					operator === "^=" ? check && result.indexOf( check ) === 0 :
       
  1640 					operator === "*=" ? check && result.indexOf( check ) > -1 :
       
  1641 					operator === "$=" ? check && result.slice( -check.length ) === check :
       
  1642 					operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
       
  1643 					operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
       
  1644 					false;
       
  1645 			};
       
  1646 		},
       
  1647 
       
  1648 		"CHILD": function( type, what, argument, first, last ) {
       
  1649 			var simple = type.slice( 0, 3 ) !== "nth",
       
  1650 				forward = type.slice( -4 ) !== "last",
       
  1651 				ofType = what === "of-type";
       
  1652 
       
  1653 			return first === 1 && last === 0 ?
       
  1654 
       
  1655 				// Shortcut for :nth-*(n)
       
  1656 				function( elem ) {
       
  1657 					return !!elem.parentNode;
       
  1658 				} :
       
  1659 
       
  1660 				function( elem, context, xml ) {
       
  1661 					var cache, outerCache, node, diff, nodeIndex, start,
       
  1662 						dir = simple !== forward ? "nextSibling" : "previousSibling",
       
  1663 						parent = elem.parentNode,
       
  1664 						name = ofType && elem.nodeName.toLowerCase(),
       
  1665 						useCache = !xml && !ofType;
       
  1666 
       
  1667 					if ( parent ) {
       
  1668 
       
  1669 						// :(first|last|only)-(child|of-type)
       
  1670 						if ( simple ) {
       
  1671 							while ( dir ) {
       
  1672 								node = elem;
       
  1673 								while ( (node = node[ dir ]) ) {
       
  1674 									if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
       
  1675 										return false;
       
  1676 									}
       
  1677 								}
       
  1678 								// Reverse direction for :only-* (if we haven't yet done so)
       
  1679 								start = dir = type === "only" && !start && "nextSibling";
       
  1680 							}
       
  1681 							return true;
       
  1682 						}
       
  1683 
       
  1684 						start = [ forward ? parent.firstChild : parent.lastChild ];
       
  1685 
       
  1686 						// non-xml :nth-child(...) stores cache data on `parent`
       
  1687 						if ( forward && useCache ) {
       
  1688 							// Seek `elem` from a previously-cached index
       
  1689 							outerCache = parent[ expando ] || (parent[ expando ] = {});
       
  1690 							cache = outerCache[ type ] || [];
       
  1691 							nodeIndex = cache[0] === dirruns && cache[1];
       
  1692 							diff = cache[0] === dirruns && cache[2];
       
  1693 							node = nodeIndex && parent.childNodes[ nodeIndex ];
       
  1694 
       
  1695 							while ( (node = ++nodeIndex && node && node[ dir ] ||
       
  1696 
       
  1697 								// Fallback to seeking `elem` from the start
       
  1698 								(diff = nodeIndex = 0) || start.pop()) ) {
       
  1699 
       
  1700 								// When found, cache indexes on `parent` and break
       
  1701 								if ( node.nodeType === 1 && ++diff && node === elem ) {
       
  1702 									outerCache[ type ] = [ dirruns, nodeIndex, diff ];
       
  1703 									break;
       
  1704 								}
       
  1705 							}
       
  1706 
       
  1707 						// Use previously-cached element index if available
       
  1708 						} else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
       
  1709 							diff = cache[1];
       
  1710 
       
  1711 						// xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)
       
  1712 						} else {
       
  1713 							// Use the same loop as above to seek `elem` from the start
       
  1714 							while ( (node = ++nodeIndex && node && node[ dir ] ||
       
  1715 								(diff = nodeIndex = 0) || start.pop()) ) {
       
  1716 
       
  1717 								if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
       
  1718 									// Cache the index of each encountered element
       
  1719 									if ( useCache ) {
       
  1720 										(node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
       
  1721 									}
       
  1722 
       
  1723 									if ( node === elem ) {
       
  1724 										break;
       
  1725 									}
       
  1726 								}
       
  1727 							}
       
  1728 						}
       
  1729 
       
  1730 						// Incorporate the offset, then check against cycle size
       
  1731 						diff -= last;
       
  1732 						return diff === first || ( diff % first === 0 && diff / first >= 0 );
       
  1733 					}
       
  1734 				};
       
  1735 		},
       
  1736 
       
  1737 		"PSEUDO": function( pseudo, argument ) {
       
  1738 			// pseudo-class names are case-insensitive
       
  1739 			// http://www.w3.org/TR/selectors/#pseudo-classes
       
  1740 			// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
       
  1741 			// Remember that setFilters inherits from pseudos
       
  1742 			var args,
       
  1743 				fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
       
  1744 					Sizzle.error( "unsupported pseudo: " + pseudo );
       
  1745 
       
  1746 			// The user may use createPseudo to indicate that
       
  1747 			// arguments are needed to create the filter function
       
  1748 			// just as Sizzle does
       
  1749 			if ( fn[ expando ] ) {
       
  1750 				return fn( argument );
       
  1751 			}
       
  1752 
       
  1753 			// But maintain support for old signatures
       
  1754 			if ( fn.length > 1 ) {
       
  1755 				args = [ pseudo, pseudo, "", argument ];
       
  1756 				return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
       
  1757 					markFunction(function( seed, matches ) {
       
  1758 						var idx,
       
  1759 							matched = fn( seed, argument ),
       
  1760 							i = matched.length;
       
  1761 						while ( i-- ) {
       
  1762 							idx = indexOf.call( seed, matched[i] );
       
  1763 							seed[ idx ] = !( matches[ idx ] = matched[i] );
       
  1764 						}
       
  1765 					}) :
       
  1766 					function( elem ) {
       
  1767 						return fn( elem, 0, args );
       
  1768 					};
       
  1769 			}
       
  1770 
       
  1771 			return fn;
       
  1772 		}
       
  1773 	},
       
  1774 
       
  1775 	pseudos: {
       
  1776 		// Potentially complex pseudos
       
  1777 		"not": markFunction(function( selector ) {
       
  1778 			// Trim the selector passed to compile
       
  1779 			// to avoid treating leading and trailing
       
  1780 			// spaces as combinators
       
  1781 			var input = [],
       
  1782 				results = [],
       
  1783 				matcher = compile( selector.replace( rtrim, "$1" ) );
       
  1784 
       
  1785 			return matcher[ expando ] ?
       
  1786 				markFunction(function( seed, matches, context, xml ) {
       
  1787 					var elem,
       
  1788 						unmatched = matcher( seed, null, xml, [] ),
       
  1789 						i = seed.length;
       
  1790 
       
  1791 					// Match elements unmatched by `matcher`
       
  1792 					while ( i-- ) {
       
  1793 						if ( (elem = unmatched[i]) ) {
       
  1794 							seed[i] = !(matches[i] = elem);
       
  1795 						}
       
  1796 					}
       
  1797 				}) :
       
  1798 				function( elem, context, xml ) {
       
  1799 					input[0] = elem;
       
  1800 					matcher( input, null, xml, results );
       
  1801 					return !results.pop();
       
  1802 				};
       
  1803 		}),
       
  1804 
       
  1805 		"has": markFunction(function( selector ) {
       
  1806 			return function( elem ) {
       
  1807 				return Sizzle( selector, elem ).length > 0;
       
  1808 			};
       
  1809 		}),
       
  1810 
       
  1811 		"contains": markFunction(function( text ) {
       
  1812 			return function( elem ) {
       
  1813 				return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
       
  1814 			};
       
  1815 		}),
       
  1816 
       
  1817 		// "Whether an element is represented by a :lang() selector
       
  1818 		// is based solely on the element's language value
       
  1819 		// being equal to the identifier C,
       
  1820 		// or beginning with the identifier C immediately followed by "-".
       
  1821 		// The matching of C against the element's language value is performed case-insensitively.
       
  1822 		// The identifier C does not have to be a valid language name."
       
  1823 		// http://www.w3.org/TR/selectors/#lang-pseudo
       
  1824 		"lang": markFunction( function( lang ) {
       
  1825 			// lang value must be a valid identifier
       
  1826 			if ( !ridentifier.test(lang || "") ) {
       
  1827 				Sizzle.error( "unsupported lang: " + lang );
       
  1828 			}
       
  1829 			lang = lang.replace( runescape, funescape ).toLowerCase();
       
  1830 			return function( elem ) {
       
  1831 				var elemLang;
       
  1832 				do {
       
  1833 					if ( (elemLang = documentIsHTML ?
       
  1834 						elem.lang :
       
  1835 						elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
       
  1836 
       
  1837 						elemLang = elemLang.toLowerCase();
       
  1838 						return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
       
  1839 					}
       
  1840 				} while ( (elem = elem.parentNode) && elem.nodeType === 1 );
       
  1841 				return false;
       
  1842 			};
       
  1843 		}),
       
  1844 
       
  1845 		// Miscellaneous
       
  1846 		"target": function( elem ) {
       
  1847 			var hash = window.location && window.location.hash;
       
  1848 			return hash && hash.slice( 1 ) === elem.id;
       
  1849 		},
       
  1850 
       
  1851 		"root": function( elem ) {
       
  1852 			return elem === docElem;
       
  1853 		},
       
  1854 
       
  1855 		"focus": function( elem ) {
       
  1856 			return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
       
  1857 		},
       
  1858 
       
  1859 		// Boolean properties
       
  1860 		"enabled": function( elem ) {
       
  1861 			return elem.disabled === false;
       
  1862 		},
       
  1863 
       
  1864 		"disabled": function( elem ) {
       
  1865 			return elem.disabled === true;
       
  1866 		},
       
  1867 
       
  1868 		"checked": function( elem ) {
       
  1869 			// In CSS3, :checked should return both checked and selected elements
       
  1870 			// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
       
  1871 			var nodeName = elem.nodeName.toLowerCase();
       
  1872 			return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
       
  1873 		},
       
  1874 
       
  1875 		"selected": function( elem ) {
       
  1876 			// Accessing this property makes selected-by-default
       
  1877 			// options in Safari work properly
       
  1878 			if ( elem.parentNode ) {
       
  1879 				elem.parentNode.selectedIndex;
       
  1880 			}
       
  1881 
       
  1882 			return elem.selected === true;
       
  1883 		},
       
  1884 
       
  1885 		// Contents
       
  1886 		"empty": function( elem ) {
       
  1887 			// http://www.w3.org/TR/selectors/#empty-pseudo
       
  1888 			// :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
       
  1889 			//   but not by others (comment: 8; processing instruction: 7; etc.)
       
  1890 			// nodeType < 6 works because attributes (2) do not appear as children
       
  1891 			for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
       
  1892 				if ( elem.nodeType < 6 ) {
       
  1893 					return false;
       
  1894 				}
       
  1895 			}
       
  1896 			return true;
       
  1897 		},
       
  1898 
       
  1899 		"parent": function( elem ) {
       
  1900 			return !Expr.pseudos["empty"]( elem );
       
  1901 		},
       
  1902 
       
  1903 		// Element/input types
       
  1904 		"header": function( elem ) {
       
  1905 			return rheader.test( elem.nodeName );
       
  1906 		},
       
  1907 
       
  1908 		"input": function( elem ) {
       
  1909 			return rinputs.test( elem.nodeName );
       
  1910 		},
       
  1911 
       
  1912 		"button": function( elem ) {
       
  1913 			var name = elem.nodeName.toLowerCase();
       
  1914 			return name === "input" && elem.type === "button" || name === "button";
       
  1915 		},
       
  1916 
       
  1917 		"text": function( elem ) {
       
  1918 			var attr;
       
  1919 			return elem.nodeName.toLowerCase() === "input" &&
       
  1920 				elem.type === "text" &&
       
  1921 
       
  1922 				// Support: IE<8
       
  1923 				// New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
       
  1924 				( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" );
       
  1925 		},
       
  1926 
       
  1927 		// Position-in-collection
       
  1928 		"first": createPositionalPseudo(function() {
       
  1929 			return [ 0 ];
       
  1930 		}),
       
  1931 
       
  1932 		"last": createPositionalPseudo(function( matchIndexes, length ) {
       
  1933 			return [ length - 1 ];
       
  1934 		}),
       
  1935 
       
  1936 		"eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
       
  1937 			return [ argument < 0 ? argument + length : argument ];
       
  1938 		}),
       
  1939 
       
  1940 		"even": createPositionalPseudo(function( matchIndexes, length ) {
       
  1941 			var i = 0;
       
  1942 			for ( ; i < length; i += 2 ) {
       
  1943 				matchIndexes.push( i );
       
  1944 			}
       
  1945 			return matchIndexes;
       
  1946 		}),
       
  1947 
       
  1948 		"odd": createPositionalPseudo(function( matchIndexes, length ) {
       
  1949 			var i = 1;
       
  1950 			for ( ; i < length; i += 2 ) {
       
  1951 				matchIndexes.push( i );
       
  1952 			}
       
  1953 			return matchIndexes;
       
  1954 		}),
       
  1955 
       
  1956 		"lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
       
  1957 			var i = argument < 0 ? argument + length : argument;
       
  1958 			for ( ; --i >= 0; ) {
       
  1959 				matchIndexes.push( i );
       
  1960 			}
       
  1961 			return matchIndexes;
       
  1962 		}),
       
  1963 
       
  1964 		"gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
       
  1965 			var i = argument < 0 ? argument + length : argument;
       
  1966 			for ( ; ++i < length; ) {
       
  1967 				matchIndexes.push( i );
       
  1968 			}
       
  1969 			return matchIndexes;
       
  1970 		})
       
  1971 	}
       
  1972 };
       
  1973 
       
  1974 Expr.pseudos["nth"] = Expr.pseudos["eq"];
       
  1975 
       
  1976 // Add button/input type pseudos
       
  1977 for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
       
  1978 	Expr.pseudos[ i ] = createInputPseudo( i );
       
  1979 }
       
  1980 for ( i in { submit: true, reset: true } ) {
       
  1981 	Expr.pseudos[ i ] = createButtonPseudo( i );
       
  1982 }
       
  1983 
       
  1984 // Easy API for creating new setFilters
       
  1985 function setFilters() {}
       
  1986 setFilters.prototype = Expr.filters = Expr.pseudos;
       
  1987 Expr.setFilters = new setFilters();
       
  1988 
       
  1989 tokenize = Sizzle.tokenize = function( selector, parseOnly ) {
       
  1990 	var matched, match, tokens, type,
       
  1991 		soFar, groups, preFilters,
       
  1992 		cached = tokenCache[ selector + " " ];
       
  1993 
       
  1994 	if ( cached ) {
       
  1995 		return parseOnly ? 0 : cached.slice( 0 );
       
  1996 	}
       
  1997 
       
  1998 	soFar = selector;
       
  1999 	groups = [];
       
  2000 	preFilters = Expr.preFilter;
       
  2001 
       
  2002 	while ( soFar ) {
       
  2003 
       
  2004 		// Comma and first run
       
  2005 		if ( !matched || (match = rcomma.exec( soFar )) ) {
       
  2006 			if ( match ) {
       
  2007 				// Don't consume trailing commas as valid
       
  2008 				soFar = soFar.slice( match[0].length ) || soFar;
       
  2009 			}
       
  2010 			groups.push( (tokens = []) );
       
  2011 		}
       
  2012 
       
  2013 		matched = false;
       
  2014 
       
  2015 		// Combinators
       
  2016 		if ( (match = rcombinators.exec( soFar )) ) {
       
  2017 			matched = match.shift();
       
  2018 			tokens.push({
       
  2019 				value: matched,
       
  2020 				// Cast descendant combinators to space
       
  2021 				type: match[0].replace( rtrim, " " )
       
  2022 			});
       
  2023 			soFar = soFar.slice( matched.length );
       
  2024 		}
       
  2025 
       
  2026 		// Filters
       
  2027 		for ( type in Expr.filter ) {
       
  2028 			if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
       
  2029 				(match = preFilters[ type ]( match ))) ) {
       
  2030 				matched = match.shift();
       
  2031 				tokens.push({
       
  2032 					value: matched,
       
  2033 					type: type,
       
  2034 					matches: match
       
  2035 				});
       
  2036 				soFar = soFar.slice( matched.length );
       
  2037 			}
       
  2038 		}
       
  2039 
       
  2040 		if ( !matched ) {
       
  2041 			break;
       
  2042 		}
       
  2043 	}
       
  2044 
       
  2045 	// Return the length of the invalid excess
       
  2046 	// if we're just parsing
       
  2047 	// Otherwise, throw an error or return tokens
       
  2048 	return parseOnly ?
       
  2049 		soFar.length :
       
  2050 		soFar ?
       
  2051 			Sizzle.error( selector ) :
       
  2052 			// Cache the tokens
       
  2053 			tokenCache( selector, groups ).slice( 0 );
       
  2054 };
       
  2055 
       
  2056 function toSelector( tokens ) {
       
  2057 	var i = 0,
       
  2058 		len = tokens.length,
       
  2059 		selector = "";
       
  2060 	for ( ; i < len; i++ ) {
       
  2061 		selector += tokens[i].value;
       
  2062 	}
       
  2063 	return selector;
       
  2064 }
       
  2065 
       
  2066 function addCombinator( matcher, combinator, base ) {
       
  2067 	var dir = combinator.dir,
       
  2068 		checkNonElements = base && dir === "parentNode",
       
  2069 		doneName = done++;
       
  2070 
       
  2071 	return combinator.first ?
       
  2072 		// Check against closest ancestor/preceding element
       
  2073 		function( elem, context, xml ) {
       
  2074 			while ( (elem = elem[ dir ]) ) {
       
  2075 				if ( elem.nodeType === 1 || checkNonElements ) {
       
  2076 					return matcher( elem, context, xml );
       
  2077 				}
       
  2078 			}
       
  2079 		} :
       
  2080 
       
  2081 		// Check against all ancestor/preceding elements
       
  2082 		function( elem, context, xml ) {
       
  2083 			var oldCache, outerCache,
       
  2084 				newCache = [ dirruns, doneName ];
       
  2085 
       
  2086 			// We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
       
  2087 			if ( xml ) {
       
  2088 				while ( (elem = elem[ dir ]) ) {
       
  2089 					if ( elem.nodeType === 1 || checkNonElements ) {
       
  2090 						if ( matcher( elem, context, xml ) ) {
       
  2091 							return true;
       
  2092 						}
       
  2093 					}
       
  2094 				}
       
  2095 			} else {
       
  2096 				while ( (elem = elem[ dir ]) ) {
       
  2097 					if ( elem.nodeType === 1 || checkNonElements ) {
       
  2098 						outerCache = elem[ expando ] || (elem[ expando ] = {});
       
  2099 						if ( (oldCache = outerCache[ dir ]) &&
       
  2100 							oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
       
  2101 
       
  2102 							// Assign to newCache so results back-propagate to previous elements
       
  2103 							return (newCache[ 2 ] = oldCache[ 2 ]);
       
  2104 						} else {
       
  2105 							// Reuse newcache so results back-propagate to previous elements
       
  2106 							outerCache[ dir ] = newCache;
       
  2107 
       
  2108 							// A match means we're done; a fail means we have to keep checking
       
  2109 							if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {
       
  2110 								return true;
       
  2111 							}
       
  2112 						}
       
  2113 					}
       
  2114 				}
       
  2115 			}
       
  2116 		};
       
  2117 }
       
  2118 
       
  2119 function elementMatcher( matchers ) {
       
  2120 	return matchers.length > 1 ?
       
  2121 		function( elem, context, xml ) {
       
  2122 			var i = matchers.length;
       
  2123 			while ( i-- ) {
       
  2124 				if ( !matchers[i]( elem, context, xml ) ) {
       
  2125 					return false;
       
  2126 				}
       
  2127 			}
       
  2128 			return true;
       
  2129 		} :
       
  2130 		matchers[0];
       
  2131 }
       
  2132 
       
  2133 function multipleContexts( selector, contexts, results ) {
       
  2134 	var i = 0,
       
  2135 		len = contexts.length;
       
  2136 	for ( ; i < len; i++ ) {
       
  2137 		Sizzle( selector, contexts[i], results );
       
  2138 	}
       
  2139 	return results;
       
  2140 }
       
  2141 
       
  2142 function condense( unmatched, map, filter, context, xml ) {
       
  2143 	var elem,
       
  2144 		newUnmatched = [],
       
  2145 		i = 0,
       
  2146 		len = unmatched.length,
       
  2147 		mapped = map != null;
       
  2148 
       
  2149 	for ( ; i < len; i++ ) {
       
  2150 		if ( (elem = unmatched[i]) ) {
       
  2151 			if ( !filter || filter( elem, context, xml ) ) {
       
  2152 				newUnmatched.push( elem );
       
  2153 				if ( mapped ) {
       
  2154 					map.push( i );
       
  2155 				}
       
  2156 			}
       
  2157 		}
       
  2158 	}
       
  2159 
       
  2160 	return newUnmatched;
       
  2161 }
       
  2162 
       
  2163 function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
       
  2164 	if ( postFilter && !postFilter[ expando ] ) {
       
  2165 		postFilter = setMatcher( postFilter );
       
  2166 	}
       
  2167 	if ( postFinder && !postFinder[ expando ] ) {
       
  2168 		postFinder = setMatcher( postFinder, postSelector );
       
  2169 	}
       
  2170 	return markFunction(function( seed, results, context, xml ) {
       
  2171 		var temp, i, elem,
       
  2172 			preMap = [],
       
  2173 			postMap = [],
       
  2174 			preexisting = results.length,
       
  2175 
       
  2176 			// Get initial elements from seed or context
       
  2177 			elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
       
  2178 
       
  2179 			// Prefilter to get matcher input, preserving a map for seed-results synchronization
       
  2180 			matcherIn = preFilter && ( seed || !selector ) ?
       
  2181 				condense( elems, preMap, preFilter, context, xml ) :
       
  2182 				elems,
       
  2183 
       
  2184 			matcherOut = matcher ?
       
  2185 				// If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
       
  2186 				postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
       
  2187 
       
  2188 					// ...intermediate processing is necessary
       
  2189 					[] :
       
  2190 
       
  2191 					// ...otherwise use results directly
       
  2192 					results :
       
  2193 				matcherIn;
       
  2194 
       
  2195 		// Find primary matches
       
  2196 		if ( matcher ) {
       
  2197 			matcher( matcherIn, matcherOut, context, xml );
       
  2198 		}
       
  2199 
       
  2200 		// Apply postFilter
       
  2201 		if ( postFilter ) {
       
  2202 			temp = condense( matcherOut, postMap );
       
  2203 			postFilter( temp, [], context, xml );
       
  2204 
       
  2205 			// Un-match failing elements by moving them back to matcherIn
       
  2206 			i = temp.length;
       
  2207 			while ( i-- ) {
       
  2208 				if ( (elem = temp[i]) ) {
       
  2209 					matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
       
  2210 				}
       
  2211 			}
       
  2212 		}
       
  2213 
       
  2214 		if ( seed ) {
       
  2215 			if ( postFinder || preFilter ) {
       
  2216 				if ( postFinder ) {
       
  2217 					// Get the final matcherOut by condensing this intermediate into postFinder contexts
       
  2218 					temp = [];
       
  2219 					i = matcherOut.length;
       
  2220 					while ( i-- ) {
       
  2221 						if ( (elem = matcherOut[i]) ) {
       
  2222 							// Restore matcherIn since elem is not yet a final match
       
  2223 							temp.push( (matcherIn[i] = elem) );
       
  2224 						}
       
  2225 					}
       
  2226 					postFinder( null, (matcherOut = []), temp, xml );
       
  2227 				}
       
  2228 
       
  2229 				// Move matched elements from seed to results to keep them synchronized
       
  2230 				i = matcherOut.length;
       
  2231 				while ( i-- ) {
       
  2232 					if ( (elem = matcherOut[i]) &&
       
  2233 						(temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
       
  2234 
       
  2235 						seed[temp] = !(results[temp] = elem);
       
  2236 					}
       
  2237 				}
       
  2238 			}
       
  2239 
       
  2240 		// Add elements to results, through postFinder if defined
       
  2241 		} else {
       
  2242 			matcherOut = condense(
       
  2243 				matcherOut === results ?
       
  2244 					matcherOut.splice( preexisting, matcherOut.length ) :
       
  2245 					matcherOut
       
  2246 			);
       
  2247 			if ( postFinder ) {
       
  2248 				postFinder( null, results, matcherOut, xml );
       
  2249 			} else {
       
  2250 				push.apply( results, matcherOut );
       
  2251 			}
       
  2252 		}
       
  2253 	});
       
  2254 }
       
  2255 
       
  2256 function matcherFromTokens( tokens ) {
       
  2257 	var checkContext, matcher, j,
       
  2258 		len = tokens.length,
       
  2259 		leadingRelative = Expr.relative[ tokens[0].type ],
       
  2260 		implicitRelative = leadingRelative || Expr.relative[" "],
       
  2261 		i = leadingRelative ? 1 : 0,
       
  2262 
       
  2263 		// The foundational matcher ensures that elements are reachable from top-level context(s)
       
  2264 		matchContext = addCombinator( function( elem ) {
       
  2265 			return elem === checkContext;
       
  2266 		}, implicitRelative, true ),
       
  2267 		matchAnyContext = addCombinator( function( elem ) {
       
  2268 			return indexOf.call( checkContext, elem ) > -1;
       
  2269 		}, implicitRelative, true ),
       
  2270 		matchers = [ function( elem, context, xml ) {
       
  2271 			return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
       
  2272 				(checkContext = context).nodeType ?
       
  2273 					matchContext( elem, context, xml ) :
       
  2274 					matchAnyContext( elem, context, xml ) );
       
  2275 		} ];
       
  2276 
       
  2277 	for ( ; i < len; i++ ) {
       
  2278 		if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
       
  2279 			matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
       
  2280 		} else {
       
  2281 			matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
       
  2282 
       
  2283 			// Return special upon seeing a positional matcher
       
  2284 			if ( matcher[ expando ] ) {
       
  2285 				// Find the next relative operator (if any) for proper handling
       
  2286 				j = ++i;
       
  2287 				for ( ; j < len; j++ ) {
       
  2288 					if ( Expr.relative[ tokens[j].type ] ) {
       
  2289 						break;
       
  2290 					}
       
  2291 				}
       
  2292 				return setMatcher(
       
  2293 					i > 1 && elementMatcher( matchers ),
       
  2294 					i > 1 && toSelector(
       
  2295 						// If the preceding token was a descendant combinator, insert an implicit any-element `*`
       
  2296 						tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
       
  2297 					).replace( rtrim, "$1" ),
       
  2298 					matcher,
       
  2299 					i < j && matcherFromTokens( tokens.slice( i, j ) ),
       
  2300 					j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
       
  2301 					j < len && toSelector( tokens )
       
  2302 				);
       
  2303 			}
       
  2304 			matchers.push( matcher );
       
  2305 		}
       
  2306 	}
       
  2307 
       
  2308 	return elementMatcher( matchers );
       
  2309 }
       
  2310 
       
  2311 function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
       
  2312 	var bySet = setMatchers.length > 0,
       
  2313 		byElement = elementMatchers.length > 0,
       
  2314 		superMatcher = function( seed, context, xml, results, outermost ) {
       
  2315 			var elem, j, matcher,
       
  2316 				matchedCount = 0,
       
  2317 				i = "0",
       
  2318 				unmatched = seed && [],
       
  2319 				setMatched = [],
       
  2320 				contextBackup = outermostContext,
       
  2321 				// We must always have either seed elements or outermost context
       
  2322 				elems = seed || byElement && Expr.find["TAG"]( "*", outermost ),
       
  2323 				// Use integer dirruns iff this is the outermost matcher
       
  2324 				dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
       
  2325 				len = elems.length;
       
  2326 
       
  2327 			if ( outermost ) {
       
  2328 				outermostContext = context !== document && context;
       
  2329 			}
       
  2330 
       
  2331 			// Add elements passing elementMatchers directly to results
       
  2332 			// Keep `i` a string if there are no elements so `matchedCount` will be "00" below
       
  2333 			// Support: IE<9, Safari
       
  2334 			// Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id
       
  2335 			for ( ; i !== len && (elem = elems[i]) != null; i++ ) {
       
  2336 				if ( byElement && elem ) {
       
  2337 					j = 0;
       
  2338 					while ( (matcher = elementMatchers[j++]) ) {
       
  2339 						if ( matcher( elem, context, xml ) ) {
       
  2340 							results.push( elem );
       
  2341 							break;
       
  2342 						}
       
  2343 					}
       
  2344 					if ( outermost ) {
       
  2345 						dirruns = dirrunsUnique;
       
  2346 					}
       
  2347 				}
       
  2348 
       
  2349 				// Track unmatched elements for set filters
       
  2350 				if ( bySet ) {
       
  2351 					// They will have gone through all possible matchers
       
  2352 					if ( (elem = !matcher && elem) ) {
       
  2353 						matchedCount--;
       
  2354 					}
       
  2355 
       
  2356 					// Lengthen the array for every element, matched or not
       
  2357 					if ( seed ) {
       
  2358 						unmatched.push( elem );
       
  2359 					}
       
  2360 				}
       
  2361 			}
       
  2362 
       
  2363 			// Apply set filters to unmatched elements
       
  2364 			matchedCount += i;
       
  2365 			if ( bySet && i !== matchedCount ) {
       
  2366 				j = 0;
       
  2367 				while ( (matcher = setMatchers[j++]) ) {
       
  2368 					matcher( unmatched, setMatched, context, xml );
       
  2369 				}
       
  2370 
       
  2371 				if ( seed ) {
       
  2372 					// Reintegrate element matches to eliminate the need for sorting
       
  2373 					if ( matchedCount > 0 ) {
       
  2374 						while ( i-- ) {
       
  2375 							if ( !(unmatched[i] || setMatched[i]) ) {
       
  2376 								setMatched[i] = pop.call( results );
       
  2377 							}
       
  2378 						}
       
  2379 					}
       
  2380 
       
  2381 					// Discard index placeholder values to get only actual matches
       
  2382 					setMatched = condense( setMatched );
       
  2383 				}
       
  2384 
       
  2385 				// Add matches to results
       
  2386 				push.apply( results, setMatched );
       
  2387 
       
  2388 				// Seedless set matches succeeding multiple successful matchers stipulate sorting
       
  2389 				if ( outermost && !seed && setMatched.length > 0 &&
       
  2390 					( matchedCount + setMatchers.length ) > 1 ) {
       
  2391 
       
  2392 					Sizzle.uniqueSort( results );
       
  2393 				}
       
  2394 			}
       
  2395 
       
  2396 			// Override manipulation of globals by nested matchers
       
  2397 			if ( outermost ) {
       
  2398 				dirruns = dirrunsUnique;
       
  2399 				outermostContext = contextBackup;
       
  2400 			}
       
  2401 
       
  2402 			return unmatched;
       
  2403 		};
       
  2404 
       
  2405 	return bySet ?
       
  2406 		markFunction( superMatcher ) :
       
  2407 		superMatcher;
       
  2408 }
       
  2409 
       
  2410 compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {
       
  2411 	var i,
       
  2412 		setMatchers = [],
       
  2413 		elementMatchers = [],
       
  2414 		cached = compilerCache[ selector + " " ];
       
  2415 
       
  2416 	if ( !cached ) {
       
  2417 		// Generate a function of recursive functions that can be used to check each element
       
  2418 		if ( !match ) {
       
  2419 			match = tokenize( selector );
       
  2420 		}
       
  2421 		i = match.length;
       
  2422 		while ( i-- ) {
       
  2423 			cached = matcherFromTokens( match[i] );
       
  2424 			if ( cached[ expando ] ) {
       
  2425 				setMatchers.push( cached );
       
  2426 			} else {
       
  2427 				elementMatchers.push( cached );
       
  2428 			}
       
  2429 		}
       
  2430 
       
  2431 		// Cache the compiled function
       
  2432 		cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
       
  2433 
       
  2434 		// Save selector and tokenization
       
  2435 		cached.selector = selector;
       
  2436 	}
       
  2437 	return cached;
       
  2438 };
       
  2439 
       
  2440 /**
       
  2441  * A low-level selection function that works with Sizzle's compiled
       
  2442  *  selector functions
       
  2443  * @param {String|Function} selector A selector or a pre-compiled
       
  2444  *  selector function built with Sizzle.compile
       
  2445  * @param {Element} context
       
  2446  * @param {Array} [results]
       
  2447  * @param {Array} [seed] A set of elements to match against
       
  2448  */
       
  2449 select = Sizzle.select = function( selector, context, results, seed ) {
       
  2450 	var i, tokens, token, type, find,
       
  2451 		compiled = typeof selector === "function" && selector,
       
  2452 		match = !seed && tokenize( (selector = compiled.selector || selector) );
       
  2453 
       
  2454 	results = results || [];
       
  2455 
       
  2456 	// Try to minimize operations if there is no seed and only one group
       
  2457 	if ( match.length === 1 ) {
       
  2458 
       
  2459 		// Take a shortcut and set the context if the root selector is an ID
       
  2460 		tokens = match[0] = match[0].slice( 0 );
       
  2461 		if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
       
  2462 				support.getById && context.nodeType === 9 && documentIsHTML &&
       
  2463 				Expr.relative[ tokens[1].type ] ) {
       
  2464 
       
  2465 			context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
       
  2466 			if ( !context ) {
       
  2467 				return results;
       
  2468 
       
  2469 			// Precompiled matchers will still verify ancestry, so step up a level
       
  2470 			} else if ( compiled ) {
       
  2471 				context = context.parentNode;
       
  2472 			}
       
  2473 
       
  2474 			selector = selector.slice( tokens.shift().value.length );
       
  2475 		}
       
  2476 
       
  2477 		// Fetch a seed set for right-to-left matching
       
  2478 		i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
       
  2479 		while ( i-- ) {
       
  2480 			token = tokens[i];
       
  2481 
       
  2482 			// Abort if we hit a combinator
       
  2483 			if ( Expr.relative[ (type = token.type) ] ) {
       
  2484 				break;
       
  2485 			}
       
  2486 			if ( (find = Expr.find[ type ]) ) {
       
  2487 				// Search, expanding context for leading sibling combinators
       
  2488 				if ( (seed = find(
       
  2489 					token.matches[0].replace( runescape, funescape ),
       
  2490 					rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context
       
  2491 				)) ) {
       
  2492 
       
  2493 					// If seed is empty or no tokens remain, we can return early
       
  2494 					tokens.splice( i, 1 );
       
  2495 					selector = seed.length && toSelector( tokens );
       
  2496 					if ( !selector ) {
       
  2497 						push.apply( results, seed );
       
  2498 						return results;
       
  2499 					}
       
  2500 
       
  2501 					break;
       
  2502 				}
       
  2503 			}
       
  2504 		}
       
  2505 	}
       
  2506 
       
  2507 	// Compile and execute a filtering function if one is not provided
       
  2508 	// Provide `match` to avoid retokenization if we modified the selector above
       
  2509 	( compiled || compile( selector, match ) )(
       
  2510 		seed,
       
  2511 		context,
       
  2512 		!documentIsHTML,
       
  2513 		results,
       
  2514 		rsibling.test( selector ) && testContext( context.parentNode ) || context
       
  2515 	);
       
  2516 	return results;
       
  2517 };
       
  2518 
       
  2519 // One-time assignments
       
  2520 
       
  2521 // Sort stability
       
  2522 support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
       
  2523 
       
  2524 // Support: Chrome<14
       
  2525 // Always assume duplicates if they aren't passed to the comparison function
       
  2526 support.detectDuplicates = !!hasDuplicate;
       
  2527 
       
  2528 // Initialize against the default document
       
  2529 setDocument();
       
  2530 
       
  2531 // Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
       
  2532 // Detached nodes confoundingly follow *each other*
       
  2533 support.sortDetached = assert(function( div1 ) {
       
  2534 	// Should return 1, but returns 4 (following)
       
  2535 	return div1.compareDocumentPosition( document.createElement("div") ) & 1;
       
  2536 });
       
  2537 
       
  2538 // Support: IE<8
       
  2539 // Prevent attribute/property "interpolation"
       
  2540 // http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
       
  2541 if ( !assert(function( div ) {
       
  2542 	div.innerHTML = "<a href='#'></a>";
       
  2543 	return div.firstChild.getAttribute("href") === "#" ;
       
  2544 }) ) {
       
  2545 	addHandle( "type|href|height|width", function( elem, name, isXML ) {
       
  2546 		if ( !isXML ) {
       
  2547 			return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
       
  2548 		}
       
  2549 	});
       
  2550 }
       
  2551 
       
  2552 // Support: IE<9
       
  2553 // Use defaultValue in place of getAttribute("value")
       
  2554 if ( !support.attributes || !assert(function( div ) {
       
  2555 	div.innerHTML = "<input/>";
       
  2556 	div.firstChild.setAttribute( "value", "" );
       
  2557 	return div.firstChild.getAttribute( "value" ) === "";
       
  2558 }) ) {
       
  2559 	addHandle( "value", function( elem, name, isXML ) {
       
  2560 		if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
       
  2561 			return elem.defaultValue;
       
  2562 		}
       
  2563 	});
       
  2564 }
       
  2565 
       
  2566 // Support: IE<9
       
  2567 // Use getAttributeNode to fetch booleans when getAttribute lies
       
  2568 if ( !assert(function( div ) {
       
  2569 	return div.getAttribute("disabled") == null;
       
  2570 }) ) {
       
  2571 	addHandle( booleans, function( elem, name, isXML ) {
       
  2572 		var val;
       
  2573 		if ( !isXML ) {
       
  2574 			return elem[ name ] === true ? name.toLowerCase() :
       
  2575 					(val = elem.getAttributeNode( name )) && val.specified ?
       
  2576 					val.value :
       
  2577 				null;
       
  2578 		}
       
  2579 	});
       
  2580 }
       
  2581 
       
  2582 return Sizzle;
       
  2583 
       
  2584 })( window );
       
  2585 
       
  2586 
       
  2587 
       
  2588 jQuery.find = Sizzle;
       
  2589 jQuery.expr = Sizzle.selectors;
       
  2590 jQuery.expr[":"] = jQuery.expr.pseudos;
       
  2591 jQuery.unique = Sizzle.uniqueSort;
       
  2592 jQuery.text = Sizzle.getText;
       
  2593 jQuery.isXMLDoc = Sizzle.isXML;
       
  2594 jQuery.contains = Sizzle.contains;
       
  2595 
       
  2596 
       
  2597 
       
  2598 var rneedsContext = jQuery.expr.match.needsContext;
       
  2599 
       
  2600 var rsingleTag = (/^<(\w+)\s*\/?>(?:<\/\1>|)$/);
       
  2601 
       
  2602 
       
  2603 
       
  2604 var risSimple = /^.[^:#\[\.,]*$/;
       
  2605 
       
  2606 // Implement the identical functionality for filter and not
       
  2607 function winnow( elements, qualifier, not ) {
       
  2608 	if ( jQuery.isFunction( qualifier ) ) {
       
  2609 		return jQuery.grep( elements, function( elem, i ) {
       
  2610 			/* jshint -W018 */
       
  2611 			return !!qualifier.call( elem, i, elem ) !== not;
       
  2612 		});
       
  2613 
       
  2614 	}
       
  2615 
       
  2616 	if ( qualifier.nodeType ) {
       
  2617 		return jQuery.grep( elements, function( elem ) {
       
  2618 			return ( elem === qualifier ) !== not;
       
  2619 		});
       
  2620 
       
  2621 	}
       
  2622 
       
  2623 	if ( typeof qualifier === "string" ) {
       
  2624 		if ( risSimple.test( qualifier ) ) {
       
  2625 			return jQuery.filter( qualifier, elements, not );
       
  2626 		}
       
  2627 
       
  2628 		qualifier = jQuery.filter( qualifier, elements );
       
  2629 	}
       
  2630 
       
  2631 	return jQuery.grep( elements, function( elem ) {
       
  2632 		return ( indexOf.call( qualifier, elem ) >= 0 ) !== not;
       
  2633 	});
       
  2634 }
       
  2635 
       
  2636 jQuery.filter = function( expr, elems, not ) {
       
  2637 	var elem = elems[ 0 ];
       
  2638 
       
  2639 	if ( not ) {
       
  2640 		expr = ":not(" + expr + ")";
       
  2641 	}
       
  2642 
       
  2643 	return elems.length === 1 && elem.nodeType === 1 ?
       
  2644 		jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :
       
  2645 		jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
       
  2646 			return elem.nodeType === 1;
       
  2647 		}));
       
  2648 };
       
  2649 
       
  2650 jQuery.fn.extend({
       
  2651 	find: function( selector ) {
       
  2652 		var i,
       
  2653 			len = this.length,
       
  2654 			ret = [],
       
  2655 			self = this;
       
  2656 
       
  2657 		if ( typeof selector !== "string" ) {
       
  2658 			return this.pushStack( jQuery( selector ).filter(function() {
       
  2659 				for ( i = 0; i < len; i++ ) {
       
  2660 					if ( jQuery.contains( self[ i ], this ) ) {
       
  2661 						return true;
       
  2662 					}
       
  2663 				}
       
  2664 			}) );
       
  2665 		}
       
  2666 
       
  2667 		for ( i = 0; i < len; i++ ) {
       
  2668 			jQuery.find( selector, self[ i ], ret );
       
  2669 		}
       
  2670 
       
  2671 		// Needed because $( selector, context ) becomes $( context ).find( selector )
       
  2672 		ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
       
  2673 		ret.selector = this.selector ? this.selector + " " + selector : selector;
       
  2674 		return ret;
       
  2675 	},
       
  2676 	filter: function( selector ) {
       
  2677 		return this.pushStack( winnow(this, selector || [], false) );
       
  2678 	},
       
  2679 	not: function( selector ) {
       
  2680 		return this.pushStack( winnow(this, selector || [], true) );
       
  2681 	},
       
  2682 	is: function( selector ) {
       
  2683 		return !!winnow(
       
  2684 			this,
       
  2685 
       
  2686 			// If this is a positional/relative selector, check membership in the returned set
       
  2687 			// so $("p:first").is("p:last") won't return true for a doc with two "p".
       
  2688 			typeof selector === "string" && rneedsContext.test( selector ) ?
       
  2689 				jQuery( selector ) :
       
  2690 				selector || [],
       
  2691 			false
       
  2692 		).length;
       
  2693 	}
       
  2694 });
       
  2695 
       
  2696 
       
  2697 // Initialize a jQuery object
       
  2698 
       
  2699 
       
  2700 // A central reference to the root jQuery(document)
       
  2701 var rootjQuery,
       
  2702 
       
  2703 	// A simple way to check for HTML strings
       
  2704 	// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
       
  2705 	// Strict HTML recognition (#11290: must start with <)
       
  2706 	rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,
       
  2707 
       
  2708 	init = jQuery.fn.init = function( selector, context ) {
       
  2709 		var match, elem;
       
  2710 
       
  2711 		// HANDLE: $(""), $(null), $(undefined), $(false)
       
  2712 		if ( !selector ) {
       
  2713 			return this;
       
  2714 		}
       
  2715 
       
  2716 		// Handle HTML strings
       
  2717 		if ( typeof selector === "string" ) {
       
  2718 			if ( selector[0] === "<" && selector[ selector.length - 1 ] === ">" && selector.length >= 3 ) {
       
  2719 				// Assume that strings that start and end with <> are HTML and skip the regex check
       
  2720 				match = [ null, selector, null ];
       
  2721 
       
  2722 			} else {
       
  2723 				match = rquickExpr.exec( selector );
       
  2724 			}
       
  2725 
       
  2726 			// Match html or make sure no context is specified for #id
       
  2727 			if ( match && (match[1] || !context) ) {
       
  2728 
       
  2729 				// HANDLE: $(html) -> $(array)
       
  2730 				if ( match[1] ) {
       
  2731 					context = context instanceof jQuery ? context[0] : context;
       
  2732 
       
  2733 					// scripts is true for back-compat
       
  2734 					// Intentionally let the error be thrown if parseHTML is not present
       
  2735 					jQuery.merge( this, jQuery.parseHTML(
       
  2736 						match[1],
       
  2737 						context && context.nodeType ? context.ownerDocument || context : document,
       
  2738 						true
       
  2739 					) );
       
  2740 
       
  2741 					// HANDLE: $(html, props)
       
  2742 					if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
       
  2743 						for ( match in context ) {
       
  2744 							// Properties of context are called as methods if possible
       
  2745 							if ( jQuery.isFunction( this[ match ] ) ) {
       
  2746 								this[ match ]( context[ match ] );
       
  2747 
       
  2748 							// ...and otherwise set as attributes
       
  2749 							} else {
       
  2750 								this.attr( match, context[ match ] );
       
  2751 							}
       
  2752 						}
       
  2753 					}
       
  2754 
       
  2755 					return this;
       
  2756 
       
  2757 				// HANDLE: $(#id)
       
  2758 				} else {
       
  2759 					elem = document.getElementById( match[2] );
       
  2760 
       
  2761 					// Check parentNode to catch when Blackberry 4.6 returns
       
  2762 					// nodes that are no longer in the document #6963
       
  2763 					if ( elem && elem.parentNode ) {
       
  2764 						// Inject the element directly into the jQuery object
       
  2765 						this.length = 1;
       
  2766 						this[0] = elem;
       
  2767 					}
       
  2768 
       
  2769 					this.context = document;
       
  2770 					this.selector = selector;
       
  2771 					return this;
       
  2772 				}
       
  2773 
       
  2774 			// HANDLE: $(expr, $(...))
       
  2775 			} else if ( !context || context.jquery ) {
       
  2776 				return ( context || rootjQuery ).find( selector );
       
  2777 
       
  2778 			// HANDLE: $(expr, context)
       
  2779 			// (which is just equivalent to: $(context).find(expr)
       
  2780 			} else {
       
  2781 				return this.constructor( context ).find( selector );
       
  2782 			}
       
  2783 
       
  2784 		// HANDLE: $(DOMElement)
       
  2785 		} else if ( selector.nodeType ) {
       
  2786 			this.context = this[0] = selector;
       
  2787 			this.length = 1;
       
  2788 			return this;
       
  2789 
       
  2790 		// HANDLE: $(function)
       
  2791 		// Shortcut for document ready
       
  2792 		} else if ( jQuery.isFunction( selector ) ) {
       
  2793 			return typeof rootjQuery.ready !== "undefined" ?
       
  2794 				rootjQuery.ready( selector ) :
       
  2795 				// Execute immediately if ready is not present
       
  2796 				selector( jQuery );
       
  2797 		}
       
  2798 
       
  2799 		if ( selector.selector !== undefined ) {
       
  2800 			this.selector = selector.selector;
       
  2801 			this.context = selector.context;
       
  2802 		}
       
  2803 
       
  2804 		return jQuery.makeArray( selector, this );
       
  2805 	};
       
  2806 
       
  2807 // Give the init function the jQuery prototype for later instantiation
       
  2808 init.prototype = jQuery.fn;
       
  2809 
       
  2810 // Initialize central reference
       
  2811 rootjQuery = jQuery( document );
       
  2812 
       
  2813 
       
  2814 var rparentsprev = /^(?:parents|prev(?:Until|All))/,
       
  2815 	// methods guaranteed to produce a unique set when starting from a unique set
       
  2816 	guaranteedUnique = {
       
  2817 		children: true,
       
  2818 		contents: true,
       
  2819 		next: true,
       
  2820 		prev: true
       
  2821 	};
       
  2822 
       
  2823 jQuery.extend({
       
  2824 	dir: function( elem, dir, until ) {
       
  2825 		var matched = [],
       
  2826 			truncate = until !== undefined;
       
  2827 
       
  2828 		while ( (elem = elem[ dir ]) && elem.nodeType !== 9 ) {
       
  2829 			if ( elem.nodeType === 1 ) {
       
  2830 				if ( truncate && jQuery( elem ).is( until ) ) {
       
  2831 					break;
       
  2832 				}
       
  2833 				matched.push( elem );
       
  2834 			}
       
  2835 		}
       
  2836 		return matched;
       
  2837 	},
       
  2838 
       
  2839 	sibling: function( n, elem ) {
       
  2840 		var matched = [];
       
  2841 
       
  2842 		for ( ; n; n = n.nextSibling ) {
       
  2843 			if ( n.nodeType === 1 && n !== elem ) {
       
  2844 				matched.push( n );
       
  2845 			}
       
  2846 		}
       
  2847 
       
  2848 		return matched;
       
  2849 	}
       
  2850 });
       
  2851 
       
  2852 jQuery.fn.extend({
       
  2853 	has: function( target ) {
       
  2854 		var targets = jQuery( target, this ),
       
  2855 			l = targets.length;
       
  2856 
       
  2857 		return this.filter(function() {
       
  2858 			var i = 0;
       
  2859 			for ( ; i < l; i++ ) {
       
  2860 				if ( jQuery.contains( this, targets[i] ) ) {
       
  2861 					return true;
       
  2862 				}
       
  2863 			}
       
  2864 		});
       
  2865 	},
       
  2866 
       
  2867 	closest: function( selectors, context ) {
       
  2868 		var cur,
       
  2869 			i = 0,
       
  2870 			l = this.length,
       
  2871 			matched = [],
       
  2872 			pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
       
  2873 				jQuery( selectors, context || this.context ) :
       
  2874 				0;
       
  2875 
       
  2876 		for ( ; i < l; i++ ) {
       
  2877 			for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) {
       
  2878 				// Always skip document fragments
       
  2879 				if ( cur.nodeType < 11 && (pos ?
       
  2880 					pos.index(cur) > -1 :
       
  2881 
       
  2882 					// Don't pass non-elements to Sizzle
       
  2883 					cur.nodeType === 1 &&
       
  2884 						jQuery.find.matchesSelector(cur, selectors)) ) {
       
  2885 
       
  2886 					matched.push( cur );
       
  2887 					break;
       
  2888 				}
       
  2889 			}
       
  2890 		}
       
  2891 
       
  2892 		return this.pushStack( matched.length > 1 ? jQuery.unique( matched ) : matched );
       
  2893 	},
       
  2894 
       
  2895 	// Determine the position of an element within
       
  2896 	// the matched set of elements
       
  2897 	index: function( elem ) {
       
  2898 
       
  2899 		// No argument, return index in parent
       
  2900 		if ( !elem ) {
       
  2901 			return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;
       
  2902 		}
       
  2903 
       
  2904 		// index in selector
       
  2905 		if ( typeof elem === "string" ) {
       
  2906 			return indexOf.call( jQuery( elem ), this[ 0 ] );
       
  2907 		}
       
  2908 
       
  2909 		// Locate the position of the desired element
       
  2910 		return indexOf.call( this,
       
  2911 
       
  2912 			// If it receives a jQuery object, the first element is used
       
  2913 			elem.jquery ? elem[ 0 ] : elem
       
  2914 		);
       
  2915 	},
       
  2916 
       
  2917 	add: function( selector, context ) {
       
  2918 		return this.pushStack(
       
  2919 			jQuery.unique(
       
  2920 				jQuery.merge( this.get(), jQuery( selector, context ) )
       
  2921 			)
       
  2922 		);
       
  2923 	},
       
  2924 
       
  2925 	addBack: function( selector ) {
       
  2926 		return this.add( selector == null ?
       
  2927 			this.prevObject : this.prevObject.filter(selector)
       
  2928 		);
       
  2929 	}
       
  2930 });
       
  2931 
       
  2932 function sibling( cur, dir ) {
       
  2933 	while ( (cur = cur[dir]) && cur.nodeType !== 1 ) {}
       
  2934 	return cur;
       
  2935 }
       
  2936 
       
  2937 jQuery.each({
       
  2938 	parent: function( elem ) {
       
  2939 		var parent = elem.parentNode;
       
  2940 		return parent && parent.nodeType !== 11 ? parent : null;
       
  2941 	},
       
  2942 	parents: function( elem ) {
       
  2943 		return jQuery.dir( elem, "parentNode" );
       
  2944 	},
       
  2945 	parentsUntil: function( elem, i, until ) {
       
  2946 		return jQuery.dir( elem, "parentNode", until );
       
  2947 	},
       
  2948 	next: function( elem ) {
       
  2949 		return sibling( elem, "nextSibling" );
       
  2950 	},
       
  2951 	prev: function( elem ) {
       
  2952 		return sibling( elem, "previousSibling" );
       
  2953 	},
       
  2954 	nextAll: function( elem ) {
       
  2955 		return jQuery.dir( elem, "nextSibling" );
       
  2956 	},
       
  2957 	prevAll: function( elem ) {
       
  2958 		return jQuery.dir( elem, "previousSibling" );
       
  2959 	},
       
  2960 	nextUntil: function( elem, i, until ) {
       
  2961 		return jQuery.dir( elem, "nextSibling", until );
       
  2962 	},
       
  2963 	prevUntil: function( elem, i, until ) {
       
  2964 		return jQuery.dir( elem, "previousSibling", until );
       
  2965 	},
       
  2966 	siblings: function( elem ) {
       
  2967 		return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
       
  2968 	},
       
  2969 	children: function( elem ) {
       
  2970 		return jQuery.sibling( elem.firstChild );
       
  2971 	},
       
  2972 	contents: function( elem ) {
       
  2973 		return elem.contentDocument || jQuery.merge( [], elem.childNodes );
       
  2974 	}
       
  2975 }, function( name, fn ) {
       
  2976 	jQuery.fn[ name ] = function( until, selector ) {
       
  2977 		var matched = jQuery.map( this, fn, until );
       
  2978 
       
  2979 		if ( name.slice( -5 ) !== "Until" ) {
       
  2980 			selector = until;
       
  2981 		}
       
  2982 
       
  2983 		if ( selector && typeof selector === "string" ) {
       
  2984 			matched = jQuery.filter( selector, matched );
       
  2985 		}
       
  2986 
       
  2987 		if ( this.length > 1 ) {
       
  2988 			// Remove duplicates
       
  2989 			if ( !guaranteedUnique[ name ] ) {
       
  2990 				jQuery.unique( matched );
       
  2991 			}
       
  2992 
       
  2993 			// Reverse order for parents* and prev-derivatives
       
  2994 			if ( rparentsprev.test( name ) ) {
       
  2995 				matched.reverse();
       
  2996 			}
       
  2997 		}
       
  2998 
       
  2999 		return this.pushStack( matched );
       
  3000 	};
       
  3001 });
       
  3002 var rnotwhite = (/\S+/g);
       
  3003 
       
  3004 
       
  3005 
       
  3006 // String to Object options format cache
       
  3007 var optionsCache = {};
       
  3008 
       
  3009 // Convert String-formatted options into Object-formatted ones and store in cache
       
  3010 function createOptions( options ) {
       
  3011 	var object = optionsCache[ options ] = {};
       
  3012 	jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) {
       
  3013 		object[ flag ] = true;
       
  3014 	});
       
  3015 	return object;
       
  3016 }
       
  3017 
       
  3018 /*
       
  3019  * Create a callback list using the following parameters:
       
  3020  *
       
  3021  *	options: an optional list of space-separated options that will change how
       
  3022  *			the callback list behaves or a more traditional option object
       
  3023  *
       
  3024  * By default a callback list will act like an event callback list and can be
       
  3025  * "fired" multiple times.
       
  3026  *
       
  3027  * Possible options:
       
  3028  *
       
  3029  *	once:			will ensure the callback list can only be fired once (like a Deferred)
       
  3030  *
       
  3031  *	memory:			will keep track of previous values and will call any callback added
       
  3032  *					after the list has been fired right away with the latest "memorized"
       
  3033  *					values (like a Deferred)
       
  3034  *
       
  3035  *	unique:			will ensure a callback can only be added once (no duplicate in the list)
       
  3036  *
       
  3037  *	stopOnFalse:	interrupt callings when a callback returns false
       
  3038  *
       
  3039  */
       
  3040 jQuery.Callbacks = function( options ) {
       
  3041 
       
  3042 	// Convert options from String-formatted to Object-formatted if needed
       
  3043 	// (we check in cache first)
       
  3044 	options = typeof options === "string" ?
       
  3045 		( optionsCache[ options ] || createOptions( options ) ) :
       
  3046 		jQuery.extend( {}, options );
       
  3047 
       
  3048 	var // Last fire value (for non-forgettable lists)
       
  3049 		memory,
       
  3050 		// Flag to know if list was already fired
       
  3051 		fired,
       
  3052 		// Flag to know if list is currently firing
       
  3053 		firing,
       
  3054 		// First callback to fire (used internally by add and fireWith)
       
  3055 		firingStart,
       
  3056 		// End of the loop when firing
       
  3057 		firingLength,
       
  3058 		// Index of currently firing callback (modified by remove if needed)
       
  3059 		firingIndex,
       
  3060 		// Actual callback list
       
  3061 		list = [],
       
  3062 		// Stack of fire calls for repeatable lists
       
  3063 		stack = !options.once && [],
       
  3064 		// Fire callbacks
       
  3065 		fire = function( data ) {
       
  3066 			memory = options.memory && data;
       
  3067 			fired = true;
       
  3068 			firingIndex = firingStart || 0;
       
  3069 			firingStart = 0;
       
  3070 			firingLength = list.length;
       
  3071 			firing = true;
       
  3072 			for ( ; list && firingIndex < firingLength; firingIndex++ ) {
       
  3073 				if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
       
  3074 					memory = false; // To prevent further calls using add
       
  3075 					break;
       
  3076 				}
       
  3077 			}
       
  3078 			firing = false;
       
  3079 			if ( list ) {
       
  3080 				if ( stack ) {
       
  3081 					if ( stack.length ) {
       
  3082 						fire( stack.shift() );
       
  3083 					}
       
  3084 				} else if ( memory ) {
       
  3085 					list = [];
       
  3086 				} else {
       
  3087 					self.disable();
       
  3088 				}
       
  3089 			}
       
  3090 		},
       
  3091 		// Actual Callbacks object
       
  3092 		self = {
       
  3093 			// Add a callback or a collection of callbacks to the list
       
  3094 			add: function() {
       
  3095 				if ( list ) {
       
  3096 					// First, we save the current length
       
  3097 					var start = list.length;
       
  3098 					(function add( args ) {
       
  3099 						jQuery.each( args, function( _, arg ) {
       
  3100 							var type = jQuery.type( arg );
       
  3101 							if ( type === "function" ) {
       
  3102 								if ( !options.unique || !self.has( arg ) ) {
       
  3103 									list.push( arg );
       
  3104 								}
       
  3105 							} else if ( arg && arg.length && type !== "string" ) {
       
  3106 								// Inspect recursively
       
  3107 								add( arg );
       
  3108 							}
       
  3109 						});
       
  3110 					})( arguments );
       
  3111 					// Do we need to add the callbacks to the
       
  3112 					// current firing batch?
       
  3113 					if ( firing ) {
       
  3114 						firingLength = list.length;
       
  3115 					// With memory, if we're not firing then
       
  3116 					// we should call right away
       
  3117 					} else if ( memory ) {
       
  3118 						firingStart = start;
       
  3119 						fire( memory );
       
  3120 					}
       
  3121 				}
       
  3122 				return this;
       
  3123 			},
       
  3124 			// Remove a callback from the list
       
  3125 			remove: function() {
       
  3126 				if ( list ) {
       
  3127 					jQuery.each( arguments, function( _, arg ) {
       
  3128 						var index;
       
  3129 						while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
       
  3130 							list.splice( index, 1 );
       
  3131 							// Handle firing indexes
       
  3132 							if ( firing ) {
       
  3133 								if ( index <= firingLength ) {
       
  3134 									firingLength--;
       
  3135 								}
       
  3136 								if ( index <= firingIndex ) {
       
  3137 									firingIndex--;
       
  3138 								}
       
  3139 							}
       
  3140 						}
       
  3141 					});
       
  3142 				}
       
  3143 				return this;
       
  3144 			},
       
  3145 			// Check if a given callback is in the list.
       
  3146 			// If no argument is given, return whether or not list has callbacks attached.
       
  3147 			has: function( fn ) {
       
  3148 				return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
       
  3149 			},
       
  3150 			// Remove all callbacks from the list
       
  3151 			empty: function() {
       
  3152 				list = [];
       
  3153 				firingLength = 0;
       
  3154 				return this;
       
  3155 			},
       
  3156 			// Have the list do nothing anymore
       
  3157 			disable: function() {
       
  3158 				list = stack = memory = undefined;
       
  3159 				return this;
       
  3160 			},
       
  3161 			// Is it disabled?
       
  3162 			disabled: function() {
       
  3163 				return !list;
       
  3164 			},
       
  3165 			// Lock the list in its current state
       
  3166 			lock: function() {
       
  3167 				stack = undefined;
       
  3168 				if ( !memory ) {
       
  3169 					self.disable();
       
  3170 				}
       
  3171 				return this;
       
  3172 			},
       
  3173 			// Is it locked?
       
  3174 			locked: function() {
       
  3175 				return !stack;
       
  3176 			},
       
  3177 			// Call all callbacks with the given context and arguments
       
  3178 			fireWith: function( context, args ) {
       
  3179 				if ( list && ( !fired || stack ) ) {
       
  3180 					args = args || [];
       
  3181 					args = [ context, args.slice ? args.slice() : args ];
       
  3182 					if ( firing ) {
       
  3183 						stack.push( args );
       
  3184 					} else {
       
  3185 						fire( args );
       
  3186 					}
       
  3187 				}
       
  3188 				return this;
       
  3189 			},
       
  3190 			// Call all the callbacks with the given arguments
       
  3191 			fire: function() {
       
  3192 				self.fireWith( this, arguments );
       
  3193 				return this;
       
  3194 			},
       
  3195 			// To know if the callbacks have already been called at least once
       
  3196 			fired: function() {
       
  3197 				return !!fired;
       
  3198 			}
       
  3199 		};
       
  3200 
       
  3201 	return self;
       
  3202 };
       
  3203 
       
  3204 
       
  3205 jQuery.extend({
       
  3206 
       
  3207 	Deferred: function( func ) {
       
  3208 		var tuples = [
       
  3209 				// action, add listener, listener list, final state
       
  3210 				[ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
       
  3211 				[ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
       
  3212 				[ "notify", "progress", jQuery.Callbacks("memory") ]
       
  3213 			],
       
  3214 			state = "pending",
       
  3215 			promise = {
       
  3216 				state: function() {
       
  3217 					return state;
       
  3218 				},
       
  3219 				always: function() {
       
  3220 					deferred.done( arguments ).fail( arguments );
       
  3221 					return this;
       
  3222 				},
       
  3223 				then: function( /* fnDone, fnFail, fnProgress */ ) {
       
  3224 					var fns = arguments;
       
  3225 					return jQuery.Deferred(function( newDefer ) {
       
  3226 						jQuery.each( tuples, function( i, tuple ) {
       
  3227 							var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
       
  3228 							// deferred[ done | fail | progress ] for forwarding actions to newDefer
       
  3229 							deferred[ tuple[1] ](function() {
       
  3230 								var returned = fn && fn.apply( this, arguments );
       
  3231 								if ( returned && jQuery.isFunction( returned.promise ) ) {
       
  3232 									returned.promise()
       
  3233 										.done( newDefer.resolve )
       
  3234 										.fail( newDefer.reject )
       
  3235 										.progress( newDefer.notify );
       
  3236 								} else {
       
  3237 									newDefer[ tuple[ 0 ] + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
       
  3238 								}
       
  3239 							});
       
  3240 						});
       
  3241 						fns = null;
       
  3242 					}).promise();
       
  3243 				},
       
  3244 				// Get a promise for this deferred
       
  3245 				// If obj is provided, the promise aspect is added to the object
       
  3246 				promise: function( obj ) {
       
  3247 					return obj != null ? jQuery.extend( obj, promise ) : promise;
       
  3248 				}
       
  3249 			},
       
  3250 			deferred = {};
       
  3251 
       
  3252 		// Keep pipe for back-compat
       
  3253 		promise.pipe = promise.then;
       
  3254 
       
  3255 		// Add list-specific methods
       
  3256 		jQuery.each( tuples, function( i, tuple ) {
       
  3257 			var list = tuple[ 2 ],
       
  3258 				stateString = tuple[ 3 ];
       
  3259 
       
  3260 			// promise[ done | fail | progress ] = list.add
       
  3261 			promise[ tuple[1] ] = list.add;
       
  3262 
       
  3263 			// Handle state
       
  3264 			if ( stateString ) {
       
  3265 				list.add(function() {
       
  3266 					// state = [ resolved | rejected ]
       
  3267 					state = stateString;
       
  3268 
       
  3269 				// [ reject_list | resolve_list ].disable; progress_list.lock
       
  3270 				}, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
       
  3271 			}
       
  3272 
       
  3273 			// deferred[ resolve | reject | notify ]
       
  3274 			deferred[ tuple[0] ] = function() {
       
  3275 				deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
       
  3276 				return this;
       
  3277 			};
       
  3278 			deferred[ tuple[0] + "With" ] = list.fireWith;
       
  3279 		});
       
  3280 
       
  3281 		// Make the deferred a promise
       
  3282 		promise.promise( deferred );
       
  3283 
       
  3284 		// Call given func if any
       
  3285 		if ( func ) {
       
  3286 			func.call( deferred, deferred );
       
  3287 		}
       
  3288 
       
  3289 		// All done!
       
  3290 		return deferred;
       
  3291 	},
       
  3292 
       
  3293 	// Deferred helper
       
  3294 	when: function( subordinate /* , ..., subordinateN */ ) {
       
  3295 		var i = 0,
       
  3296 			resolveValues = slice.call( arguments ),
       
  3297 			length = resolveValues.length,
       
  3298 
       
  3299 			// the count of uncompleted subordinates
       
  3300 			remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
       
  3301 
       
  3302 			// the master Deferred. If resolveValues consist of only a single Deferred, just use that.
       
  3303 			deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
       
  3304 
       
  3305 			// Update function for both resolve and progress values
       
  3306 			updateFunc = function( i, contexts, values ) {
       
  3307 				return function( value ) {
       
  3308 					contexts[ i ] = this;
       
  3309 					values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
       
  3310 					if ( values === progressValues ) {
       
  3311 						deferred.notifyWith( contexts, values );
       
  3312 					} else if ( !( --remaining ) ) {
       
  3313 						deferred.resolveWith( contexts, values );
       
  3314 					}
       
  3315 				};
       
  3316 			},
       
  3317 
       
  3318 			progressValues, progressContexts, resolveContexts;
       
  3319 
       
  3320 		// add listeners to Deferred subordinates; treat others as resolved
       
  3321 		if ( length > 1 ) {
       
  3322 			progressValues = new Array( length );
       
  3323 			progressContexts = new Array( length );
       
  3324 			resolveContexts = new Array( length );
       
  3325 			for ( ; i < length; i++ ) {
       
  3326 				if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
       
  3327 					resolveValues[ i ].promise()
       
  3328 						.done( updateFunc( i, resolveContexts, resolveValues ) )
       
  3329 						.fail( deferred.reject )
       
  3330 						.progress( updateFunc( i, progressContexts, progressValues ) );
       
  3331 				} else {
       
  3332 					--remaining;
       
  3333 				}
       
  3334 			}
       
  3335 		}
       
  3336 
       
  3337 		// if we're not waiting on anything, resolve the master
       
  3338 		if ( !remaining ) {
       
  3339 			deferred.resolveWith( resolveContexts, resolveValues );
       
  3340 		}
       
  3341 
       
  3342 		return deferred.promise();
       
  3343 	}
       
  3344 });
       
  3345 
       
  3346 
       
  3347 // The deferred used on DOM ready
       
  3348 var readyList;
       
  3349 
       
  3350 jQuery.fn.ready = function( fn ) {
       
  3351 	// Add the callback
       
  3352 	jQuery.ready.promise().done( fn );
       
  3353 
       
  3354 	return this;
       
  3355 };
       
  3356 
       
  3357 jQuery.extend({
       
  3358 	// Is the DOM ready to be used? Set to true once it occurs.
       
  3359 	isReady: false,
       
  3360 
       
  3361 	// A counter to track how many items to wait for before
       
  3362 	// the ready event fires. See #6781
       
  3363 	readyWait: 1,
       
  3364 
       
  3365 	// Hold (or release) the ready event
       
  3366 	holdReady: function( hold ) {
       
  3367 		if ( hold ) {
       
  3368 			jQuery.readyWait++;
       
  3369 		} else {
       
  3370 			jQuery.ready( true );
       
  3371 		}
       
  3372 	},
       
  3373 
       
  3374 	// Handle when the DOM is ready
       
  3375 	ready: function( wait ) {
       
  3376 
       
  3377 		// Abort if there are pending holds or we're already ready
       
  3378 		if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
       
  3379 			return;
       
  3380 		}
       
  3381 
       
  3382 		// Remember that the DOM is ready
       
  3383 		jQuery.isReady = true;
       
  3384 
       
  3385 		// If a normal DOM Ready event fired, decrement, and wait if need be
       
  3386 		if ( wait !== true && --jQuery.readyWait > 0 ) {
       
  3387 			return;
       
  3388 		}
       
  3389 
       
  3390 		// If there are functions bound, to execute
       
  3391 		readyList.resolveWith( document, [ jQuery ] );
       
  3392 
       
  3393 		// Trigger any bound ready events
       
  3394 		if ( jQuery.fn.triggerHandler ) {
       
  3395 			jQuery( document ).triggerHandler( "ready" );
       
  3396 			jQuery( document ).off( "ready" );
       
  3397 		}
       
  3398 	}
       
  3399 });
       
  3400 
       
  3401 /**
       
  3402  * The ready event handler and self cleanup method
       
  3403  */
       
  3404 function completed() {
       
  3405 	document.removeEventListener( "DOMContentLoaded", completed, false );
       
  3406 	window.removeEventListener( "load", completed, false );
       
  3407 	jQuery.ready();
       
  3408 }
       
  3409 
       
  3410 jQuery.ready.promise = function( obj ) {
       
  3411 	if ( !readyList ) {
       
  3412 
       
  3413 		readyList = jQuery.Deferred();
       
  3414 
       
  3415 		// Catch cases where $(document).ready() is called after the browser event has already occurred.
       
  3416 		// we once tried to use readyState "interactive" here, but it caused issues like the one
       
  3417 		// discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
       
  3418 		if ( document.readyState === "complete" ) {
       
  3419 			// Handle it asynchronously to allow scripts the opportunity to delay ready
       
  3420 			setTimeout( jQuery.ready );
       
  3421 
       
  3422 		} else {
       
  3423 
       
  3424 			// Use the handy event callback
       
  3425 			document.addEventListener( "DOMContentLoaded", completed, false );
       
  3426 
       
  3427 			// A fallback to window.onload, that will always work
       
  3428 			window.addEventListener( "load", completed, false );
       
  3429 		}
       
  3430 	}
       
  3431 	return readyList.promise( obj );
       
  3432 };
       
  3433 
       
  3434 // Kick off the DOM ready check even if the user does not
       
  3435 jQuery.ready.promise();
       
  3436 
       
  3437 
       
  3438 
       
  3439 
       
  3440 // Multifunctional method to get and set values of a collection
       
  3441 // The value/s can optionally be executed if it's a function
       
  3442 var access = jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
       
  3443 	var i = 0,
       
  3444 		len = elems.length,
       
  3445 		bulk = key == null;
       
  3446 
       
  3447 	// Sets many values
       
  3448 	if ( jQuery.type( key ) === "object" ) {
       
  3449 		chainable = true;
       
  3450 		for ( i in key ) {
       
  3451 			jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
       
  3452 		}
       
  3453 
       
  3454 	// Sets one value
       
  3455 	} else if ( value !== undefined ) {
       
  3456 		chainable = true;
       
  3457 
       
  3458 		if ( !jQuery.isFunction( value ) ) {
       
  3459 			raw = true;
       
  3460 		}
       
  3461 
       
  3462 		if ( bulk ) {
       
  3463 			// Bulk operations run against the entire set
       
  3464 			if ( raw ) {
       
  3465 				fn.call( elems, value );
       
  3466 				fn = null;
       
  3467 
       
  3468 			// ...except when executing function values
       
  3469 			} else {
       
  3470 				bulk = fn;
       
  3471 				fn = function( elem, key, value ) {
       
  3472 					return bulk.call( jQuery( elem ), value );
       
  3473 				};
       
  3474 			}
       
  3475 		}
       
  3476 
       
  3477 		if ( fn ) {
       
  3478 			for ( ; i < len; i++ ) {
       
  3479 				fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
       
  3480 			}
       
  3481 		}
       
  3482 	}
       
  3483 
       
  3484 	return chainable ?
       
  3485 		elems :
       
  3486 
       
  3487 		// Gets
       
  3488 		bulk ?
       
  3489 			fn.call( elems ) :
       
  3490 			len ? fn( elems[0], key ) : emptyGet;
       
  3491 };
       
  3492 
       
  3493 
       
  3494 /**
       
  3495  * Determines whether an object can have data
       
  3496  */
       
  3497 jQuery.acceptData = function( owner ) {
       
  3498 	// Accepts only:
       
  3499 	//  - Node
       
  3500 	//    - Node.ELEMENT_NODE
       
  3501 	//    - Node.DOCUMENT_NODE
       
  3502 	//  - Object
       
  3503 	//    - Any
       
  3504 	/* jshint -W018 */
       
  3505 	return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType );
       
  3506 };
       
  3507 
       
  3508 
       
  3509 function Data() {
       
  3510 	// Support: Android < 4,
       
  3511 	// Old WebKit does not have Object.preventExtensions/freeze method,
       
  3512 	// return new empty object instead with no [[set]] accessor
       
  3513 	Object.defineProperty( this.cache = {}, 0, {
       
  3514 		get: function() {
       
  3515 			return {};
       
  3516 		}
       
  3517 	});
       
  3518 
       
  3519 	this.expando = jQuery.expando + Math.random();
       
  3520 }
       
  3521 
       
  3522 Data.uid = 1;
       
  3523 Data.accepts = jQuery.acceptData;
       
  3524 
       
  3525 Data.prototype = {
       
  3526 	key: function( owner ) {
       
  3527 		// We can accept data for non-element nodes in modern browsers,
       
  3528 		// but we should not, see #8335.
       
  3529 		// Always return the key for a frozen object.
       
  3530 		if ( !Data.accepts( owner ) ) {
       
  3531 			return 0;
       
  3532 		}
       
  3533 
       
  3534 		var descriptor = {},
       
  3535 			// Check if the owner object already has a cache key
       
  3536 			unlock = owner[ this.expando ];
       
  3537 
       
  3538 		// If not, create one
       
  3539 		if ( !unlock ) {
       
  3540 			unlock = Data.uid++;
       
  3541 
       
  3542 			// Secure it in a non-enumerable, non-writable property
       
  3543 			try {
       
  3544 				descriptor[ this.expando ] = { value: unlock };
       
  3545 				Object.defineProperties( owner, descriptor );
       
  3546 
       
  3547 			// Support: Android < 4
       
  3548 			// Fallback to a less secure definition
       
  3549 			} catch ( e ) {
       
  3550 				descriptor[ this.expando ] = unlock;
       
  3551 				jQuery.extend( owner, descriptor );
       
  3552 			}
       
  3553 		}
       
  3554 
       
  3555 		// Ensure the cache object
       
  3556 		if ( !this.cache[ unlock ] ) {
       
  3557 			this.cache[ unlock ] = {};
       
  3558 		}
       
  3559 
       
  3560 		return unlock;
       
  3561 	},
       
  3562 	set: function( owner, data, value ) {
       
  3563 		var prop,
       
  3564 			// There may be an unlock assigned to this node,
       
  3565 			// if there is no entry for this "owner", create one inline
       
  3566 			// and set the unlock as though an owner entry had always existed
       
  3567 			unlock = this.key( owner ),
       
  3568 			cache = this.cache[ unlock ];
       
  3569 
       
  3570 		// Handle: [ owner, key, value ] args
       
  3571 		if ( typeof data === "string" ) {
       
  3572 			cache[ data ] = value;
       
  3573 
       
  3574 		// Handle: [ owner, { properties } ] args
       
  3575 		} else {
       
  3576 			// Fresh assignments by object are shallow copied
       
  3577 			if ( jQuery.isEmptyObject( cache ) ) {
       
  3578 				jQuery.extend( this.cache[ unlock ], data );
       
  3579 			// Otherwise, copy the properties one-by-one to the cache object
       
  3580 			} else {
       
  3581 				for ( prop in data ) {
       
  3582 					cache[ prop ] = data[ prop ];
       
  3583 				}
       
  3584 			}
       
  3585 		}
       
  3586 		return cache;
       
  3587 	},
       
  3588 	get: function( owner, key ) {
       
  3589 		// Either a valid cache is found, or will be created.
       
  3590 		// New caches will be created and the unlock returned,
       
  3591 		// allowing direct access to the newly created
       
  3592 		// empty data object. A valid owner object must be provided.
       
  3593 		var cache = this.cache[ this.key( owner ) ];
       
  3594 
       
  3595 		return key === undefined ?
       
  3596 			cache : cache[ key ];
       
  3597 	},
       
  3598 	access: function( owner, key, value ) {
       
  3599 		var stored;
       
  3600 		// In cases where either:
       
  3601 		//
       
  3602 		//   1. No key was specified
       
  3603 		//   2. A string key was specified, but no value provided
       
  3604 		//
       
  3605 		// Take the "read" path and allow the get method to determine
       
  3606 		// which value to return, respectively either:
       
  3607 		//
       
  3608 		//   1. The entire cache object
       
  3609 		//   2. The data stored at the key
       
  3610 		//
       
  3611 		if ( key === undefined ||
       
  3612 				((key && typeof key === "string") && value === undefined) ) {
       
  3613 
       
  3614 			stored = this.get( owner, key );
       
  3615 
       
  3616 			return stored !== undefined ?
       
  3617 				stored : this.get( owner, jQuery.camelCase(key) );
       
  3618 		}
       
  3619 
       
  3620 		// [*]When the key is not a string, or both a key and value
       
  3621 		// are specified, set or extend (existing objects) with either:
       
  3622 		//
       
  3623 		//   1. An object of properties
       
  3624 		//   2. A key and value
       
  3625 		//
       
  3626 		this.set( owner, key, value );
       
  3627 
       
  3628 		// Since the "set" path can have two possible entry points
       
  3629 		// return the expected data based on which path was taken[*]
       
  3630 		return value !== undefined ? value : key;
       
  3631 	},
       
  3632 	remove: function( owner, key ) {
       
  3633 		var i, name, camel,
       
  3634 			unlock = this.key( owner ),
       
  3635 			cache = this.cache[ unlock ];
       
  3636 
       
  3637 		if ( key === undefined ) {
       
  3638 			this.cache[ unlock ] = {};
       
  3639 
       
  3640 		} else {
       
  3641 			// Support array or space separated string of keys
       
  3642 			if ( jQuery.isArray( key ) ) {
       
  3643 				// If "name" is an array of keys...
       
  3644 				// When data is initially created, via ("key", "val") signature,
       
  3645 				// keys will be converted to camelCase.
       
  3646 				// Since there is no way to tell _how_ a key was added, remove
       
  3647 				// both plain key and camelCase key. #12786
       
  3648 				// This will only penalize the array argument path.
       
  3649 				name = key.concat( key.map( jQuery.camelCase ) );
       
  3650 			} else {
       
  3651 				camel = jQuery.camelCase( key );
       
  3652 				// Try the string as a key before any manipulation
       
  3653 				if ( key in cache ) {
       
  3654 					name = [ key, camel ];
       
  3655 				} else {
       
  3656 					// If a key with the spaces exists, use it.
       
  3657 					// Otherwise, create an array by matching non-whitespace
       
  3658 					name = camel;
       
  3659 					name = name in cache ?
       
  3660 						[ name ] : ( name.match( rnotwhite ) || [] );
       
  3661 				}
       
  3662 			}
       
  3663 
       
  3664 			i = name.length;
       
  3665 			while ( i-- ) {
       
  3666 				delete cache[ name[ i ] ];
       
  3667 			}
       
  3668 		}
       
  3669 	},
       
  3670 	hasData: function( owner ) {
       
  3671 		return !jQuery.isEmptyObject(
       
  3672 			this.cache[ owner[ this.expando ] ] || {}
       
  3673 		);
       
  3674 	},
       
  3675 	discard: function( owner ) {
       
  3676 		if ( owner[ this.expando ] ) {
       
  3677 			delete this.cache[ owner[ this.expando ] ];
       
  3678 		}
       
  3679 	}
       
  3680 };
       
  3681 var data_priv = new Data();
       
  3682 
       
  3683 var data_user = new Data();
       
  3684 
       
  3685 
       
  3686 
       
  3687 /*
       
  3688 	Implementation Summary
       
  3689 
       
  3690 	1. Enforce API surface and semantic compatibility with 1.9.x branch
       
  3691 	2. Improve the module's maintainability by reducing the storage
       
  3692 		paths to a single mechanism.
       
  3693 	3. Use the same single mechanism to support "private" and "user" data.
       
  3694 	4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData)
       
  3695 	5. Avoid exposing implementation details on user objects (eg. expando properties)
       
  3696 	6. Provide a clear path for implementation upgrade to WeakMap in 2014
       
  3697 */
       
  3698 var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,
       
  3699 	rmultiDash = /([A-Z])/g;
       
  3700 
       
  3701 function dataAttr( elem, key, data ) {
       
  3702 	var name;
       
  3703 
       
  3704 	// If nothing was found internally, try to fetch any
       
  3705 	// data from the HTML5 data-* attribute
       
  3706 	if ( data === undefined && elem.nodeType === 1 ) {
       
  3707 		name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
       
  3708 		data = elem.getAttribute( name );
       
  3709 
       
  3710 		if ( typeof data === "string" ) {
       
  3711 			try {
       
  3712 				data = data === "true" ? true :
       
  3713 					data === "false" ? false :
       
  3714 					data === "null" ? null :
       
  3715 					// Only convert to a number if it doesn't change the string
       
  3716 					+data + "" === data ? +data :
       
  3717 					rbrace.test( data ) ? jQuery.parseJSON( data ) :
       
  3718 					data;
       
  3719 			} catch( e ) {}
       
  3720 
       
  3721 			// Make sure we set the data so it isn't changed later
       
  3722 			data_user.set( elem, key, data );
       
  3723 		} else {
       
  3724 			data = undefined;
       
  3725 		}
       
  3726 	}
       
  3727 	return data;
       
  3728 }
       
  3729 
       
  3730 jQuery.extend({
       
  3731 	hasData: function( elem ) {
       
  3732 		return data_user.hasData( elem ) || data_priv.hasData( elem );
       
  3733 	},
       
  3734 
       
  3735 	data: function( elem, name, data ) {
       
  3736 		return data_user.access( elem, name, data );
       
  3737 	},
       
  3738 
       
  3739 	removeData: function( elem, name ) {
       
  3740 		data_user.remove( elem, name );
       
  3741 	},
       
  3742 
       
  3743 	// TODO: Now that all calls to _data and _removeData have been replaced
       
  3744 	// with direct calls to data_priv methods, these can be deprecated.
       
  3745 	_data: function( elem, name, data ) {
       
  3746 		return data_priv.access( elem, name, data );
       
  3747 	},
       
  3748 
       
  3749 	_removeData: function( elem, name ) {
       
  3750 		data_priv.remove( elem, name );
       
  3751 	}
       
  3752 });
       
  3753 
       
  3754 jQuery.fn.extend({
       
  3755 	data: function( key, value ) {
       
  3756 		var i, name, data,
       
  3757 			elem = this[ 0 ],
       
  3758 			attrs = elem && elem.attributes;
       
  3759 
       
  3760 		// Gets all values
       
  3761 		if ( key === undefined ) {
       
  3762 			if ( this.length ) {
       
  3763 				data = data_user.get( elem );
       
  3764 
       
  3765 				if ( elem.nodeType === 1 && !data_priv.get( elem, "hasDataAttrs" ) ) {
       
  3766 					i = attrs.length;
       
  3767 					while ( i-- ) {
       
  3768 
       
  3769 						// Support: IE11+
       
  3770 						// The attrs elements can be null (#14894)
       
  3771 						if ( attrs[ i ] ) {
       
  3772 							name = attrs[ i ].name;
       
  3773 							if ( name.indexOf( "data-" ) === 0 ) {
       
  3774 								name = jQuery.camelCase( name.slice(5) );
       
  3775 								dataAttr( elem, name, data[ name ] );
       
  3776 							}
       
  3777 						}
       
  3778 					}
       
  3779 					data_priv.set( elem, "hasDataAttrs", true );
       
  3780 				}
       
  3781 			}
       
  3782 
       
  3783 			return data;
       
  3784 		}
       
  3785 
       
  3786 		// Sets multiple values
       
  3787 		if ( typeof key === "object" ) {
       
  3788 			return this.each(function() {
       
  3789 				data_user.set( this, key );
       
  3790 			});
       
  3791 		}
       
  3792 
       
  3793 		return access( this, function( value ) {
       
  3794 			var data,
       
  3795 				camelKey = jQuery.camelCase( key );
       
  3796 
       
  3797 			// The calling jQuery object (element matches) is not empty
       
  3798 			// (and therefore has an element appears at this[ 0 ]) and the
       
  3799 			// `value` parameter was not undefined. An empty jQuery object
       
  3800 			// will result in `undefined` for elem = this[ 0 ] which will
       
  3801 			// throw an exception if an attempt to read a data cache is made.
       
  3802 			if ( elem && value === undefined ) {
       
  3803 				// Attempt to get data from the cache
       
  3804 				// with the key as-is
       
  3805 				data = data_user.get( elem, key );
       
  3806 				if ( data !== undefined ) {
       
  3807 					return data;
       
  3808 				}
       
  3809 
       
  3810 				// Attempt to get data from the cache
       
  3811 				// with the key camelized
       
  3812 				data = data_user.get( elem, camelKey );
       
  3813 				if ( data !== undefined ) {
       
  3814 					return data;
       
  3815 				}
       
  3816 
       
  3817 				// Attempt to "discover" the data in
       
  3818 				// HTML5 custom data-* attrs
       
  3819 				data = dataAttr( elem, camelKey, undefined );
       
  3820 				if ( data !== undefined ) {
       
  3821 					return data;
       
  3822 				}
       
  3823 
       
  3824 				// We tried really hard, but the data doesn't exist.
       
  3825 				return;
       
  3826 			}
       
  3827 
       
  3828 			// Set the data...
       
  3829 			this.each(function() {
       
  3830 				// First, attempt to store a copy or reference of any
       
  3831 				// data that might've been store with a camelCased key.
       
  3832 				var data = data_user.get( this, camelKey );
       
  3833 
       
  3834 				// For HTML5 data-* attribute interop, we have to
       
  3835 				// store property names with dashes in a camelCase form.
       
  3836 				// This might not apply to all properties...*
       
  3837 				data_user.set( this, camelKey, value );
       
  3838 
       
  3839 				// *... In the case of properties that might _actually_
       
  3840 				// have dashes, we need to also store a copy of that
       
  3841 				// unchanged property.
       
  3842 				if ( key.indexOf("-") !== -1 && data !== undefined ) {
       
  3843 					data_user.set( this, key, value );
       
  3844 				}
       
  3845 			});
       
  3846 		}, null, value, arguments.length > 1, null, true );
       
  3847 	},
       
  3848 
       
  3849 	removeData: function( key ) {
       
  3850 		return this.each(function() {
       
  3851 			data_user.remove( this, key );
       
  3852 		});
       
  3853 	}
       
  3854 });
       
  3855 
       
  3856 
       
  3857 jQuery.extend({
       
  3858 	queue: function( elem, type, data ) {
       
  3859 		var queue;
       
  3860 
       
  3861 		if ( elem ) {
       
  3862 			type = ( type || "fx" ) + "queue";
       
  3863 			queue = data_priv.get( elem, type );
       
  3864 
       
  3865 			// Speed up dequeue by getting out quickly if this is just a lookup
       
  3866 			if ( data ) {
       
  3867 				if ( !queue || jQuery.isArray( data ) ) {
       
  3868 					queue = data_priv.access( elem, type, jQuery.makeArray(data) );
       
  3869 				} else {
       
  3870 					queue.push( data );
       
  3871 				}
       
  3872 			}
       
  3873 			return queue || [];
       
  3874 		}
       
  3875 	},
       
  3876 
       
  3877 	dequeue: function( elem, type ) {
       
  3878 		type = type || "fx";
       
  3879 
       
  3880 		var queue = jQuery.queue( elem, type ),
       
  3881 			startLength = queue.length,
       
  3882 			fn = queue.shift(),
       
  3883 			hooks = jQuery._queueHooks( elem, type ),
       
  3884 			next = function() {
       
  3885 				jQuery.dequeue( elem, type );
       
  3886 			};
       
  3887 
       
  3888 		// If the fx queue is dequeued, always remove the progress sentinel
       
  3889 		if ( fn === "inprogress" ) {
       
  3890 			fn = queue.shift();
       
  3891 			startLength--;
       
  3892 		}
       
  3893 
       
  3894 		if ( fn ) {
       
  3895 
       
  3896 			// Add a progress sentinel to prevent the fx queue from being
       
  3897 			// automatically dequeued
       
  3898 			if ( type === "fx" ) {
       
  3899 				queue.unshift( "inprogress" );
       
  3900 			}
       
  3901 
       
  3902 			// clear up the last queue stop function
       
  3903 			delete hooks.stop;
       
  3904 			fn.call( elem, next, hooks );
       
  3905 		}
       
  3906 
       
  3907 		if ( !startLength && hooks ) {
       
  3908 			hooks.empty.fire();
       
  3909 		}
       
  3910 	},
       
  3911 
       
  3912 	// not intended for public consumption - generates a queueHooks object, or returns the current one
       
  3913 	_queueHooks: function( elem, type ) {
       
  3914 		var key = type + "queueHooks";
       
  3915 		return data_priv.get( elem, key ) || data_priv.access( elem, key, {
       
  3916 			empty: jQuery.Callbacks("once memory").add(function() {
       
  3917 				data_priv.remove( elem, [ type + "queue", key ] );
       
  3918 			})
       
  3919 		});
       
  3920 	}
       
  3921 });
       
  3922 
       
  3923 jQuery.fn.extend({
       
  3924 	queue: function( type, data ) {
       
  3925 		var setter = 2;
       
  3926 
       
  3927 		if ( typeof type !== "string" ) {
       
  3928 			data = type;
       
  3929 			type = "fx";
       
  3930 			setter--;
       
  3931 		}
       
  3932 
       
  3933 		if ( arguments.length < setter ) {
       
  3934 			return jQuery.queue( this[0], type );
       
  3935 		}
       
  3936 
       
  3937 		return data === undefined ?
       
  3938 			this :
       
  3939 			this.each(function() {
       
  3940 				var queue = jQuery.queue( this, type, data );
       
  3941 
       
  3942 				// ensure a hooks for this queue
       
  3943 				jQuery._queueHooks( this, type );
       
  3944 
       
  3945 				if ( type === "fx" && queue[0] !== "inprogress" ) {
       
  3946 					jQuery.dequeue( this, type );
       
  3947 				}
       
  3948 			});
       
  3949 	},
       
  3950 	dequeue: function( type ) {
       
  3951 		return this.each(function() {
       
  3952 			jQuery.dequeue( this, type );
       
  3953 		});
       
  3954 	},
       
  3955 	clearQueue: function( type ) {
       
  3956 		return this.queue( type || "fx", [] );
       
  3957 	},
       
  3958 	// Get a promise resolved when queues of a certain type
       
  3959 	// are emptied (fx is the type by default)
       
  3960 	promise: function( type, obj ) {
       
  3961 		var tmp,
       
  3962 			count = 1,
       
  3963 			defer = jQuery.Deferred(),
       
  3964 			elements = this,
       
  3965 			i = this.length,
       
  3966 			resolve = function() {
       
  3967 				if ( !( --count ) ) {
       
  3968 					defer.resolveWith( elements, [ elements ] );
       
  3969 				}
       
  3970 			};
       
  3971 
       
  3972 		if ( typeof type !== "string" ) {
       
  3973 			obj = type;
       
  3974 			type = undefined;
       
  3975 		}
       
  3976 		type = type || "fx";
       
  3977 
       
  3978 		while ( i-- ) {
       
  3979 			tmp = data_priv.get( elements[ i ], type + "queueHooks" );
       
  3980 			if ( tmp && tmp.empty ) {
       
  3981 				count++;
       
  3982 				tmp.empty.add( resolve );
       
  3983 			}
       
  3984 		}
       
  3985 		resolve();
       
  3986 		return defer.promise( obj );
       
  3987 	}
       
  3988 });
       
  3989 var pnum = (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source;
       
  3990 
       
  3991 var cssExpand = [ "Top", "Right", "Bottom", "Left" ];
       
  3992 
       
  3993 var isHidden = function( elem, el ) {
       
  3994 		// isHidden might be called from jQuery#filter function;
       
  3995 		// in that case, element will be second argument
       
  3996 		elem = el || elem;
       
  3997 		return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );
       
  3998 	};
       
  3999 
       
  4000 var rcheckableType = (/^(?:checkbox|radio)$/i);
       
  4001 
       
  4002 
       
  4003 
       
  4004 (function() {
       
  4005 	var fragment = document.createDocumentFragment(),
       
  4006 		div = fragment.appendChild( document.createElement( "div" ) ),
       
  4007 		input = document.createElement( "input" );
       
  4008 
       
  4009 	// #11217 - WebKit loses check when the name is after the checked attribute
       
  4010 	// Support: Windows Web Apps (WWA)
       
  4011 	// `name` and `type` need .setAttribute for WWA
       
  4012 	input.setAttribute( "type", "radio" );
       
  4013 	input.setAttribute( "checked", "checked" );
       
  4014 	input.setAttribute( "name", "t" );
       
  4015 
       
  4016 	div.appendChild( input );
       
  4017 
       
  4018 	// Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3
       
  4019 	// old WebKit doesn't clone checked state correctly in fragments
       
  4020 	support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;
       
  4021 
       
  4022 	// Make sure textarea (and checkbox) defaultValue is properly cloned
       
  4023 	// Support: IE9-IE11+
       
  4024 	div.innerHTML = "<textarea>x</textarea>";
       
  4025 	support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;
       
  4026 })();
       
  4027 var strundefined = typeof undefined;
       
  4028 
       
  4029 
       
  4030 
       
  4031 support.focusinBubbles = "onfocusin" in window;
       
  4032 
       
  4033 
       
  4034 var
       
  4035 	rkeyEvent = /^key/,
       
  4036 	rmouseEvent = /^(?:mouse|pointer|contextmenu)|click/,
       
  4037 	rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
       
  4038 	rtypenamespace = /^([^.]*)(?:\.(.+)|)$/;
       
  4039 
       
  4040 function returnTrue() {
       
  4041 	return true;
       
  4042 }
       
  4043 
       
  4044 function returnFalse() {
       
  4045 	return false;
       
  4046 }
       
  4047 
       
  4048 function safeActiveElement() {
       
  4049 	try {
       
  4050 		return document.activeElement;
       
  4051 	} catch ( err ) { }
       
  4052 }
       
  4053 
       
  4054 /*
       
  4055  * Helper functions for managing events -- not part of the public interface.
       
  4056  * Props to Dean Edwards' addEvent library for many of the ideas.
       
  4057  */
       
  4058 jQuery.event = {
       
  4059 
       
  4060 	global: {},
       
  4061 
       
  4062 	add: function( elem, types, handler, data, selector ) {
       
  4063 
       
  4064 		var handleObjIn, eventHandle, tmp,
       
  4065 			events, t, handleObj,
       
  4066 			special, handlers, type, namespaces, origType,
       
  4067 			elemData = data_priv.get( elem );
       
  4068 
       
  4069 		// Don't attach events to noData or text/comment nodes (but allow plain objects)
       
  4070 		if ( !elemData ) {
       
  4071 			return;
       
  4072 		}
       
  4073 
       
  4074 		// Caller can pass in an object of custom data in lieu of the handler
       
  4075 		if ( handler.handler ) {
       
  4076 			handleObjIn = handler;
       
  4077 			handler = handleObjIn.handler;
       
  4078 			selector = handleObjIn.selector;
       
  4079 		}
       
  4080 
       
  4081 		// Make sure that the handler has a unique ID, used to find/remove it later
       
  4082 		if ( !handler.guid ) {
       
  4083 			handler.guid = jQuery.guid++;
       
  4084 		}
       
  4085 
       
  4086 		// Init the element's event structure and main handler, if this is the first
       
  4087 		if ( !(events = elemData.events) ) {
       
  4088 			events = elemData.events = {};
       
  4089 		}
       
  4090 		if ( !(eventHandle = elemData.handle) ) {
       
  4091 			eventHandle = elemData.handle = function( e ) {
       
  4092 				// Discard the second event of a jQuery.event.trigger() and
       
  4093 				// when an event is called after a page has unloaded
       
  4094 				return typeof jQuery !== strundefined && jQuery.event.triggered !== e.type ?
       
  4095 					jQuery.event.dispatch.apply( elem, arguments ) : undefined;
       
  4096 			};
       
  4097 		}
       
  4098 
       
  4099 		// Handle multiple events separated by a space
       
  4100 		types = ( types || "" ).match( rnotwhite ) || [ "" ];
       
  4101 		t = types.length;
       
  4102 		while ( t-- ) {
       
  4103 			tmp = rtypenamespace.exec( types[t] ) || [];
       
  4104 			type = origType = tmp[1];
       
  4105 			namespaces = ( tmp[2] || "" ).split( "." ).sort();
       
  4106 
       
  4107 			// There *must* be a type, no attaching namespace-only handlers
       
  4108 			if ( !type ) {
       
  4109 				continue;
       
  4110 			}
       
  4111 
       
  4112 			// If event changes its type, use the special event handlers for the changed type
       
  4113 			special = jQuery.event.special[ type ] || {};
       
  4114 
       
  4115 			// If selector defined, determine special event api type, otherwise given type
       
  4116 			type = ( selector ? special.delegateType : special.bindType ) || type;
       
  4117 
       
  4118 			// Update special based on newly reset type
       
  4119 			special = jQuery.event.special[ type ] || {};
       
  4120 
       
  4121 			// handleObj is passed to all event handlers
       
  4122 			handleObj = jQuery.extend({
       
  4123 				type: type,
       
  4124 				origType: origType,
       
  4125 				data: data,
       
  4126 				handler: handler,
       
  4127 				guid: handler.guid,
       
  4128 				selector: selector,
       
  4129 				needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
       
  4130 				namespace: namespaces.join(".")
       
  4131 			}, handleObjIn );
       
  4132 
       
  4133 			// Init the event handler queue if we're the first
       
  4134 			if ( !(handlers = events[ type ]) ) {
       
  4135 				handlers = events[ type ] = [];
       
  4136 				handlers.delegateCount = 0;
       
  4137 
       
  4138 				// Only use addEventListener if the special events handler returns false
       
  4139 				if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
       
  4140 					if ( elem.addEventListener ) {
       
  4141 						elem.addEventListener( type, eventHandle, false );
       
  4142 					}
       
  4143 				}
       
  4144 			}
       
  4145 
       
  4146 			if ( special.add ) {
       
  4147 				special.add.call( elem, handleObj );
       
  4148 
       
  4149 				if ( !handleObj.handler.guid ) {
       
  4150 					handleObj.handler.guid = handler.guid;
       
  4151 				}
       
  4152 			}
       
  4153 
       
  4154 			// Add to the element's handler list, delegates in front
       
  4155 			if ( selector ) {
       
  4156 				handlers.splice( handlers.delegateCount++, 0, handleObj );
       
  4157 			} else {
       
  4158 				handlers.push( handleObj );
       
  4159 			}
       
  4160 
       
  4161 			// Keep track of which events have ever been used, for event optimization
       
  4162 			jQuery.event.global[ type ] = true;
       
  4163 		}
       
  4164 
       
  4165 	},
       
  4166 
       
  4167 	// Detach an event or set of events from an element
       
  4168 	remove: function( elem, types, handler, selector, mappedTypes ) {
       
  4169 
       
  4170 		var j, origCount, tmp,
       
  4171 			events, t, handleObj,
       
  4172 			special, handlers, type, namespaces, origType,
       
  4173 			elemData = data_priv.hasData( elem ) && data_priv.get( elem );
       
  4174 
       
  4175 		if ( !elemData || !(events = elemData.events) ) {
       
  4176 			return;
       
  4177 		}
       
  4178 
       
  4179 		// Once for each type.namespace in types; type may be omitted
       
  4180 		types = ( types || "" ).match( rnotwhite ) || [ "" ];
       
  4181 		t = types.length;
       
  4182 		while ( t-- ) {
       
  4183 			tmp = rtypenamespace.exec( types[t] ) || [];
       
  4184 			type = origType = tmp[1];
       
  4185 			namespaces = ( tmp[2] || "" ).split( "." ).sort();
       
  4186 
       
  4187 			// Unbind all events (on this namespace, if provided) for the element
       
  4188 			if ( !type ) {
       
  4189 				for ( type in events ) {
       
  4190 					jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
       
  4191 				}
       
  4192 				continue;
       
  4193 			}
       
  4194 
       
  4195 			special = jQuery.event.special[ type ] || {};
       
  4196 			type = ( selector ? special.delegateType : special.bindType ) || type;
       
  4197 			handlers = events[ type ] || [];
       
  4198 			tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" );
       
  4199 
       
  4200 			// Remove matching events
       
  4201 			origCount = j = handlers.length;
       
  4202 			while ( j-- ) {
       
  4203 				handleObj = handlers[ j ];
       
  4204 
       
  4205 				if ( ( mappedTypes || origType === handleObj.origType ) &&
       
  4206 					( !handler || handler.guid === handleObj.guid ) &&
       
  4207 					( !tmp || tmp.test( handleObj.namespace ) ) &&
       
  4208 					( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
       
  4209 					handlers.splice( j, 1 );
       
  4210 
       
  4211 					if ( handleObj.selector ) {
       
  4212 						handlers.delegateCount--;
       
  4213 					}
       
  4214 					if ( special.remove ) {
       
  4215 						special.remove.call( elem, handleObj );
       
  4216 					}
       
  4217 				}
       
  4218 			}
       
  4219 
       
  4220 			// Remove generic event handler if we removed something and no more handlers exist
       
  4221 			// (avoids potential for endless recursion during removal of special event handlers)
       
  4222 			if ( origCount && !handlers.length ) {
       
  4223 				if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
       
  4224 					jQuery.removeEvent( elem, type, elemData.handle );
       
  4225 				}
       
  4226 
       
  4227 				delete events[ type ];
       
  4228 			}
       
  4229 		}
       
  4230 
       
  4231 		// Remove the expando if it's no longer used
       
  4232 		if ( jQuery.isEmptyObject( events ) ) {
       
  4233 			delete elemData.handle;
       
  4234 			data_priv.remove( elem, "events" );
       
  4235 		}
       
  4236 	},
       
  4237 
       
  4238 	trigger: function( event, data, elem, onlyHandlers ) {
       
  4239 
       
  4240 		var i, cur, tmp, bubbleType, ontype, handle, special,
       
  4241 			eventPath = [ elem || document ],
       
  4242 			type = hasOwn.call( event, "type" ) ? event.type : event,
       
  4243 			namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : [];
       
  4244 
       
  4245 		cur = tmp = elem = elem || document;
       
  4246 
       
  4247 		// Don't do events on text and comment nodes
       
  4248 		if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
       
  4249 			return;
       
  4250 		}
       
  4251 
       
  4252 		// focus/blur morphs to focusin/out; ensure we're not firing them right now
       
  4253 		if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
       
  4254 			return;
       
  4255 		}
       
  4256 
       
  4257 		if ( type.indexOf(".") >= 0 ) {
       
  4258 			// Namespaced trigger; create a regexp to match event type in handle()
       
  4259 			namespaces = type.split(".");
       
  4260 			type = namespaces.shift();
       
  4261 			namespaces.sort();
       
  4262 		}
       
  4263 		ontype = type.indexOf(":") < 0 && "on" + type;
       
  4264 
       
  4265 		// Caller can pass in a jQuery.Event object, Object, or just an event type string
       
  4266 		event = event[ jQuery.expando ] ?
       
  4267 			event :
       
  4268 			new jQuery.Event( type, typeof event === "object" && event );
       
  4269 
       
  4270 		// Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
       
  4271 		event.isTrigger = onlyHandlers ? 2 : 3;
       
  4272 		event.namespace = namespaces.join(".");
       
  4273 		event.namespace_re = event.namespace ?
       
  4274 			new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) :
       
  4275 			null;
       
  4276 
       
  4277 		// Clean up the event in case it is being reused
       
  4278 		event.result = undefined;
       
  4279 		if ( !event.target ) {
       
  4280 			event.target = elem;
       
  4281 		}
       
  4282 
       
  4283 		// Clone any incoming data and prepend the event, creating the handler arg list
       
  4284 		data = data == null ?
       
  4285 			[ event ] :
       
  4286 			jQuery.makeArray( data, [ event ] );
       
  4287 
       
  4288 		// Allow special events to draw outside the lines
       
  4289 		special = jQuery.event.special[ type ] || {};
       
  4290 		if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
       
  4291 			return;
       
  4292 		}
       
  4293 
       
  4294 		// Determine event propagation path in advance, per W3C events spec (#9951)
       
  4295 		// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
       
  4296 		if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
       
  4297 
       
  4298 			bubbleType = special.delegateType || type;
       
  4299 			if ( !rfocusMorph.test( bubbleType + type ) ) {
       
  4300 				cur = cur.parentNode;
       
  4301 			}
       
  4302 			for ( ; cur; cur = cur.parentNode ) {
       
  4303 				eventPath.push( cur );
       
  4304 				tmp = cur;
       
  4305 			}
       
  4306 
       
  4307 			// Only add window if we got to document (e.g., not plain obj or detached DOM)
       
  4308 			if ( tmp === (elem.ownerDocument || document) ) {
       
  4309 				eventPath.push( tmp.defaultView || tmp.parentWindow || window );
       
  4310 			}
       
  4311 		}
       
  4312 
       
  4313 		// Fire handlers on the event path
       
  4314 		i = 0;
       
  4315 		while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {
       
  4316 
       
  4317 			event.type = i > 1 ?
       
  4318 				bubbleType :
       
  4319 				special.bindType || type;
       
  4320 
       
  4321 			// jQuery handler
       
  4322 			handle = ( data_priv.get( cur, "events" ) || {} )[ event.type ] && data_priv.get( cur, "handle" );
       
  4323 			if ( handle ) {
       
  4324 				handle.apply( cur, data );
       
  4325 			}
       
  4326 
       
  4327 			// Native handler
       
  4328 			handle = ontype && cur[ ontype ];
       
  4329 			if ( handle && handle.apply && jQuery.acceptData( cur ) ) {
       
  4330 				event.result = handle.apply( cur, data );
       
  4331 				if ( event.result === false ) {
       
  4332 					event.preventDefault();
       
  4333 				}
       
  4334 			}
       
  4335 		}
       
  4336 		event.type = type;
       
  4337 
       
  4338 		// If nobody prevented the default action, do it now
       
  4339 		if ( !onlyHandlers && !event.isDefaultPrevented() ) {
       
  4340 
       
  4341 			if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) &&
       
  4342 				jQuery.acceptData( elem ) ) {
       
  4343 
       
  4344 				// Call a native DOM method on the target with the same name name as the event.
       
  4345 				// Don't do default actions on window, that's where global variables be (#6170)
       
  4346 				if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) {
       
  4347 
       
  4348 					// Don't re-trigger an onFOO event when we call its FOO() method
       
  4349 					tmp = elem[ ontype ];
       
  4350 
       
  4351 					if ( tmp ) {
       
  4352 						elem[ ontype ] = null;
       
  4353 					}
       
  4354 
       
  4355 					// Prevent re-triggering of the same event, since we already bubbled it above
       
  4356 					jQuery.event.triggered = type;
       
  4357 					elem[ type ]();
       
  4358 					jQuery.event.triggered = undefined;
       
  4359 
       
  4360 					if ( tmp ) {
       
  4361 						elem[ ontype ] = tmp;
       
  4362 					}
       
  4363 				}
       
  4364 			}
       
  4365 		}
       
  4366 
       
  4367 		return event.result;
       
  4368 	},
       
  4369 
       
  4370 	dispatch: function( event ) {
       
  4371 
       
  4372 		// Make a writable jQuery.Event from the native event object
       
  4373 		event = jQuery.event.fix( event );
       
  4374 
       
  4375 		var i, j, ret, matched, handleObj,
       
  4376 			handlerQueue = [],
       
  4377 			args = slice.call( arguments ),
       
  4378 			handlers = ( data_priv.get( this, "events" ) || {} )[ event.type ] || [],
       
  4379 			special = jQuery.event.special[ event.type ] || {};
       
  4380 
       
  4381 		// Use the fix-ed jQuery.Event rather than the (read-only) native event
       
  4382 		args[0] = event;
       
  4383 		event.delegateTarget = this;
       
  4384 
       
  4385 		// Call the preDispatch hook for the mapped type, and let it bail if desired
       
  4386 		if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
       
  4387 			return;
       
  4388 		}
       
  4389 
       
  4390 		// Determine handlers
       
  4391 		handlerQueue = jQuery.event.handlers.call( this, event, handlers );
       
  4392 
       
  4393 		// Run delegates first; they may want to stop propagation beneath us
       
  4394 		i = 0;
       
  4395 		while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {
       
  4396 			event.currentTarget = matched.elem;
       
  4397 
       
  4398 			j = 0;
       
  4399 			while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {
       
  4400 
       
  4401 				// Triggered event must either 1) have no namespace, or
       
  4402 				// 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
       
  4403 				if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {
       
  4404 
       
  4405 					event.handleObj = handleObj;
       
  4406 					event.data = handleObj.data;
       
  4407 
       
  4408 					ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
       
  4409 							.apply( matched.elem, args );
       
  4410 
       
  4411 					if ( ret !== undefined ) {
       
  4412 						if ( (event.result = ret) === false ) {
       
  4413 							event.preventDefault();
       
  4414 							event.stopPropagation();
       
  4415 						}
       
  4416 					}
       
  4417 				}
       
  4418 			}
       
  4419 		}
       
  4420 
       
  4421 		// Call the postDispatch hook for the mapped type
       
  4422 		if ( special.postDispatch ) {
       
  4423 			special.postDispatch.call( this, event );
       
  4424 		}
       
  4425 
       
  4426 		return event.result;
       
  4427 	},
       
  4428 
       
  4429 	handlers: function( event, handlers ) {
       
  4430 		var i, matches, sel, handleObj,
       
  4431 			handlerQueue = [],
       
  4432 			delegateCount = handlers.delegateCount,
       
  4433 			cur = event.target;
       
  4434 
       
  4435 		// Find delegate handlers
       
  4436 		// Black-hole SVG <use> instance trees (#13180)
       
  4437 		// Avoid non-left-click bubbling in Firefox (#3861)
       
  4438 		if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) {
       
  4439 
       
  4440 			for ( ; cur !== this; cur = cur.parentNode || this ) {
       
  4441 
       
  4442 				// Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
       
  4443 				if ( cur.disabled !== true || event.type !== "click" ) {
       
  4444 					matches = [];
       
  4445 					for ( i = 0; i < delegateCount; i++ ) {
       
  4446 						handleObj = handlers[ i ];
       
  4447 
       
  4448 						// Don't conflict with Object.prototype properties (#13203)
       
  4449 						sel = handleObj.selector + " ";
       
  4450 
       
  4451 						if ( matches[ sel ] === undefined ) {
       
  4452 							matches[ sel ] = handleObj.needsContext ?
       
  4453 								jQuery( sel, this ).index( cur ) >= 0 :
       
  4454 								jQuery.find( sel, this, null, [ cur ] ).length;
       
  4455 						}
       
  4456 						if ( matches[ sel ] ) {
       
  4457 							matches.push( handleObj );
       
  4458 						}
       
  4459 					}
       
  4460 					if ( matches.length ) {
       
  4461 						handlerQueue.push({ elem: cur, handlers: matches });
       
  4462 					}
       
  4463 				}
       
  4464 			}
       
  4465 		}
       
  4466 
       
  4467 		// Add the remaining (directly-bound) handlers
       
  4468 		if ( delegateCount < handlers.length ) {
       
  4469 			handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });
       
  4470 		}
       
  4471 
       
  4472 		return handlerQueue;
       
  4473 	},
       
  4474 
       
  4475 	// Includes some event props shared by KeyEvent and MouseEvent
       
  4476 	props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
       
  4477 
       
  4478 	fixHooks: {},
       
  4479 
       
  4480 	keyHooks: {
       
  4481 		props: "char charCode key keyCode".split(" "),
       
  4482 		filter: function( event, original ) {
       
  4483 
       
  4484 			// Add which for key events
       
  4485 			if ( event.which == null ) {
       
  4486 				event.which = original.charCode != null ? original.charCode : original.keyCode;
       
  4487 			}
       
  4488 
       
  4489 			return event;
       
  4490 		}
       
  4491 	},
       
  4492 
       
  4493 	mouseHooks: {
       
  4494 		props: "button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
       
  4495 		filter: function( event, original ) {
       
  4496 			var eventDoc, doc, body,
       
  4497 				button = original.button;
       
  4498 
       
  4499 			// Calculate pageX/Y if missing and clientX/Y available
       
  4500 			if ( event.pageX == null && original.clientX != null ) {
       
  4501 				eventDoc = event.target.ownerDocument || document;
       
  4502 				doc = eventDoc.documentElement;
       
  4503 				body = eventDoc.body;
       
  4504 
       
  4505 				event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
       
  4506 				event.pageY = original.clientY + ( doc && doc.scrollTop  || body && body.scrollTop  || 0 ) - ( doc && doc.clientTop  || body && body.clientTop  || 0 );
       
  4507 			}
       
  4508 
       
  4509 			// Add which for click: 1 === left; 2 === middle; 3 === right
       
  4510 			// Note: button is not normalized, so don't use it
       
  4511 			if ( !event.which && button !== undefined ) {
       
  4512 				event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
       
  4513 			}
       
  4514 
       
  4515 			return event;
       
  4516 		}
       
  4517 	},
       
  4518 
       
  4519 	fix: function( event ) {
       
  4520 		if ( event[ jQuery.expando ] ) {
       
  4521 			return event;
       
  4522 		}
       
  4523 
       
  4524 		// Create a writable copy of the event object and normalize some properties
       
  4525 		var i, prop, copy,
       
  4526 			type = event.type,
       
  4527 			originalEvent = event,
       
  4528 			fixHook = this.fixHooks[ type ];
       
  4529 
       
  4530 		if ( !fixHook ) {
       
  4531 			this.fixHooks[ type ] = fixHook =
       
  4532 				rmouseEvent.test( type ) ? this.mouseHooks :
       
  4533 				rkeyEvent.test( type ) ? this.keyHooks :
       
  4534 				{};
       
  4535 		}
       
  4536 		copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
       
  4537 
       
  4538 		event = new jQuery.Event( originalEvent );
       
  4539 
       
  4540 		i = copy.length;
       
  4541 		while ( i-- ) {
       
  4542 			prop = copy[ i ];
       
  4543 			event[ prop ] = originalEvent[ prop ];
       
  4544 		}
       
  4545 
       
  4546 		// Support: Cordova 2.5 (WebKit) (#13255)
       
  4547 		// All events should have a target; Cordova deviceready doesn't
       
  4548 		if ( !event.target ) {
       
  4549 			event.target = document;
       
  4550 		}
       
  4551 
       
  4552 		// Support: Safari 6.0+, Chrome < 28
       
  4553 		// Target should not be a text node (#504, #13143)
       
  4554 		if ( event.target.nodeType === 3 ) {
       
  4555 			event.target = event.target.parentNode;
       
  4556 		}
       
  4557 
       
  4558 		return fixHook.filter ? fixHook.filter( event, originalEvent ) : event;
       
  4559 	},
       
  4560 
       
  4561 	special: {
       
  4562 		load: {
       
  4563 			// Prevent triggered image.load events from bubbling to window.load
       
  4564 			noBubble: true
       
  4565 		},
       
  4566 		focus: {
       
  4567 			// Fire native event if possible so blur/focus sequence is correct
       
  4568 			trigger: function() {
       
  4569 				if ( this !== safeActiveElement() && this.focus ) {
       
  4570 					this.focus();
       
  4571 					return false;
       
  4572 				}
       
  4573 			},
       
  4574 			delegateType: "focusin"
       
  4575 		},
       
  4576 		blur: {
       
  4577 			trigger: function() {
       
  4578 				if ( this === safeActiveElement() && this.blur ) {
       
  4579 					this.blur();
       
  4580 					return false;
       
  4581 				}
       
  4582 			},
       
  4583 			delegateType: "focusout"
       
  4584 		},
       
  4585 		click: {
       
  4586 			// For checkbox, fire native event so checked state will be right
       
  4587 			trigger: function() {
       
  4588 				if ( this.type === "checkbox" && this.click && jQuery.nodeName( this, "input" ) ) {
       
  4589 					this.click();
       
  4590 					return false;
       
  4591 				}
       
  4592 			},
       
  4593 
       
  4594 			// For cross-browser consistency, don't fire native .click() on links
       
  4595 			_default: function( event ) {
       
  4596 				return jQuery.nodeName( event.target, "a" );
       
  4597 			}
       
  4598 		},
       
  4599 
       
  4600 		beforeunload: {
       
  4601 			postDispatch: function( event ) {
       
  4602 
       
  4603 				// Support: Firefox 20+
       
  4604 				// Firefox doesn't alert if the returnValue field is not set.
       
  4605 				if ( event.result !== undefined && event.originalEvent ) {
       
  4606 					event.originalEvent.returnValue = event.result;
       
  4607 				}
       
  4608 			}
       
  4609 		}
       
  4610 	},
       
  4611 
       
  4612 	simulate: function( type, elem, event, bubble ) {
       
  4613 		// Piggyback on a donor event to simulate a different one.
       
  4614 		// Fake originalEvent to avoid donor's stopPropagation, but if the
       
  4615 		// simulated event prevents default then we do the same on the donor.
       
  4616 		var e = jQuery.extend(
       
  4617 			new jQuery.Event(),
       
  4618 			event,
       
  4619 			{
       
  4620 				type: type,
       
  4621 				isSimulated: true,
       
  4622 				originalEvent: {}
       
  4623 			}
       
  4624 		);
       
  4625 		if ( bubble ) {
       
  4626 			jQuery.event.trigger( e, null, elem );
       
  4627 		} else {
       
  4628 			jQuery.event.dispatch.call( elem, e );
       
  4629 		}
       
  4630 		if ( e.isDefaultPrevented() ) {
       
  4631 			event.preventDefault();
       
  4632 		}
       
  4633 	}
       
  4634 };
       
  4635 
       
  4636 jQuery.removeEvent = function( elem, type, handle ) {
       
  4637 	if ( elem.removeEventListener ) {
       
  4638 		elem.removeEventListener( type, handle, false );
       
  4639 	}
       
  4640 };
       
  4641 
       
  4642 jQuery.Event = function( src, props ) {
       
  4643 	// Allow instantiation without the 'new' keyword
       
  4644 	if ( !(this instanceof jQuery.Event) ) {
       
  4645 		return new jQuery.Event( src, props );
       
  4646 	}
       
  4647 
       
  4648 	// Event object
       
  4649 	if ( src && src.type ) {
       
  4650 		this.originalEvent = src;
       
  4651 		this.type = src.type;
       
  4652 
       
  4653 		// Events bubbling up the document may have been marked as prevented
       
  4654 		// by a handler lower down the tree; reflect the correct value.
       
  4655 		this.isDefaultPrevented = src.defaultPrevented ||
       
  4656 				src.defaultPrevented === undefined &&
       
  4657 				// Support: Android < 4.0
       
  4658 				src.returnValue === false ?
       
  4659 			returnTrue :
       
  4660 			returnFalse;
       
  4661 
       
  4662 	// Event type
       
  4663 	} else {
       
  4664 		this.type = src;
       
  4665 	}
       
  4666 
       
  4667 	// Put explicitly provided properties onto the event object
       
  4668 	if ( props ) {
       
  4669 		jQuery.extend( this, props );
       
  4670 	}
       
  4671 
       
  4672 	// Create a timestamp if incoming event doesn't have one
       
  4673 	this.timeStamp = src && src.timeStamp || jQuery.now();
       
  4674 
       
  4675 	// Mark it as fixed
       
  4676 	this[ jQuery.expando ] = true;
       
  4677 };
       
  4678 
       
  4679 // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
       
  4680 // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
       
  4681 jQuery.Event.prototype = {
       
  4682 	isDefaultPrevented: returnFalse,
       
  4683 	isPropagationStopped: returnFalse,
       
  4684 	isImmediatePropagationStopped: returnFalse,
       
  4685 
       
  4686 	preventDefault: function() {
       
  4687 		var e = this.originalEvent;
       
  4688 
       
  4689 		this.isDefaultPrevented = returnTrue;
       
  4690 
       
  4691 		if ( e && e.preventDefault ) {
       
  4692 			e.preventDefault();
       
  4693 		}
       
  4694 	},
       
  4695 	stopPropagation: function() {
       
  4696 		var e = this.originalEvent;
       
  4697 
       
  4698 		this.isPropagationStopped = returnTrue;
       
  4699 
       
  4700 		if ( e && e.stopPropagation ) {
       
  4701 			e.stopPropagation();
       
  4702 		}
       
  4703 	},
       
  4704 	stopImmediatePropagation: function() {
       
  4705 		var e = this.originalEvent;
       
  4706 
       
  4707 		this.isImmediatePropagationStopped = returnTrue;
       
  4708 
       
  4709 		if ( e && e.stopImmediatePropagation ) {
       
  4710 			e.stopImmediatePropagation();
       
  4711 		}
       
  4712 
       
  4713 		this.stopPropagation();
       
  4714 	}
       
  4715 };
       
  4716 
       
  4717 // Create mouseenter/leave events using mouseover/out and event-time checks
       
  4718 // Support: Chrome 15+
       
  4719 jQuery.each({
       
  4720 	mouseenter: "mouseover",
       
  4721 	mouseleave: "mouseout",
       
  4722 	pointerenter: "pointerover",
       
  4723 	pointerleave: "pointerout"
       
  4724 }, function( orig, fix ) {
       
  4725 	jQuery.event.special[ orig ] = {
       
  4726 		delegateType: fix,
       
  4727 		bindType: fix,
       
  4728 
       
  4729 		handle: function( event ) {
       
  4730 			var ret,
       
  4731 				target = this,
       
  4732 				related = event.relatedTarget,
       
  4733 				handleObj = event.handleObj;
       
  4734 
       
  4735 			// For mousenter/leave call the handler if related is outside the target.
       
  4736 			// NB: No relatedTarget if the mouse left/entered the browser window
       
  4737 			if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
       
  4738 				event.type = handleObj.origType;
       
  4739 				ret = handleObj.handler.apply( this, arguments );
       
  4740 				event.type = fix;
       
  4741 			}
       
  4742 			return ret;
       
  4743 		}
       
  4744 	};
       
  4745 });
       
  4746 
       
  4747 // Create "bubbling" focus and blur events
       
  4748 // Support: Firefox, Chrome, Safari
       
  4749 if ( !support.focusinBubbles ) {
       
  4750 	jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
       
  4751 
       
  4752 		// Attach a single capturing handler on the document while someone wants focusin/focusout
       
  4753 		var handler = function( event ) {
       
  4754 				jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
       
  4755 			};
       
  4756 
       
  4757 		jQuery.event.special[ fix ] = {
       
  4758 			setup: function() {
       
  4759 				var doc = this.ownerDocument || this,
       
  4760 					attaches = data_priv.access( doc, fix );
       
  4761 
       
  4762 				if ( !attaches ) {
       
  4763 					doc.addEventListener( orig, handler, true );
       
  4764 				}
       
  4765 				data_priv.access( doc, fix, ( attaches || 0 ) + 1 );
       
  4766 			},
       
  4767 			teardown: function() {
       
  4768 				var doc = this.ownerDocument || this,
       
  4769 					attaches = data_priv.access( doc, fix ) - 1;
       
  4770 
       
  4771 				if ( !attaches ) {
       
  4772 					doc.removeEventListener( orig, handler, true );
       
  4773 					data_priv.remove( doc, fix );
       
  4774 
       
  4775 				} else {
       
  4776 					data_priv.access( doc, fix, attaches );
       
  4777 				}
       
  4778 			}
       
  4779 		};
       
  4780 	});
       
  4781 }
       
  4782 
       
  4783 jQuery.fn.extend({
       
  4784 
       
  4785 	on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
       
  4786 		var origFn, type;
       
  4787 
       
  4788 		// Types can be a map of types/handlers
       
  4789 		if ( typeof types === "object" ) {
       
  4790 			// ( types-Object, selector, data )
       
  4791 			if ( typeof selector !== "string" ) {
       
  4792 				// ( types-Object, data )
       
  4793 				data = data || selector;
       
  4794 				selector = undefined;
       
  4795 			}
       
  4796 			for ( type in types ) {
       
  4797 				this.on( type, selector, data, types[ type ], one );
       
  4798 			}
       
  4799 			return this;
       
  4800 		}
       
  4801 
       
  4802 		if ( data == null && fn == null ) {
       
  4803 			// ( types, fn )
       
  4804 			fn = selector;
       
  4805 			data = selector = undefined;
       
  4806 		} else if ( fn == null ) {
       
  4807 			if ( typeof selector === "string" ) {
       
  4808 				// ( types, selector, fn )
       
  4809 				fn = data;
       
  4810 				data = undefined;
       
  4811 			} else {
       
  4812 				// ( types, data, fn )
       
  4813 				fn = data;
       
  4814 				data = selector;
       
  4815 				selector = undefined;
       
  4816 			}
       
  4817 		}
       
  4818 		if ( fn === false ) {
       
  4819 			fn = returnFalse;
       
  4820 		} else if ( !fn ) {
       
  4821 			return this;
       
  4822 		}
       
  4823 
       
  4824 		if ( one === 1 ) {
       
  4825 			origFn = fn;
       
  4826 			fn = function( event ) {
       
  4827 				// Can use an empty set, since event contains the info
       
  4828 				jQuery().off( event );
       
  4829 				return origFn.apply( this, arguments );
       
  4830 			};
       
  4831 			// Use same guid so caller can remove using origFn
       
  4832 			fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
       
  4833 		}
       
  4834 		return this.each( function() {
       
  4835 			jQuery.event.add( this, types, fn, data, selector );
       
  4836 		});
       
  4837 	},
       
  4838 	one: function( types, selector, data, fn ) {
       
  4839 		return this.on( types, selector, data, fn, 1 );
       
  4840 	},
       
  4841 	off: function( types, selector, fn ) {
       
  4842 		var handleObj, type;
       
  4843 		if ( types && types.preventDefault && types.handleObj ) {
       
  4844 			// ( event )  dispatched jQuery.Event
       
  4845 			handleObj = types.handleObj;
       
  4846 			jQuery( types.delegateTarget ).off(
       
  4847 				handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
       
  4848 				handleObj.selector,
       
  4849 				handleObj.handler
       
  4850 			);
       
  4851 			return this;
       
  4852 		}
       
  4853 		if ( typeof types === "object" ) {
       
  4854 			// ( types-object [, selector] )
       
  4855 			for ( type in types ) {
       
  4856 				this.off( type, selector, types[ type ] );
       
  4857 			}
       
  4858 			return this;
       
  4859 		}
       
  4860 		if ( selector === false || typeof selector === "function" ) {
       
  4861 			// ( types [, fn] )
       
  4862 			fn = selector;
       
  4863 			selector = undefined;
       
  4864 		}
       
  4865 		if ( fn === false ) {
       
  4866 			fn = returnFalse;
       
  4867 		}
       
  4868 		return this.each(function() {
       
  4869 			jQuery.event.remove( this, types, fn, selector );
       
  4870 		});
       
  4871 	},
       
  4872 
       
  4873 	trigger: function( type, data ) {
       
  4874 		return this.each(function() {
       
  4875 			jQuery.event.trigger( type, data, this );
       
  4876 		});
       
  4877 	},
       
  4878 	triggerHandler: function( type, data ) {
       
  4879 		var elem = this[0];
       
  4880 		if ( elem ) {
       
  4881 			return jQuery.event.trigger( type, data, elem, true );
       
  4882 		}
       
  4883 	}
       
  4884 });
       
  4885 
       
  4886 
       
  4887 var
       
  4888 	rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
       
  4889 	rtagName = /<([\w:]+)/,
       
  4890 	rhtml = /<|&#?\w+;/,
       
  4891 	rnoInnerhtml = /<(?:script|style|link)/i,
       
  4892 	// checked="checked" or checked
       
  4893 	rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
       
  4894 	rscriptType = /^$|\/(?:java|ecma)script/i,
       
  4895 	rscriptTypeMasked = /^true\/(.*)/,
       
  4896 	rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,
       
  4897 
       
  4898 	// We have to close these tags to support XHTML (#13200)
       
  4899 	wrapMap = {
       
  4900 
       
  4901 		// Support: IE 9
       
  4902 		option: [ 1, "<select multiple='multiple'>", "</select>" ],
       
  4903 
       
  4904 		thead: [ 1, "<table>", "</table>" ],
       
  4905 		col: [ 2, "<table><colgroup>", "</colgroup></table>" ],
       
  4906 		tr: [ 2, "<table><tbody>", "</tbody></table>" ],
       
  4907 		td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
       
  4908 
       
  4909 		_default: [ 0, "", "" ]
       
  4910 	};
       
  4911 
       
  4912 // Support: IE 9
       
  4913 wrapMap.optgroup = wrapMap.option;
       
  4914 
       
  4915 wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
       
  4916 wrapMap.th = wrapMap.td;
       
  4917 
       
  4918 // Support: 1.x compatibility
       
  4919 // Manipulating tables requires a tbody
       
  4920 function manipulationTarget( elem, content ) {
       
  4921 	return jQuery.nodeName( elem, "table" ) &&
       
  4922 		jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ?
       
  4923 
       
  4924 		elem.getElementsByTagName("tbody")[0] ||
       
  4925 			elem.appendChild( elem.ownerDocument.createElement("tbody") ) :
       
  4926 		elem;
       
  4927 }
       
  4928 
       
  4929 // Replace/restore the type attribute of script elements for safe DOM manipulation
       
  4930 function disableScript( elem ) {
       
  4931 	elem.type = (elem.getAttribute("type") !== null) + "/" + elem.type;
       
  4932 	return elem;
       
  4933 }
       
  4934 function restoreScript( elem ) {
       
  4935 	var match = rscriptTypeMasked.exec( elem.type );
       
  4936 
       
  4937 	if ( match ) {
       
  4938 		elem.type = match[ 1 ];
       
  4939 	} else {
       
  4940 		elem.removeAttribute("type");
       
  4941 	}
       
  4942 
       
  4943 	return elem;
       
  4944 }
       
  4945 
       
  4946 // Mark scripts as having already been evaluated
       
  4947 function setGlobalEval( elems, refElements ) {
       
  4948 	var i = 0,
       
  4949 		l = elems.length;
       
  4950 
       
  4951 	for ( ; i < l; i++ ) {
       
  4952 		data_priv.set(
       
  4953 			elems[ i ], "globalEval", !refElements || data_priv.get( refElements[ i ], "globalEval" )
       
  4954 		);
       
  4955 	}
       
  4956 }
       
  4957 
       
  4958 function cloneCopyEvent( src, dest ) {
       
  4959 	var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;
       
  4960 
       
  4961 	if ( dest.nodeType !== 1 ) {
       
  4962 		return;
       
  4963 	}
       
  4964 
       
  4965 	// 1. Copy private data: events, handlers, etc.
       
  4966 	if ( data_priv.hasData( src ) ) {
       
  4967 		pdataOld = data_priv.access( src );
       
  4968 		pdataCur = data_priv.set( dest, pdataOld );
       
  4969 		events = pdataOld.events;
       
  4970 
       
  4971 		if ( events ) {
       
  4972 			delete pdataCur.handle;
       
  4973 			pdataCur.events = {};
       
  4974 
       
  4975 			for ( type in events ) {
       
  4976 				for ( i = 0, l = events[ type ].length; i < l; i++ ) {
       
  4977 					jQuery.event.add( dest, type, events[ type ][ i ] );
       
  4978 				}
       
  4979 			}
       
  4980 		}
       
  4981 	}
       
  4982 
       
  4983 	// 2. Copy user data
       
  4984 	if ( data_user.hasData( src ) ) {
       
  4985 		udataOld = data_user.access( src );
       
  4986 		udataCur = jQuery.extend( {}, udataOld );
       
  4987 
       
  4988 		data_user.set( dest, udataCur );
       
  4989 	}
       
  4990 }
       
  4991 
       
  4992 function getAll( context, tag ) {
       
  4993 	var ret = context.getElementsByTagName ? context.getElementsByTagName( tag || "*" ) :
       
  4994 			context.querySelectorAll ? context.querySelectorAll( tag || "*" ) :
       
  4995 			[];
       
  4996 
       
  4997 	return tag === undefined || tag && jQuery.nodeName( context, tag ) ?
       
  4998 		jQuery.merge( [ context ], ret ) :
       
  4999 		ret;
       
  5000 }
       
  5001 
       
  5002 // Support: IE >= 9
       
  5003 function fixInput( src, dest ) {
       
  5004 	var nodeName = dest.nodeName.toLowerCase();
       
  5005 
       
  5006 	// Fails to persist the checked state of a cloned checkbox or radio button.
       
  5007 	if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
       
  5008 		dest.checked = src.checked;
       
  5009 
       
  5010 	// Fails to return the selected option to the default selected state when cloning options
       
  5011 	} else if ( nodeName === "input" || nodeName === "textarea" ) {
       
  5012 		dest.defaultValue = src.defaultValue;
       
  5013 	}
       
  5014 }
       
  5015 
       
  5016 jQuery.extend({
       
  5017 	clone: function( elem, dataAndEvents, deepDataAndEvents ) {
       
  5018 		var i, l, srcElements, destElements,
       
  5019 			clone = elem.cloneNode( true ),
       
  5020 			inPage = jQuery.contains( elem.ownerDocument, elem );
       
  5021 
       
  5022 		// Support: IE >= 9
       
  5023 		// Fix Cloning issues
       
  5024 		if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&
       
  5025 				!jQuery.isXMLDoc( elem ) ) {
       
  5026 
       
  5027 			// We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2
       
  5028 			destElements = getAll( clone );
       
  5029 			srcElements = getAll( elem );
       
  5030 
       
  5031 			for ( i = 0, l = srcElements.length; i < l; i++ ) {
       
  5032 				fixInput( srcElements[ i ], destElements[ i ] );
       
  5033 			}
       
  5034 		}
       
  5035 
       
  5036 		// Copy the events from the original to the clone
       
  5037 		if ( dataAndEvents ) {
       
  5038 			if ( deepDataAndEvents ) {
       
  5039 				srcElements = srcElements || getAll( elem );
       
  5040 				destElements = destElements || getAll( clone );
       
  5041 
       
  5042 				for ( i = 0, l = srcElements.length; i < l; i++ ) {
       
  5043 					cloneCopyEvent( srcElements[ i ], destElements[ i ] );
       
  5044 				}
       
  5045 			} else {
       
  5046 				cloneCopyEvent( elem, clone );
       
  5047 			}
       
  5048 		}
       
  5049 
       
  5050 		// Preserve script evaluation history
       
  5051 		destElements = getAll( clone, "script" );
       
  5052 		if ( destElements.length > 0 ) {
       
  5053 			setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
       
  5054 		}
       
  5055 
       
  5056 		// Return the cloned set
       
  5057 		return clone;
       
  5058 	},
       
  5059 
       
  5060 	buildFragment: function( elems, context, scripts, selection ) {
       
  5061 		var elem, tmp, tag, wrap, contains, j,
       
  5062 			fragment = context.createDocumentFragment(),
       
  5063 			nodes = [],
       
  5064 			i = 0,
       
  5065 			l = elems.length;
       
  5066 
       
  5067 		for ( ; i < l; i++ ) {
       
  5068 			elem = elems[ i ];
       
  5069 
       
  5070 			if ( elem || elem === 0 ) {
       
  5071 
       
  5072 				// Add nodes directly
       
  5073 				if ( jQuery.type( elem ) === "object" ) {
       
  5074 					// Support: QtWebKit
       
  5075 					// jQuery.merge because push.apply(_, arraylike) throws
       
  5076 					jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
       
  5077 
       
  5078 				// Convert non-html into a text node
       
  5079 				} else if ( !rhtml.test( elem ) ) {
       
  5080 					nodes.push( context.createTextNode( elem ) );
       
  5081 
       
  5082 				// Convert html into DOM nodes
       
  5083 				} else {
       
  5084 					tmp = tmp || fragment.appendChild( context.createElement("div") );
       
  5085 
       
  5086 					// Deserialize a standard representation
       
  5087 					tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase();
       
  5088 					wrap = wrapMap[ tag ] || wrapMap._default;
       
  5089 					tmp.innerHTML = wrap[ 1 ] + elem.replace( rxhtmlTag, "<$1></$2>" ) + wrap[ 2 ];
       
  5090 
       
  5091 					// Descend through wrappers to the right content
       
  5092 					j = wrap[ 0 ];
       
  5093 					while ( j-- ) {
       
  5094 						tmp = tmp.lastChild;
       
  5095 					}
       
  5096 
       
  5097 					// Support: QtWebKit
       
  5098 					// jQuery.merge because push.apply(_, arraylike) throws
       
  5099 					jQuery.merge( nodes, tmp.childNodes );
       
  5100 
       
  5101 					// Remember the top-level container
       
  5102 					tmp = fragment.firstChild;
       
  5103 
       
  5104 					// Fixes #12346
       
  5105 					// Support: Webkit, IE
       
  5106 					tmp.textContent = "";
       
  5107 				}
       
  5108 			}
       
  5109 		}
       
  5110 
       
  5111 		// Remove wrapper from fragment
       
  5112 		fragment.textContent = "";
       
  5113 
       
  5114 		i = 0;
       
  5115 		while ( (elem = nodes[ i++ ]) ) {
       
  5116 
       
  5117 			// #4087 - If origin and destination elements are the same, and this is
       
  5118 			// that element, do not do anything
       
  5119 			if ( selection && jQuery.inArray( elem, selection ) !== -1 ) {
       
  5120 				continue;
       
  5121 			}
       
  5122 
       
  5123 			contains = jQuery.contains( elem.ownerDocument, elem );
       
  5124 
       
  5125 			// Append to fragment
       
  5126 			tmp = getAll( fragment.appendChild( elem ), "script" );
       
  5127 
       
  5128 			// Preserve script evaluation history
       
  5129 			if ( contains ) {
       
  5130 				setGlobalEval( tmp );
       
  5131 			}
       
  5132 
       
  5133 			// Capture executables
       
  5134 			if ( scripts ) {
       
  5135 				j = 0;
       
  5136 				while ( (elem = tmp[ j++ ]) ) {
       
  5137 					if ( rscriptType.test( elem.type || "" ) ) {
       
  5138 						scripts.push( elem );
       
  5139 					}
       
  5140 				}
       
  5141 			}
       
  5142 		}
       
  5143 
       
  5144 		return fragment;
       
  5145 	},
       
  5146 
       
  5147 	cleanData: function( elems ) {
       
  5148 		var data, elem, type, key,
       
  5149 			special = jQuery.event.special,
       
  5150 			i = 0;
       
  5151 
       
  5152 		for ( ; (elem = elems[ i ]) !== undefined; i++ ) {
       
  5153 			if ( jQuery.acceptData( elem ) ) {
       
  5154 				key = elem[ data_priv.expando ];
       
  5155 
       
  5156 				if ( key && (data = data_priv.cache[ key ]) ) {
       
  5157 					if ( data.events ) {
       
  5158 						for ( type in data.events ) {
       
  5159 							if ( special[ type ] ) {
       
  5160 								jQuery.event.remove( elem, type );
       
  5161 
       
  5162 							// This is a shortcut to avoid jQuery.event.remove's overhead
       
  5163 							} else {
       
  5164 								jQuery.removeEvent( elem, type, data.handle );
       
  5165 							}
       
  5166 						}
       
  5167 					}
       
  5168 					if ( data_priv.cache[ key ] ) {
       
  5169 						// Discard any remaining `private` data
       
  5170 						delete data_priv.cache[ key ];
       
  5171 					}
       
  5172 				}
       
  5173 			}
       
  5174 			// Discard any remaining `user` data
       
  5175 			delete data_user.cache[ elem[ data_user.expando ] ];
       
  5176 		}
       
  5177 	}
       
  5178 });
       
  5179 
       
  5180 jQuery.fn.extend({
       
  5181 	text: function( value ) {
       
  5182 		return access( this, function( value ) {
       
  5183 			return value === undefined ?
       
  5184 				jQuery.text( this ) :
       
  5185 				this.empty().each(function() {
       
  5186 					if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
       
  5187 						this.textContent = value;
       
  5188 					}
       
  5189 				});
       
  5190 		}, null, value, arguments.length );
       
  5191 	},
       
  5192 
       
  5193 	append: function() {
       
  5194 		return this.domManip( arguments, function( elem ) {
       
  5195 			if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
       
  5196 				var target = manipulationTarget( this, elem );
       
  5197 				target.appendChild( elem );
       
  5198 			}
       
  5199 		});
       
  5200 	},
       
  5201 
       
  5202 	prepend: function() {
       
  5203 		return this.domManip( arguments, function( elem ) {
       
  5204 			if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
       
  5205 				var target = manipulationTarget( this, elem );
       
  5206 				target.insertBefore( elem, target.firstChild );
       
  5207 			}
       
  5208 		});
       
  5209 	},
       
  5210 
       
  5211 	before: function() {
       
  5212 		return this.domManip( arguments, function( elem ) {
       
  5213 			if ( this.parentNode ) {
       
  5214 				this.parentNode.insertBefore( elem, this );
       
  5215 			}
       
  5216 		});
       
  5217 	},
       
  5218 
       
  5219 	after: function() {
       
  5220 		return this.domManip( arguments, function( elem ) {
       
  5221 			if ( this.parentNode ) {
       
  5222 				this.parentNode.insertBefore( elem, this.nextSibling );
       
  5223 			}
       
  5224 		});
       
  5225 	},
       
  5226 
       
  5227 	remove: function( selector, keepData /* Internal Use Only */ ) {
       
  5228 		var elem,
       
  5229 			elems = selector ? jQuery.filter( selector, this ) : this,
       
  5230 			i = 0;
       
  5231 
       
  5232 		for ( ; (elem = elems[i]) != null; i++ ) {
       
  5233 			if ( !keepData && elem.nodeType === 1 ) {
       
  5234 				jQuery.cleanData( getAll( elem ) );
       
  5235 			}
       
  5236 
       
  5237 			if ( elem.parentNode ) {
       
  5238 				if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) {
       
  5239 					setGlobalEval( getAll( elem, "script" ) );
       
  5240 				}
       
  5241 				elem.parentNode.removeChild( elem );
       
  5242 			}
       
  5243 		}
       
  5244 
       
  5245 		return this;
       
  5246 	},
       
  5247 
       
  5248 	empty: function() {
       
  5249 		var elem,
       
  5250 			i = 0;
       
  5251 
       
  5252 		for ( ; (elem = this[i]) != null; i++ ) {
       
  5253 			if ( elem.nodeType === 1 ) {
       
  5254 
       
  5255 				// Prevent memory leaks
       
  5256 				jQuery.cleanData( getAll( elem, false ) );
       
  5257 
       
  5258 				// Remove any remaining nodes
       
  5259 				elem.textContent = "";
       
  5260 			}
       
  5261 		}
       
  5262 
       
  5263 		return this;
       
  5264 	},
       
  5265 
       
  5266 	clone: function( dataAndEvents, deepDataAndEvents ) {
       
  5267 		dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
       
  5268 		deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
       
  5269 
       
  5270 		return this.map(function() {
       
  5271 			return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
       
  5272 		});
       
  5273 	},
       
  5274 
       
  5275 	html: function( value ) {
       
  5276 		return access( this, function( value ) {
       
  5277 			var elem = this[ 0 ] || {},
       
  5278 				i = 0,
       
  5279 				l = this.length;
       
  5280 
       
  5281 			if ( value === undefined && elem.nodeType === 1 ) {
       
  5282 				return elem.innerHTML;
       
  5283 			}
       
  5284 
       
  5285 			// See if we can take a shortcut and just use innerHTML
       
  5286 			if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
       
  5287 				!wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) {
       
  5288 
       
  5289 				value = value.replace( rxhtmlTag, "<$1></$2>" );
       
  5290 
       
  5291 				try {
       
  5292 					for ( ; i < l; i++ ) {
       
  5293 						elem = this[ i ] || {};
       
  5294 
       
  5295 						// Remove element nodes and prevent memory leaks
       
  5296 						if ( elem.nodeType === 1 ) {
       
  5297 							jQuery.cleanData( getAll( elem, false ) );
       
  5298 							elem.innerHTML = value;
       
  5299 						}
       
  5300 					}
       
  5301 
       
  5302 					elem = 0;
       
  5303 
       
  5304 				// If using innerHTML throws an exception, use the fallback method
       
  5305 				} catch( e ) {}
       
  5306 			}
       
  5307 
       
  5308 			if ( elem ) {
       
  5309 				this.empty().append( value );
       
  5310 			}
       
  5311 		}, null, value, arguments.length );
       
  5312 	},
       
  5313 
       
  5314 	replaceWith: function() {
       
  5315 		var arg = arguments[ 0 ];
       
  5316 
       
  5317 		// Make the changes, replacing each context element with the new content
       
  5318 		this.domManip( arguments, function( elem ) {
       
  5319 			arg = this.parentNode;
       
  5320 
       
  5321 			jQuery.cleanData( getAll( this ) );
       
  5322 
       
  5323 			if ( arg ) {
       
  5324 				arg.replaceChild( elem, this );
       
  5325 			}
       
  5326 		});
       
  5327 
       
  5328 		// Force removal if there was no new content (e.g., from empty arguments)
       
  5329 		return arg && (arg.length || arg.nodeType) ? this : this.remove();
       
  5330 	},
       
  5331 
       
  5332 	detach: function( selector ) {
       
  5333 		return this.remove( selector, true );
       
  5334 	},
       
  5335 
       
  5336 	domManip: function( args, callback ) {
       
  5337 
       
  5338 		// Flatten any nested arrays
       
  5339 		args = concat.apply( [], args );
       
  5340 
       
  5341 		var fragment, first, scripts, hasScripts, node, doc,
       
  5342 			i = 0,
       
  5343 			l = this.length,
       
  5344 			set = this,
       
  5345 			iNoClone = l - 1,
       
  5346 			value = args[ 0 ],
       
  5347 			isFunction = jQuery.isFunction( value );
       
  5348 
       
  5349 		// We can't cloneNode fragments that contain checked, in WebKit
       
  5350 		if ( isFunction ||
       
  5351 				( l > 1 && typeof value === "string" &&
       
  5352 					!support.checkClone && rchecked.test( value ) ) ) {
       
  5353 			return this.each(function( index ) {
       
  5354 				var self = set.eq( index );
       
  5355 				if ( isFunction ) {
       
  5356 					args[ 0 ] = value.call( this, index, self.html() );
       
  5357 				}
       
  5358 				self.domManip( args, callback );
       
  5359 			});
       
  5360 		}
       
  5361 
       
  5362 		if ( l ) {
       
  5363 			fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this );
       
  5364 			first = fragment.firstChild;
       
  5365 
       
  5366 			if ( fragment.childNodes.length === 1 ) {
       
  5367 				fragment = first;
       
  5368 			}
       
  5369 
       
  5370 			if ( first ) {
       
  5371 				scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
       
  5372 				hasScripts = scripts.length;
       
  5373 
       
  5374 				// Use the original fragment for the last item instead of the first because it can end up
       
  5375 				// being emptied incorrectly in certain situations (#8070).
       
  5376 				for ( ; i < l; i++ ) {
       
  5377 					node = fragment;
       
  5378 
       
  5379 					if ( i !== iNoClone ) {
       
  5380 						node = jQuery.clone( node, true, true );
       
  5381 
       
  5382 						// Keep references to cloned scripts for later restoration
       
  5383 						if ( hasScripts ) {
       
  5384 							// Support: QtWebKit
       
  5385 							// jQuery.merge because push.apply(_, arraylike) throws
       
  5386 							jQuery.merge( scripts, getAll( node, "script" ) );
       
  5387 						}
       
  5388 					}
       
  5389 
       
  5390 					callback.call( this[ i ], node, i );
       
  5391 				}
       
  5392 
       
  5393 				if ( hasScripts ) {
       
  5394 					doc = scripts[ scripts.length - 1 ].ownerDocument;
       
  5395 
       
  5396 					// Reenable scripts
       
  5397 					jQuery.map( scripts, restoreScript );
       
  5398 
       
  5399 					// Evaluate executable scripts on first document insertion
       
  5400 					for ( i = 0; i < hasScripts; i++ ) {
       
  5401 						node = scripts[ i ];
       
  5402 						if ( rscriptType.test( node.type || "" ) &&
       
  5403 							!data_priv.access( node, "globalEval" ) && jQuery.contains( doc, node ) ) {
       
  5404 
       
  5405 							if ( node.src ) {
       
  5406 								// Optional AJAX dependency, but won't run scripts if not present
       
  5407 								if ( jQuery._evalUrl ) {
       
  5408 									jQuery._evalUrl( node.src );
       
  5409 								}
       
  5410 							} else {
       
  5411 								jQuery.globalEval( node.textContent.replace( rcleanScript, "" ) );
       
  5412 							}
       
  5413 						}
       
  5414 					}
       
  5415 				}
       
  5416 			}
       
  5417 		}
       
  5418 
       
  5419 		return this;
       
  5420 	}
       
  5421 });
       
  5422 
       
  5423 jQuery.each({
       
  5424 	appendTo: "append",
       
  5425 	prependTo: "prepend",
       
  5426 	insertBefore: "before",
       
  5427 	insertAfter: "after",
       
  5428 	replaceAll: "replaceWith"
       
  5429 }, function( name, original ) {
       
  5430 	jQuery.fn[ name ] = function( selector ) {
       
  5431 		var elems,
       
  5432 			ret = [],
       
  5433 			insert = jQuery( selector ),
       
  5434 			last = insert.length - 1,
       
  5435 			i = 0;
       
  5436 
       
  5437 		for ( ; i <= last; i++ ) {
       
  5438 			elems = i === last ? this : this.clone( true );
       
  5439 			jQuery( insert[ i ] )[ original ]( elems );
       
  5440 
       
  5441 			// Support: QtWebKit
       
  5442 			// .get() because push.apply(_, arraylike) throws
       
  5443 			push.apply( ret, elems.get() );
       
  5444 		}
       
  5445 
       
  5446 		return this.pushStack( ret );
       
  5447 	};
       
  5448 });
       
  5449 
       
  5450 
       
  5451 var iframe,
       
  5452 	elemdisplay = {};
       
  5453 
       
  5454 /**
       
  5455  * Retrieve the actual display of a element
       
  5456  * @param {String} name nodeName of the element
       
  5457  * @param {Object} doc Document object
       
  5458  */
       
  5459 // Called only from within defaultDisplay
       
  5460 function actualDisplay( name, doc ) {
       
  5461 	var style,
       
  5462 		elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),
       
  5463 
       
  5464 		// getDefaultComputedStyle might be reliably used only on attached element
       
  5465 		display = window.getDefaultComputedStyle && ( style = window.getDefaultComputedStyle( elem[ 0 ] ) ) ?
       
  5466 
       
  5467 			// Use of this method is a temporary fix (more like optmization) until something better comes along,
       
  5468 			// since it was removed from specification and supported only in FF
       
  5469 			style.display : jQuery.css( elem[ 0 ], "display" );
       
  5470 
       
  5471 	// We don't have any data stored on the element,
       
  5472 	// so use "detach" method as fast way to get rid of the element
       
  5473 	elem.detach();
       
  5474 
       
  5475 	return display;
       
  5476 }
       
  5477 
       
  5478 /**
       
  5479  * Try to determine the default display value of an element
       
  5480  * @param {String} nodeName
       
  5481  */
       
  5482 function defaultDisplay( nodeName ) {
       
  5483 	var doc = document,
       
  5484 		display = elemdisplay[ nodeName ];
       
  5485 
       
  5486 	if ( !display ) {
       
  5487 		display = actualDisplay( nodeName, doc );
       
  5488 
       
  5489 		// If the simple way fails, read from inside an iframe
       
  5490 		if ( display === "none" || !display ) {
       
  5491 
       
  5492 			// Use the already-created iframe if possible
       
  5493 			iframe = (iframe || jQuery( "<iframe frameborder='0' width='0' height='0'/>" )).appendTo( doc.documentElement );
       
  5494 
       
  5495 			// Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse
       
  5496 			doc = iframe[ 0 ].contentDocument;
       
  5497 
       
  5498 			// Support: IE
       
  5499 			doc.write();
       
  5500 			doc.close();
       
  5501 
       
  5502 			display = actualDisplay( nodeName, doc );
       
  5503 			iframe.detach();
       
  5504 		}
       
  5505 
       
  5506 		// Store the correct default display
       
  5507 		elemdisplay[ nodeName ] = display;
       
  5508 	}
       
  5509 
       
  5510 	return display;
       
  5511 }
       
  5512 var rmargin = (/^margin/);
       
  5513 
       
  5514 var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" );
       
  5515 
       
  5516 var getStyles = function( elem ) {
       
  5517 		return elem.ownerDocument.defaultView.getComputedStyle( elem, null );
       
  5518 	};
       
  5519 
       
  5520 
       
  5521 
       
  5522 function curCSS( elem, name, computed ) {
       
  5523 	var width, minWidth, maxWidth, ret,
       
  5524 		style = elem.style;
       
  5525 
       
  5526 	computed = computed || getStyles( elem );
       
  5527 
       
  5528 	// Support: IE9
       
  5529 	// getPropertyValue is only needed for .css('filter') in IE9, see #12537
       
  5530 	if ( computed ) {
       
  5531 		ret = computed.getPropertyValue( name ) || computed[ name ];
       
  5532 	}
       
  5533 
       
  5534 	if ( computed ) {
       
  5535 
       
  5536 		if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
       
  5537 			ret = jQuery.style( elem, name );
       
  5538 		}
       
  5539 
       
  5540 		// Support: iOS < 6
       
  5541 		// A tribute to the "awesome hack by Dean Edwards"
       
  5542 		// iOS < 6 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels
       
  5543 		// this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
       
  5544 		if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
       
  5545 
       
  5546 			// Remember the original values
       
  5547 			width = style.width;
       
  5548 			minWidth = style.minWidth;
       
  5549 			maxWidth = style.maxWidth;
       
  5550 
       
  5551 			// Put in the new values to get a computed value out
       
  5552 			style.minWidth = style.maxWidth = style.width = ret;
       
  5553 			ret = computed.width;
       
  5554 
       
  5555 			// Revert the changed values
       
  5556 			style.width = width;
       
  5557 			style.minWidth = minWidth;
       
  5558 			style.maxWidth = maxWidth;
       
  5559 		}
       
  5560 	}
       
  5561 
       
  5562 	return ret !== undefined ?
       
  5563 		// Support: IE
       
  5564 		// IE returns zIndex value as an integer.
       
  5565 		ret + "" :
       
  5566 		ret;
       
  5567 }
       
  5568 
       
  5569 
       
  5570 function addGetHookIf( conditionFn, hookFn ) {
       
  5571 	// Define the hook, we'll check on the first run if it's really needed.
       
  5572 	return {
       
  5573 		get: function() {
       
  5574 			if ( conditionFn() ) {
       
  5575 				// Hook not needed (or it's not possible to use it due to missing dependency),
       
  5576 				// remove it.
       
  5577 				// Since there are no other hooks for marginRight, remove the whole object.
       
  5578 				delete this.get;
       
  5579 				return;
       
  5580 			}
       
  5581 
       
  5582 			// Hook needed; redefine it so that the support test is not executed again.
       
  5583 
       
  5584 			return (this.get = hookFn).apply( this, arguments );
       
  5585 		}
       
  5586 	};
       
  5587 }
       
  5588 
       
  5589 
       
  5590 (function() {
       
  5591 	var pixelPositionVal, boxSizingReliableVal,
       
  5592 		docElem = document.documentElement,
       
  5593 		container = document.createElement( "div" ),
       
  5594 		div = document.createElement( "div" );
       
  5595 
       
  5596 	if ( !div.style ) {
       
  5597 		return;
       
  5598 	}
       
  5599 
       
  5600 	div.style.backgroundClip = "content-box";
       
  5601 	div.cloneNode( true ).style.backgroundClip = "";
       
  5602 	support.clearCloneStyle = div.style.backgroundClip === "content-box";
       
  5603 
       
  5604 	container.style.cssText = "border:0;width:0;height:0;top:0;left:-9999px;margin-top:1px;" +
       
  5605 		"position:absolute";
       
  5606 	container.appendChild( div );
       
  5607 
       
  5608 	// Executing both pixelPosition & boxSizingReliable tests require only one layout
       
  5609 	// so they're executed at the same time to save the second computation.
       
  5610 	function computePixelPositionAndBoxSizingReliable() {
       
  5611 		div.style.cssText =
       
  5612 			// Support: Firefox<29, Android 2.3
       
  5613 			// Vendor-prefix box-sizing
       
  5614 			"-webkit-box-sizing:border-box;-moz-box-sizing:border-box;" +
       
  5615 			"box-sizing:border-box;display:block;margin-top:1%;top:1%;" +
       
  5616 			"border:1px;padding:1px;width:4px;position:absolute";
       
  5617 		div.innerHTML = "";
       
  5618 		docElem.appendChild( container );
       
  5619 
       
  5620 		var divStyle = window.getComputedStyle( div, null );
       
  5621 		pixelPositionVal = divStyle.top !== "1%";
       
  5622 		boxSizingReliableVal = divStyle.width === "4px";
       
  5623 
       
  5624 		docElem.removeChild( container );
       
  5625 	}
       
  5626 
       
  5627 	// Support: node.js jsdom
       
  5628 	// Don't assume that getComputedStyle is a property of the global object
       
  5629 	if ( window.getComputedStyle ) {
       
  5630 		jQuery.extend( support, {
       
  5631 			pixelPosition: function() {
       
  5632 				// This test is executed only once but we still do memoizing
       
  5633 				// since we can use the boxSizingReliable pre-computing.
       
  5634 				// No need to check if the test was already performed, though.
       
  5635 				computePixelPositionAndBoxSizingReliable();
       
  5636 				return pixelPositionVal;
       
  5637 			},
       
  5638 			boxSizingReliable: function() {
       
  5639 				if ( boxSizingReliableVal == null ) {
       
  5640 					computePixelPositionAndBoxSizingReliable();
       
  5641 				}
       
  5642 				return boxSizingReliableVal;
       
  5643 			},
       
  5644 			reliableMarginRight: function() {
       
  5645 				// Support: Android 2.3
       
  5646 				// Check if div with explicit width and no margin-right incorrectly
       
  5647 				// gets computed margin-right based on width of container. (#3333)
       
  5648 				// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
       
  5649 				// This support function is only executed once so no memoizing is needed.
       
  5650 				var ret,
       
  5651 					marginDiv = div.appendChild( document.createElement( "div" ) );
       
  5652 
       
  5653 				// Reset CSS: box-sizing; display; margin; border; padding
       
  5654 				marginDiv.style.cssText = div.style.cssText =
       
  5655 					// Support: Firefox<29, Android 2.3
       
  5656 					// Vendor-prefix box-sizing
       
  5657 					"-webkit-box-sizing:content-box;-moz-box-sizing:content-box;" +
       
  5658 					"box-sizing:content-box;display:block;margin:0;border:0;padding:0";
       
  5659 				marginDiv.style.marginRight = marginDiv.style.width = "0";
       
  5660 				div.style.width = "1px";
       
  5661 				docElem.appendChild( container );
       
  5662 
       
  5663 				ret = !parseFloat( window.getComputedStyle( marginDiv, null ).marginRight );
       
  5664 
       
  5665 				docElem.removeChild( container );
       
  5666 
       
  5667 				return ret;
       
  5668 			}
       
  5669 		});
       
  5670 	}
       
  5671 })();
       
  5672 
       
  5673 
       
  5674 // A method for quickly swapping in/out CSS properties to get correct calculations.
       
  5675 jQuery.swap = function( elem, options, callback, args ) {
       
  5676 	var ret, name,
       
  5677 		old = {};
       
  5678 
       
  5679 	// Remember the old values, and insert the new ones
       
  5680 	for ( name in options ) {
       
  5681 		old[ name ] = elem.style[ name ];
       
  5682 		elem.style[ name ] = options[ name ];
       
  5683 	}
       
  5684 
       
  5685 	ret = callback.apply( elem, args || [] );
       
  5686 
       
  5687 	// Revert the old values
       
  5688 	for ( name in options ) {
       
  5689 		elem.style[ name ] = old[ name ];
       
  5690 	}
       
  5691 
       
  5692 	return ret;
       
  5693 };
       
  5694 
       
  5695 
       
  5696 var
       
  5697 	// swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
       
  5698 	// see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
       
  5699 	rdisplayswap = /^(none|table(?!-c[ea]).+)/,
       
  5700 	rnumsplit = new RegExp( "^(" + pnum + ")(.*)$", "i" ),
       
  5701 	rrelNum = new RegExp( "^([+-])=(" + pnum + ")", "i" ),
       
  5702 
       
  5703 	cssShow = { position: "absolute", visibility: "hidden", display: "block" },
       
  5704 	cssNormalTransform = {
       
  5705 		letterSpacing: "0",
       
  5706 		fontWeight: "400"
       
  5707 	},
       
  5708 
       
  5709 	cssPrefixes = [ "Webkit", "O", "Moz", "ms" ];
       
  5710 
       
  5711 // return a css property mapped to a potentially vendor prefixed property
       
  5712 function vendorPropName( style, name ) {
       
  5713 
       
  5714 	// shortcut for names that are not vendor prefixed
       
  5715 	if ( name in style ) {
       
  5716 		return name;
       
  5717 	}
       
  5718 
       
  5719 	// check for vendor prefixed names
       
  5720 	var capName = name[0].toUpperCase() + name.slice(1),
       
  5721 		origName = name,
       
  5722 		i = cssPrefixes.length;
       
  5723 
       
  5724 	while ( i-- ) {
       
  5725 		name = cssPrefixes[ i ] + capName;
       
  5726 		if ( name in style ) {
       
  5727 			return name;
       
  5728 		}
       
  5729 	}
       
  5730 
       
  5731 	return origName;
       
  5732 }
       
  5733 
       
  5734 function setPositiveNumber( elem, value, subtract ) {
       
  5735 	var matches = rnumsplit.exec( value );
       
  5736 	return matches ?
       
  5737 		// Guard against undefined "subtract", e.g., when used as in cssHooks
       
  5738 		Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
       
  5739 		value;
       
  5740 }
       
  5741 
       
  5742 function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
       
  5743 	var i = extra === ( isBorderBox ? "border" : "content" ) ?
       
  5744 		// If we already have the right measurement, avoid augmentation
       
  5745 		4 :
       
  5746 		// Otherwise initialize for horizontal or vertical properties
       
  5747 		name === "width" ? 1 : 0,
       
  5748 
       
  5749 		val = 0;
       
  5750 
       
  5751 	for ( ; i < 4; i += 2 ) {
       
  5752 		// both box models exclude margin, so add it if we want it
       
  5753 		if ( extra === "margin" ) {
       
  5754 			val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
       
  5755 		}
       
  5756 
       
  5757 		if ( isBorderBox ) {
       
  5758 			// border-box includes padding, so remove it if we want content
       
  5759 			if ( extra === "content" ) {
       
  5760 				val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
       
  5761 			}
       
  5762 
       
  5763 			// at this point, extra isn't border nor margin, so remove border
       
  5764 			if ( extra !== "margin" ) {
       
  5765 				val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
       
  5766 			}
       
  5767 		} else {
       
  5768 			// at this point, extra isn't content, so add padding
       
  5769 			val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
       
  5770 
       
  5771 			// at this point, extra isn't content nor padding, so add border
       
  5772 			if ( extra !== "padding" ) {
       
  5773 				val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
       
  5774 			}
       
  5775 		}
       
  5776 	}
       
  5777 
       
  5778 	return val;
       
  5779 }
       
  5780 
       
  5781 function getWidthOrHeight( elem, name, extra ) {
       
  5782 
       
  5783 	// Start with offset property, which is equivalent to the border-box value
       
  5784 	var valueIsBorderBox = true,
       
  5785 		val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
       
  5786 		styles = getStyles( elem ),
       
  5787 		isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
       
  5788 
       
  5789 	// some non-html elements return undefined for offsetWidth, so check for null/undefined
       
  5790 	// svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
       
  5791 	// MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
       
  5792 	if ( val <= 0 || val == null ) {
       
  5793 		// Fall back to computed then uncomputed css if necessary
       
  5794 		val = curCSS( elem, name, styles );
       
  5795 		if ( val < 0 || val == null ) {
       
  5796 			val = elem.style[ name ];
       
  5797 		}
       
  5798 
       
  5799 		// Computed unit is not pixels. Stop here and return.
       
  5800 		if ( rnumnonpx.test(val) ) {
       
  5801 			return val;
       
  5802 		}
       
  5803 
       
  5804 		// we need the check for style in case a browser which returns unreliable values
       
  5805 		// for getComputedStyle silently falls back to the reliable elem.style
       
  5806 		valueIsBorderBox = isBorderBox &&
       
  5807 			( support.boxSizingReliable() || val === elem.style[ name ] );
       
  5808 
       
  5809 		// Normalize "", auto, and prepare for extra
       
  5810 		val = parseFloat( val ) || 0;
       
  5811 	}
       
  5812 
       
  5813 	// use the active box-sizing model to add/subtract irrelevant styles
       
  5814 	return ( val +
       
  5815 		augmentWidthOrHeight(
       
  5816 			elem,
       
  5817 			name,
       
  5818 			extra || ( isBorderBox ? "border" : "content" ),
       
  5819 			valueIsBorderBox,
       
  5820 			styles
       
  5821 		)
       
  5822 	) + "px";
       
  5823 }
       
  5824 
       
  5825 function showHide( elements, show ) {
       
  5826 	var display, elem, hidden,
       
  5827 		values = [],
       
  5828 		index = 0,
       
  5829 		length = elements.length;
       
  5830 
       
  5831 	for ( ; index < length; index++ ) {
       
  5832 		elem = elements[ index ];
       
  5833 		if ( !elem.style ) {
       
  5834 			continue;
       
  5835 		}
       
  5836 
       
  5837 		values[ index ] = data_priv.get( elem, "olddisplay" );
       
  5838 		display = elem.style.display;
       
  5839 		if ( show ) {
       
  5840 			// Reset the inline display of this element to learn if it is
       
  5841 			// being hidden by cascaded rules or not
       
  5842 			if ( !values[ index ] && display === "none" ) {
       
  5843 				elem.style.display = "";
       
  5844 			}
       
  5845 
       
  5846 			// Set elements which have been overridden with display: none
       
  5847 			// in a stylesheet to whatever the default browser style is
       
  5848 			// for such an element
       
  5849 			if ( elem.style.display === "" && isHidden( elem ) ) {
       
  5850 				values[ index ] = data_priv.access( elem, "olddisplay", defaultDisplay(elem.nodeName) );
       
  5851 			}
       
  5852 		} else {
       
  5853 			hidden = isHidden( elem );
       
  5854 
       
  5855 			if ( display !== "none" || !hidden ) {
       
  5856 				data_priv.set( elem, "olddisplay", hidden ? display : jQuery.css( elem, "display" ) );
       
  5857 			}
       
  5858 		}
       
  5859 	}
       
  5860 
       
  5861 	// Set the display of most of the elements in a second loop
       
  5862 	// to avoid the constant reflow
       
  5863 	for ( index = 0; index < length; index++ ) {
       
  5864 		elem = elements[ index ];
       
  5865 		if ( !elem.style ) {
       
  5866 			continue;
       
  5867 		}
       
  5868 		if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
       
  5869 			elem.style.display = show ? values[ index ] || "" : "none";
       
  5870 		}
       
  5871 	}
       
  5872 
       
  5873 	return elements;
       
  5874 }
       
  5875 
       
  5876 jQuery.extend({
       
  5877 	// Add in style property hooks for overriding the default
       
  5878 	// behavior of getting and setting a style property
       
  5879 	cssHooks: {
       
  5880 		opacity: {
       
  5881 			get: function( elem, computed ) {
       
  5882 				if ( computed ) {
       
  5883 					// We should always get a number back from opacity
       
  5884 					var ret = curCSS( elem, "opacity" );
       
  5885 					return ret === "" ? "1" : ret;
       
  5886 				}
       
  5887 			}
       
  5888 		}
       
  5889 	},
       
  5890 
       
  5891 	// Don't automatically add "px" to these possibly-unitless properties
       
  5892 	cssNumber: {
       
  5893 		"columnCount": true,
       
  5894 		"fillOpacity": true,
       
  5895 		"flexGrow": true,
       
  5896 		"flexShrink": true,
       
  5897 		"fontWeight": true,
       
  5898 		"lineHeight": true,
       
  5899 		"opacity": true,
       
  5900 		"order": true,
       
  5901 		"orphans": true,
       
  5902 		"widows": true,
       
  5903 		"zIndex": true,
       
  5904 		"zoom": true
       
  5905 	},
       
  5906 
       
  5907 	// Add in properties whose names you wish to fix before
       
  5908 	// setting or getting the value
       
  5909 	cssProps: {
       
  5910 		// normalize float css property
       
  5911 		"float": "cssFloat"
       
  5912 	},
       
  5913 
       
  5914 	// Get and set the style property on a DOM Node
       
  5915 	style: function( elem, name, value, extra ) {
       
  5916 		// Don't set styles on text and comment nodes
       
  5917 		if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
       
  5918 			return;
       
  5919 		}
       
  5920 
       
  5921 		// Make sure that we're working with the right name
       
  5922 		var ret, type, hooks,
       
  5923 			origName = jQuery.camelCase( name ),
       
  5924 			style = elem.style;
       
  5925 
       
  5926 		name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
       
  5927 
       
  5928 		// gets hook for the prefixed version
       
  5929 		// followed by the unprefixed version
       
  5930 		hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
       
  5931 
       
  5932 		// Check if we're setting a value
       
  5933 		if ( value !== undefined ) {
       
  5934 			type = typeof value;
       
  5935 
       
  5936 			// convert relative number strings (+= or -=) to relative numbers. #7345
       
  5937 			if ( type === "string" && (ret = rrelNum.exec( value )) ) {
       
  5938 				value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
       
  5939 				// Fixes bug #9237
       
  5940 				type = "number";
       
  5941 			}
       
  5942 
       
  5943 			// Make sure that null and NaN values aren't set. See: #7116
       
  5944 			if ( value == null || value !== value ) {
       
  5945 				return;
       
  5946 			}
       
  5947 
       
  5948 			// If a number was passed in, add 'px' to the (except for certain CSS properties)
       
  5949 			if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
       
  5950 				value += "px";
       
  5951 			}
       
  5952 
       
  5953 			// Fixes #8908, it can be done more correctly by specifying setters in cssHooks,
       
  5954 			// but it would mean to define eight (for every problematic property) identical functions
       
  5955 			if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) {
       
  5956 				style[ name ] = "inherit";
       
  5957 			}
       
  5958 
       
  5959 			// If a hook was provided, use that value, otherwise just set the specified value
       
  5960 			if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
       
  5961 				style[ name ] = value;
       
  5962 			}
       
  5963 
       
  5964 		} else {
       
  5965 			// If a hook was provided get the non-computed value from there
       
  5966 			if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
       
  5967 				return ret;
       
  5968 			}
       
  5969 
       
  5970 			// Otherwise just get the value from the style object
       
  5971 			return style[ name ];
       
  5972 		}
       
  5973 	},
       
  5974 
       
  5975 	css: function( elem, name, extra, styles ) {
       
  5976 		var val, num, hooks,
       
  5977 			origName = jQuery.camelCase( name );
       
  5978 
       
  5979 		// Make sure that we're working with the right name
       
  5980 		name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
       
  5981 
       
  5982 		// gets hook for the prefixed version
       
  5983 		// followed by the unprefixed version
       
  5984 		hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
       
  5985 
       
  5986 		// If a hook was provided get the computed value from there
       
  5987 		if ( hooks && "get" in hooks ) {
       
  5988 			val = hooks.get( elem, true, extra );
       
  5989 		}
       
  5990 
       
  5991 		// Otherwise, if a way to get the computed value exists, use that
       
  5992 		if ( val === undefined ) {
       
  5993 			val = curCSS( elem, name, styles );
       
  5994 		}
       
  5995 
       
  5996 		//convert "normal" to computed value
       
  5997 		if ( val === "normal" && name in cssNormalTransform ) {
       
  5998 			val = cssNormalTransform[ name ];
       
  5999 		}
       
  6000 
       
  6001 		// Return, converting to number if forced or a qualifier was provided and val looks numeric
       
  6002 		if ( extra === "" || extra ) {
       
  6003 			num = parseFloat( val );
       
  6004 			return extra === true || jQuery.isNumeric( num ) ? num || 0 : val;
       
  6005 		}
       
  6006 		return val;
       
  6007 	}
       
  6008 });
       
  6009 
       
  6010 jQuery.each([ "height", "width" ], function( i, name ) {
       
  6011 	jQuery.cssHooks[ name ] = {
       
  6012 		get: function( elem, computed, extra ) {
       
  6013 			if ( computed ) {
       
  6014 				// certain elements can have dimension info if we invisibly show them
       
  6015 				// however, it must have a current display style that would benefit from this
       
  6016 				return rdisplayswap.test( jQuery.css( elem, "display" ) ) && elem.offsetWidth === 0 ?
       
  6017 					jQuery.swap( elem, cssShow, function() {
       
  6018 						return getWidthOrHeight( elem, name, extra );
       
  6019 					}) :
       
  6020 					getWidthOrHeight( elem, name, extra );
       
  6021 			}
       
  6022 		},
       
  6023 
       
  6024 		set: function( elem, value, extra ) {
       
  6025 			var styles = extra && getStyles( elem );
       
  6026 			return setPositiveNumber( elem, value, extra ?
       
  6027 				augmentWidthOrHeight(
       
  6028 					elem,
       
  6029 					name,
       
  6030 					extra,
       
  6031 					jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
       
  6032 					styles
       
  6033 				) : 0
       
  6034 			);
       
  6035 		}
       
  6036 	};
       
  6037 });
       
  6038 
       
  6039 // Support: Android 2.3
       
  6040 jQuery.cssHooks.marginRight = addGetHookIf( support.reliableMarginRight,
       
  6041 	function( elem, computed ) {
       
  6042 		if ( computed ) {
       
  6043 			// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
       
  6044 			// Work around by temporarily setting element display to inline-block
       
  6045 			return jQuery.swap( elem, { "display": "inline-block" },
       
  6046 				curCSS, [ elem, "marginRight" ] );
       
  6047 		}
       
  6048 	}
       
  6049 );
       
  6050 
       
  6051 // These hooks are used by animate to expand properties
       
  6052 jQuery.each({
       
  6053 	margin: "",
       
  6054 	padding: "",
       
  6055 	border: "Width"
       
  6056 }, function( prefix, suffix ) {
       
  6057 	jQuery.cssHooks[ prefix + suffix ] = {
       
  6058 		expand: function( value ) {
       
  6059 			var i = 0,
       
  6060 				expanded = {},
       
  6061 
       
  6062 				// assumes a single number if not a string
       
  6063 				parts = typeof value === "string" ? value.split(" ") : [ value ];
       
  6064 
       
  6065 			for ( ; i < 4; i++ ) {
       
  6066 				expanded[ prefix + cssExpand[ i ] + suffix ] =
       
  6067 					parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
       
  6068 			}
       
  6069 
       
  6070 			return expanded;
       
  6071 		}
       
  6072 	};
       
  6073 
       
  6074 	if ( !rmargin.test( prefix ) ) {
       
  6075 		jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
       
  6076 	}
       
  6077 });
       
  6078 
       
  6079 jQuery.fn.extend({
       
  6080 	css: function( name, value ) {
       
  6081 		return access( this, function( elem, name, value ) {
       
  6082 			var styles, len,
       
  6083 				map = {},
       
  6084 				i = 0;
       
  6085 
       
  6086 			if ( jQuery.isArray( name ) ) {
       
  6087 				styles = getStyles( elem );
       
  6088 				len = name.length;
       
  6089 
       
  6090 				for ( ; i < len; i++ ) {
       
  6091 					map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
       
  6092 				}
       
  6093 
       
  6094 				return map;
       
  6095 			}
       
  6096 
       
  6097 			return value !== undefined ?
       
  6098 				jQuery.style( elem, name, value ) :
       
  6099 				jQuery.css( elem, name );
       
  6100 		}, name, value, arguments.length > 1 );
       
  6101 	},
       
  6102 	show: function() {
       
  6103 		return showHide( this, true );
       
  6104 	},
       
  6105 	hide: function() {
       
  6106 		return showHide( this );
       
  6107 	},
       
  6108 	toggle: function( state ) {
       
  6109 		if ( typeof state === "boolean" ) {
       
  6110 			return state ? this.show() : this.hide();
       
  6111 		}
       
  6112 
       
  6113 		return this.each(function() {
       
  6114 			if ( isHidden( this ) ) {
       
  6115 				jQuery( this ).show();
       
  6116 			} else {
       
  6117 				jQuery( this ).hide();
       
  6118 			}
       
  6119 		});
       
  6120 	}
       
  6121 });
       
  6122 
       
  6123 
       
  6124 function Tween( elem, options, prop, end, easing ) {
       
  6125 	return new Tween.prototype.init( elem, options, prop, end, easing );
       
  6126 }
       
  6127 jQuery.Tween = Tween;
       
  6128 
       
  6129 Tween.prototype = {
       
  6130 	constructor: Tween,
       
  6131 	init: function( elem, options, prop, end, easing, unit ) {
       
  6132 		this.elem = elem;
       
  6133 		this.prop = prop;
       
  6134 		this.easing = easing || "swing";
       
  6135 		this.options = options;
       
  6136 		this.start = this.now = this.cur();
       
  6137 		this.end = end;
       
  6138 		this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
       
  6139 	},
       
  6140 	cur: function() {
       
  6141 		var hooks = Tween.propHooks[ this.prop ];
       
  6142 
       
  6143 		return hooks && hooks.get ?
       
  6144 			hooks.get( this ) :
       
  6145 			Tween.propHooks._default.get( this );
       
  6146 	},
       
  6147 	run: function( percent ) {
       
  6148 		var eased,
       
  6149 			hooks = Tween.propHooks[ this.prop ];
       
  6150 
       
  6151 		if ( this.options.duration ) {
       
  6152 			this.pos = eased = jQuery.easing[ this.easing ](
       
  6153 				percent, this.options.duration * percent, 0, 1, this.options.duration
       
  6154 			);
       
  6155 		} else {
       
  6156 			this.pos = eased = percent;
       
  6157 		}
       
  6158 		this.now = ( this.end - this.start ) * eased + this.start;
       
  6159 
       
  6160 		if ( this.options.step ) {
       
  6161 			this.options.step.call( this.elem, this.now, this );
       
  6162 		}
       
  6163 
       
  6164 		if ( hooks && hooks.set ) {
       
  6165 			hooks.set( this );
       
  6166 		} else {
       
  6167 			Tween.propHooks._default.set( this );
       
  6168 		}
       
  6169 		return this;
       
  6170 	}
       
  6171 };
       
  6172 
       
  6173 Tween.prototype.init.prototype = Tween.prototype;
       
  6174 
       
  6175 Tween.propHooks = {
       
  6176 	_default: {
       
  6177 		get: function( tween ) {
       
  6178 			var result;
       
  6179 
       
  6180 			if ( tween.elem[ tween.prop ] != null &&
       
  6181 				(!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {
       
  6182 				return tween.elem[ tween.prop ];
       
  6183 			}
       
  6184 
       
  6185 			// passing an empty string as a 3rd parameter to .css will automatically
       
  6186 			// attempt a parseFloat and fallback to a string if the parse fails
       
  6187 			// so, simple values such as "10px" are parsed to Float.
       
  6188 			// complex values such as "rotate(1rad)" are returned as is.
       
  6189 			result = jQuery.css( tween.elem, tween.prop, "" );
       
  6190 			// Empty strings, null, undefined and "auto" are converted to 0.
       
  6191 			return !result || result === "auto" ? 0 : result;
       
  6192 		},
       
  6193 		set: function( tween ) {
       
  6194 			// use step hook for back compat - use cssHook if its there - use .style if its
       
  6195 			// available and use plain properties where available
       
  6196 			if ( jQuery.fx.step[ tween.prop ] ) {
       
  6197 				jQuery.fx.step[ tween.prop ]( tween );
       
  6198 			} else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {
       
  6199 				jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
       
  6200 			} else {
       
  6201 				tween.elem[ tween.prop ] = tween.now;
       
  6202 			}
       
  6203 		}
       
  6204 	}
       
  6205 };
       
  6206 
       
  6207 // Support: IE9
       
  6208 // Panic based approach to setting things on disconnected nodes
       
  6209 
       
  6210 Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
       
  6211 	set: function( tween ) {
       
  6212 		if ( tween.elem.nodeType && tween.elem.parentNode ) {
       
  6213 			tween.elem[ tween.prop ] = tween.now;
       
  6214 		}
       
  6215 	}
       
  6216 };
       
  6217 
       
  6218 jQuery.easing = {
       
  6219 	linear: function( p ) {
       
  6220 		return p;
       
  6221 	},
       
  6222 	swing: function( p ) {
       
  6223 		return 0.5 - Math.cos( p * Math.PI ) / 2;
       
  6224 	}
       
  6225 };
       
  6226 
       
  6227 jQuery.fx = Tween.prototype.init;
       
  6228 
       
  6229 // Back Compat <1.8 extension point
       
  6230 jQuery.fx.step = {};
       
  6231 
       
  6232 
       
  6233 
       
  6234 
       
  6235 var
       
  6236 	fxNow, timerId,
       
  6237 	rfxtypes = /^(?:toggle|show|hide)$/,
       
  6238 	rfxnum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ),
       
  6239 	rrun = /queueHooks$/,
       
  6240 	animationPrefilters = [ defaultPrefilter ],
       
  6241 	tweeners = {
       
  6242 		"*": [ function( prop, value ) {
       
  6243 			var tween = this.createTween( prop, value ),
       
  6244 				target = tween.cur(),
       
  6245 				parts = rfxnum.exec( value ),
       
  6246 				unit = parts && parts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
       
  6247 
       
  6248 				// Starting value computation is required for potential unit mismatches
       
  6249 				start = ( jQuery.cssNumber[ prop ] || unit !== "px" && +target ) &&
       
  6250 					rfxnum.exec( jQuery.css( tween.elem, prop ) ),
       
  6251 				scale = 1,
       
  6252 				maxIterations = 20;
       
  6253 
       
  6254 			if ( start && start[ 3 ] !== unit ) {
       
  6255 				// Trust units reported by jQuery.css
       
  6256 				unit = unit || start[ 3 ];
       
  6257 
       
  6258 				// Make sure we update the tween properties later on
       
  6259 				parts = parts || [];
       
  6260 
       
  6261 				// Iteratively approximate from a nonzero starting point
       
  6262 				start = +target || 1;
       
  6263 
       
  6264 				do {
       
  6265 					// If previous iteration zeroed out, double until we get *something*
       
  6266 					// Use a string for doubling factor so we don't accidentally see scale as unchanged below
       
  6267 					scale = scale || ".5";
       
  6268 
       
  6269 					// Adjust and apply
       
  6270 					start = start / scale;
       
  6271 					jQuery.style( tween.elem, prop, start + unit );
       
  6272 
       
  6273 				// Update scale, tolerating zero or NaN from tween.cur()
       
  6274 				// And breaking the loop if scale is unchanged or perfect, or if we've just had enough
       
  6275 				} while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
       
  6276 			}
       
  6277 
       
  6278 			// Update tween properties
       
  6279 			if ( parts ) {
       
  6280 				start = tween.start = +start || +target || 0;
       
  6281 				tween.unit = unit;
       
  6282 				// If a +=/-= token was provided, we're doing a relative animation
       
  6283 				tween.end = parts[ 1 ] ?
       
  6284 					start + ( parts[ 1 ] + 1 ) * parts[ 2 ] :
       
  6285 					+parts[ 2 ];
       
  6286 			}
       
  6287 
       
  6288 			return tween;
       
  6289 		} ]
       
  6290 	};
       
  6291 
       
  6292 // Animations created synchronously will run synchronously
       
  6293 function createFxNow() {
       
  6294 	setTimeout(function() {
       
  6295 		fxNow = undefined;
       
  6296 	});
       
  6297 	return ( fxNow = jQuery.now() );
       
  6298 }
       
  6299 
       
  6300 // Generate parameters to create a standard animation
       
  6301 function genFx( type, includeWidth ) {
       
  6302 	var which,
       
  6303 		i = 0,
       
  6304 		attrs = { height: type };
       
  6305 
       
  6306 	// if we include width, step value is 1 to do all cssExpand values,
       
  6307 	// if we don't include width, step value is 2 to skip over Left and Right
       
  6308 	includeWidth = includeWidth ? 1 : 0;
       
  6309 	for ( ; i < 4 ; i += 2 - includeWidth ) {
       
  6310 		which = cssExpand[ i ];
       
  6311 		attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
       
  6312 	}
       
  6313 
       
  6314 	if ( includeWidth ) {
       
  6315 		attrs.opacity = attrs.width = type;
       
  6316 	}
       
  6317 
       
  6318 	return attrs;
       
  6319 }
       
  6320 
       
  6321 function createTween( value, prop, animation ) {
       
  6322 	var tween,
       
  6323 		collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
       
  6324 		index = 0,
       
  6325 		length = collection.length;
       
  6326 	for ( ; index < length; index++ ) {
       
  6327 		if ( (tween = collection[ index ].call( animation, prop, value )) ) {
       
  6328 
       
  6329 			// we're done with this property
       
  6330 			return tween;
       
  6331 		}
       
  6332 	}
       
  6333 }
       
  6334 
       
  6335 function defaultPrefilter( elem, props, opts ) {
       
  6336 	/* jshint validthis: true */
       
  6337 	var prop, value, toggle, tween, hooks, oldfire, display, checkDisplay,
       
  6338 		anim = this,
       
  6339 		orig = {},
       
  6340 		style = elem.style,
       
  6341 		hidden = elem.nodeType && isHidden( elem ),
       
  6342 		dataShow = data_priv.get( elem, "fxshow" );
       
  6343 
       
  6344 	// handle queue: false promises
       
  6345 	if ( !opts.queue ) {
       
  6346 		hooks = jQuery._queueHooks( elem, "fx" );
       
  6347 		if ( hooks.unqueued == null ) {
       
  6348 			hooks.unqueued = 0;
       
  6349 			oldfire = hooks.empty.fire;
       
  6350 			hooks.empty.fire = function() {
       
  6351 				if ( !hooks.unqueued ) {
       
  6352 					oldfire();
       
  6353 				}
       
  6354 			};
       
  6355 		}
       
  6356 		hooks.unqueued++;
       
  6357 
       
  6358 		anim.always(function() {
       
  6359 			// doing this makes sure that the complete handler will be called
       
  6360 			// before this completes
       
  6361 			anim.always(function() {
       
  6362 				hooks.unqueued--;
       
  6363 				if ( !jQuery.queue( elem, "fx" ).length ) {
       
  6364 					hooks.empty.fire();
       
  6365 				}
       
  6366 			});
       
  6367 		});
       
  6368 	}
       
  6369 
       
  6370 	// height/width overflow pass
       
  6371 	if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
       
  6372 		// Make sure that nothing sneaks out
       
  6373 		// Record all 3 overflow attributes because IE9-10 do not
       
  6374 		// change the overflow attribute when overflowX and
       
  6375 		// overflowY are set to the same value
       
  6376 		opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
       
  6377 
       
  6378 		// Set display property to inline-block for height/width
       
  6379 		// animations on inline elements that are having width/height animated
       
  6380 		display = jQuery.css( elem, "display" );
       
  6381 
       
  6382 		// Test default display if display is currently "none"
       
  6383 		checkDisplay = display === "none" ?
       
  6384 			data_priv.get( elem, "olddisplay" ) || defaultDisplay( elem.nodeName ) : display;
       
  6385 
       
  6386 		if ( checkDisplay === "inline" && jQuery.css( elem, "float" ) === "none" ) {
       
  6387 			style.display = "inline-block";
       
  6388 		}
       
  6389 	}
       
  6390 
       
  6391 	if ( opts.overflow ) {
       
  6392 		style.overflow = "hidden";
       
  6393 		anim.always(function() {
       
  6394 			style.overflow = opts.overflow[ 0 ];
       
  6395 			style.overflowX = opts.overflow[ 1 ];
       
  6396 			style.overflowY = opts.overflow[ 2 ];
       
  6397 		});
       
  6398 	}
       
  6399 
       
  6400 	// show/hide pass
       
  6401 	for ( prop in props ) {
       
  6402 		value = props[ prop ];
       
  6403 		if ( rfxtypes.exec( value ) ) {
       
  6404 			delete props[ prop ];
       
  6405 			toggle = toggle || value === "toggle";
       
  6406 			if ( value === ( hidden ? "hide" : "show" ) ) {
       
  6407 
       
  6408 				// If there is dataShow left over from a stopped hide or show and we are going to proceed with show, we should pretend to be hidden
       
  6409 				if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
       
  6410 					hidden = true;
       
  6411 				} else {
       
  6412 					continue;
       
  6413 				}
       
  6414 			}
       
  6415 			orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
       
  6416 
       
  6417 		// Any non-fx value stops us from restoring the original display value
       
  6418 		} else {
       
  6419 			display = undefined;
       
  6420 		}
       
  6421 	}
       
  6422 
       
  6423 	if ( !jQuery.isEmptyObject( orig ) ) {
       
  6424 		if ( dataShow ) {
       
  6425 			if ( "hidden" in dataShow ) {
       
  6426 				hidden = dataShow.hidden;
       
  6427 			}
       
  6428 		} else {
       
  6429 			dataShow = data_priv.access( elem, "fxshow", {} );
       
  6430 		}
       
  6431 
       
  6432 		// store state if its toggle - enables .stop().toggle() to "reverse"
       
  6433 		if ( toggle ) {
       
  6434 			dataShow.hidden = !hidden;
       
  6435 		}
       
  6436 		if ( hidden ) {
       
  6437 			jQuery( elem ).show();
       
  6438 		} else {
       
  6439 			anim.done(function() {
       
  6440 				jQuery( elem ).hide();
       
  6441 			});
       
  6442 		}
       
  6443 		anim.done(function() {
       
  6444 			var prop;
       
  6445 
       
  6446 			data_priv.remove( elem, "fxshow" );
       
  6447 			for ( prop in orig ) {
       
  6448 				jQuery.style( elem, prop, orig[ prop ] );
       
  6449 			}
       
  6450 		});
       
  6451 		for ( prop in orig ) {
       
  6452 			tween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
       
  6453 
       
  6454 			if ( !( prop in dataShow ) ) {
       
  6455 				dataShow[ prop ] = tween.start;
       
  6456 				if ( hidden ) {
       
  6457 					tween.end = tween.start;
       
  6458 					tween.start = prop === "width" || prop === "height" ? 1 : 0;
       
  6459 				}
       
  6460 			}
       
  6461 		}
       
  6462 
       
  6463 	// If this is a noop like .hide().hide(), restore an overwritten display value
       
  6464 	} else if ( (display === "none" ? defaultDisplay( elem.nodeName ) : display) === "inline" ) {
       
  6465 		style.display = display;
       
  6466 	}
       
  6467 }
       
  6468 
       
  6469 function propFilter( props, specialEasing ) {
       
  6470 	var index, name, easing, value, hooks;
       
  6471 
       
  6472 	// camelCase, specialEasing and expand cssHook pass
       
  6473 	for ( index in props ) {
       
  6474 		name = jQuery.camelCase( index );
       
  6475 		easing = specialEasing[ name ];
       
  6476 		value = props[ index ];
       
  6477 		if ( jQuery.isArray( value ) ) {
       
  6478 			easing = value[ 1 ];
       
  6479 			value = props[ index ] = value[ 0 ];
       
  6480 		}
       
  6481 
       
  6482 		if ( index !== name ) {
       
  6483 			props[ name ] = value;
       
  6484 			delete props[ index ];
       
  6485 		}
       
  6486 
       
  6487 		hooks = jQuery.cssHooks[ name ];
       
  6488 		if ( hooks && "expand" in hooks ) {
       
  6489 			value = hooks.expand( value );
       
  6490 			delete props[ name ];
       
  6491 
       
  6492 			// not quite $.extend, this wont overwrite keys already present.
       
  6493 			// also - reusing 'index' from above because we have the correct "name"
       
  6494 			for ( index in value ) {
       
  6495 				if ( !( index in props ) ) {
       
  6496 					props[ index ] = value[ index ];
       
  6497 					specialEasing[ index ] = easing;
       
  6498 				}
       
  6499 			}
       
  6500 		} else {
       
  6501 			specialEasing[ name ] = easing;
       
  6502 		}
       
  6503 	}
       
  6504 }
       
  6505 
       
  6506 function Animation( elem, properties, options ) {
       
  6507 	var result,
       
  6508 		stopped,
       
  6509 		index = 0,
       
  6510 		length = animationPrefilters.length,
       
  6511 		deferred = jQuery.Deferred().always( function() {
       
  6512 			// don't match elem in the :animated selector
       
  6513 			delete tick.elem;
       
  6514 		}),
       
  6515 		tick = function() {
       
  6516 			if ( stopped ) {
       
  6517 				return false;
       
  6518 			}
       
  6519 			var currentTime = fxNow || createFxNow(),
       
  6520 				remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
       
  6521 				// archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)
       
  6522 				temp = remaining / animation.duration || 0,
       
  6523 				percent = 1 - temp,
       
  6524 				index = 0,
       
  6525 				length = animation.tweens.length;
       
  6526 
       
  6527 			for ( ; index < length ; index++ ) {
       
  6528 				animation.tweens[ index ].run( percent );
       
  6529 			}
       
  6530 
       
  6531 			deferred.notifyWith( elem, [ animation, percent, remaining ]);
       
  6532 
       
  6533 			if ( percent < 1 && length ) {
       
  6534 				return remaining;
       
  6535 			} else {
       
  6536 				deferred.resolveWith( elem, [ animation ] );
       
  6537 				return false;
       
  6538 			}
       
  6539 		},
       
  6540 		animation = deferred.promise({
       
  6541 			elem: elem,
       
  6542 			props: jQuery.extend( {}, properties ),
       
  6543 			opts: jQuery.extend( true, { specialEasing: {} }, options ),
       
  6544 			originalProperties: properties,
       
  6545 			originalOptions: options,
       
  6546 			startTime: fxNow || createFxNow(),
       
  6547 			duration: options.duration,
       
  6548 			tweens: [],
       
  6549 			createTween: function( prop, end ) {
       
  6550 				var tween = jQuery.Tween( elem, animation.opts, prop, end,
       
  6551 						animation.opts.specialEasing[ prop ] || animation.opts.easing );
       
  6552 				animation.tweens.push( tween );
       
  6553 				return tween;
       
  6554 			},
       
  6555 			stop: function( gotoEnd ) {
       
  6556 				var index = 0,
       
  6557 					// if we are going to the end, we want to run all the tweens
       
  6558 					// otherwise we skip this part
       
  6559 					length = gotoEnd ? animation.tweens.length : 0;
       
  6560 				if ( stopped ) {
       
  6561 					return this;
       
  6562 				}
       
  6563 				stopped = true;
       
  6564 				for ( ; index < length ; index++ ) {
       
  6565 					animation.tweens[ index ].run( 1 );
       
  6566 				}
       
  6567 
       
  6568 				// resolve when we played the last frame
       
  6569 				// otherwise, reject
       
  6570 				if ( gotoEnd ) {
       
  6571 					deferred.resolveWith( elem, [ animation, gotoEnd ] );
       
  6572 				} else {
       
  6573 					deferred.rejectWith( elem, [ animation, gotoEnd ] );
       
  6574 				}
       
  6575 				return this;
       
  6576 			}
       
  6577 		}),
       
  6578 		props = animation.props;
       
  6579 
       
  6580 	propFilter( props, animation.opts.specialEasing );
       
  6581 
       
  6582 	for ( ; index < length ; index++ ) {
       
  6583 		result = animationPrefilters[ index ].call( animation, elem, props, animation.opts );
       
  6584 		if ( result ) {
       
  6585 			return result;
       
  6586 		}
       
  6587 	}
       
  6588 
       
  6589 	jQuery.map( props, createTween, animation );
       
  6590 
       
  6591 	if ( jQuery.isFunction( animation.opts.start ) ) {
       
  6592 		animation.opts.start.call( elem, animation );
       
  6593 	}
       
  6594 
       
  6595 	jQuery.fx.timer(
       
  6596 		jQuery.extend( tick, {
       
  6597 			elem: elem,
       
  6598 			anim: animation,
       
  6599 			queue: animation.opts.queue
       
  6600 		})
       
  6601 	);
       
  6602 
       
  6603 	// attach callbacks from options
       
  6604 	return animation.progress( animation.opts.progress )
       
  6605 		.done( animation.opts.done, animation.opts.complete )
       
  6606 		.fail( animation.opts.fail )
       
  6607 		.always( animation.opts.always );
       
  6608 }
       
  6609 
       
  6610 jQuery.Animation = jQuery.extend( Animation, {
       
  6611 
       
  6612 	tweener: function( props, callback ) {
       
  6613 		if ( jQuery.isFunction( props ) ) {
       
  6614 			callback = props;
       
  6615 			props = [ "*" ];
       
  6616 		} else {
       
  6617 			props = props.split(" ");
       
  6618 		}
       
  6619 
       
  6620 		var prop,
       
  6621 			index = 0,
       
  6622 			length = props.length;
       
  6623 
       
  6624 		for ( ; index < length ; index++ ) {
       
  6625 			prop = props[ index ];
       
  6626 			tweeners[ prop ] = tweeners[ prop ] || [];
       
  6627 			tweeners[ prop ].unshift( callback );
       
  6628 		}
       
  6629 	},
       
  6630 
       
  6631 	prefilter: function( callback, prepend ) {
       
  6632 		if ( prepend ) {
       
  6633 			animationPrefilters.unshift( callback );
       
  6634 		} else {
       
  6635 			animationPrefilters.push( callback );
       
  6636 		}
       
  6637 	}
       
  6638 });
       
  6639 
       
  6640 jQuery.speed = function( speed, easing, fn ) {
       
  6641 	var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
       
  6642 		complete: fn || !fn && easing ||
       
  6643 			jQuery.isFunction( speed ) && speed,
       
  6644 		duration: speed,
       
  6645 		easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
       
  6646 	};
       
  6647 
       
  6648 	opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
       
  6649 		opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
       
  6650 
       
  6651 	// normalize opt.queue - true/undefined/null -> "fx"
       
  6652 	if ( opt.queue == null || opt.queue === true ) {
       
  6653 		opt.queue = "fx";
       
  6654 	}
       
  6655 
       
  6656 	// Queueing
       
  6657 	opt.old = opt.complete;
       
  6658 
       
  6659 	opt.complete = function() {
       
  6660 		if ( jQuery.isFunction( opt.old ) ) {
       
  6661 			opt.old.call( this );
       
  6662 		}
       
  6663 
       
  6664 		if ( opt.queue ) {
       
  6665 			jQuery.dequeue( this, opt.queue );
       
  6666 		}
       
  6667 	};
       
  6668 
       
  6669 	return opt;
       
  6670 };
       
  6671 
       
  6672 jQuery.fn.extend({
       
  6673 	fadeTo: function( speed, to, easing, callback ) {
       
  6674 
       
  6675 		// show any hidden elements after setting opacity to 0
       
  6676 		return this.filter( isHidden ).css( "opacity", 0 ).show()
       
  6677 
       
  6678 			// animate to the value specified
       
  6679 			.end().animate({ opacity: to }, speed, easing, callback );
       
  6680 	},
       
  6681 	animate: function( prop, speed, easing, callback ) {
       
  6682 		var empty = jQuery.isEmptyObject( prop ),
       
  6683 			optall = jQuery.speed( speed, easing, callback ),
       
  6684 			doAnimation = function() {
       
  6685 				// Operate on a copy of prop so per-property easing won't be lost
       
  6686 				var anim = Animation( this, jQuery.extend( {}, prop ), optall );
       
  6687 
       
  6688 				// Empty animations, or finishing resolves immediately
       
  6689 				if ( empty || data_priv.get( this, "finish" ) ) {
       
  6690 					anim.stop( true );
       
  6691 				}
       
  6692 			};
       
  6693 			doAnimation.finish = doAnimation;
       
  6694 
       
  6695 		return empty || optall.queue === false ?
       
  6696 			this.each( doAnimation ) :
       
  6697 			this.queue( optall.queue, doAnimation );
       
  6698 	},
       
  6699 	stop: function( type, clearQueue, gotoEnd ) {
       
  6700 		var stopQueue = function( hooks ) {
       
  6701 			var stop = hooks.stop;
       
  6702 			delete hooks.stop;
       
  6703 			stop( gotoEnd );
       
  6704 		};
       
  6705 
       
  6706 		if ( typeof type !== "string" ) {
       
  6707 			gotoEnd = clearQueue;
       
  6708 			clearQueue = type;
       
  6709 			type = undefined;
       
  6710 		}
       
  6711 		if ( clearQueue && type !== false ) {
       
  6712 			this.queue( type || "fx", [] );
       
  6713 		}
       
  6714 
       
  6715 		return this.each(function() {
       
  6716 			var dequeue = true,
       
  6717 				index = type != null && type + "queueHooks",
       
  6718 				timers = jQuery.timers,
       
  6719 				data = data_priv.get( this );
       
  6720 
       
  6721 			if ( index ) {
       
  6722 				if ( data[ index ] && data[ index ].stop ) {
       
  6723 					stopQueue( data[ index ] );
       
  6724 				}
       
  6725 			} else {
       
  6726 				for ( index in data ) {
       
  6727 					if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
       
  6728 						stopQueue( data[ index ] );
       
  6729 					}
       
  6730 				}
       
  6731 			}
       
  6732 
       
  6733 			for ( index = timers.length; index--; ) {
       
  6734 				if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
       
  6735 					timers[ index ].anim.stop( gotoEnd );
       
  6736 					dequeue = false;
       
  6737 					timers.splice( index, 1 );
       
  6738 				}
       
  6739 			}
       
  6740 
       
  6741 			// start the next in the queue if the last step wasn't forced
       
  6742 			// timers currently will call their complete callbacks, which will dequeue
       
  6743 			// but only if they were gotoEnd
       
  6744 			if ( dequeue || !gotoEnd ) {
       
  6745 				jQuery.dequeue( this, type );
       
  6746 			}
       
  6747 		});
       
  6748 	},
       
  6749 	finish: function( type ) {
       
  6750 		if ( type !== false ) {
       
  6751 			type = type || "fx";
       
  6752 		}
       
  6753 		return this.each(function() {
       
  6754 			var index,
       
  6755 				data = data_priv.get( this ),
       
  6756 				queue = data[ type + "queue" ],
       
  6757 				hooks = data[ type + "queueHooks" ],
       
  6758 				timers = jQuery.timers,
       
  6759 				length = queue ? queue.length : 0;
       
  6760 
       
  6761 			// enable finishing flag on private data
       
  6762 			data.finish = true;
       
  6763 
       
  6764 			// empty the queue first
       
  6765 			jQuery.queue( this, type, [] );
       
  6766 
       
  6767 			if ( hooks && hooks.stop ) {
       
  6768 				hooks.stop.call( this, true );
       
  6769 			}
       
  6770 
       
  6771 			// look for any active animations, and finish them
       
  6772 			for ( index = timers.length; index--; ) {
       
  6773 				if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
       
  6774 					timers[ index ].anim.stop( true );
       
  6775 					timers.splice( index, 1 );
       
  6776 				}
       
  6777 			}
       
  6778 
       
  6779 			// look for any animations in the old queue and finish them
       
  6780 			for ( index = 0; index < length; index++ ) {
       
  6781 				if ( queue[ index ] && queue[ index ].finish ) {
       
  6782 					queue[ index ].finish.call( this );
       
  6783 				}
       
  6784 			}
       
  6785 
       
  6786 			// turn off finishing flag
       
  6787 			delete data.finish;
       
  6788 		});
       
  6789 	}
       
  6790 });
       
  6791 
       
  6792 jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
       
  6793 	var cssFn = jQuery.fn[ name ];
       
  6794 	jQuery.fn[ name ] = function( speed, easing, callback ) {
       
  6795 		return speed == null || typeof speed === "boolean" ?
       
  6796 			cssFn.apply( this, arguments ) :
       
  6797 			this.animate( genFx( name, true ), speed, easing, callback );
       
  6798 	};
       
  6799 });
       
  6800 
       
  6801 // Generate shortcuts for custom animations
       
  6802 jQuery.each({
       
  6803 	slideDown: genFx("show"),
       
  6804 	slideUp: genFx("hide"),
       
  6805 	slideToggle: genFx("toggle"),
       
  6806 	fadeIn: { opacity: "show" },
       
  6807 	fadeOut: { opacity: "hide" },
       
  6808 	fadeToggle: { opacity: "toggle" }
       
  6809 }, function( name, props ) {
       
  6810 	jQuery.fn[ name ] = function( speed, easing, callback ) {
       
  6811 		return this.animate( props, speed, easing, callback );
       
  6812 	};
       
  6813 });
       
  6814 
       
  6815 jQuery.timers = [];
       
  6816 jQuery.fx.tick = function() {
       
  6817 	var timer,
       
  6818 		i = 0,
       
  6819 		timers = jQuery.timers;
       
  6820 
       
  6821 	fxNow = jQuery.now();
       
  6822 
       
  6823 	for ( ; i < timers.length; i++ ) {
       
  6824 		timer = timers[ i ];
       
  6825 		// Checks the timer has not already been removed
       
  6826 		if ( !timer() && timers[ i ] === timer ) {
       
  6827 			timers.splice( i--, 1 );
       
  6828 		}
       
  6829 	}
       
  6830 
       
  6831 	if ( !timers.length ) {
       
  6832 		jQuery.fx.stop();
       
  6833 	}
       
  6834 	fxNow = undefined;
       
  6835 };
       
  6836 
       
  6837 jQuery.fx.timer = function( timer ) {
       
  6838 	jQuery.timers.push( timer );
       
  6839 	if ( timer() ) {
       
  6840 		jQuery.fx.start();
       
  6841 	} else {
       
  6842 		jQuery.timers.pop();
       
  6843 	}
       
  6844 };
       
  6845 
       
  6846 jQuery.fx.interval = 13;
       
  6847 
       
  6848 jQuery.fx.start = function() {
       
  6849 	if ( !timerId ) {
       
  6850 		timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );
       
  6851 	}
       
  6852 };
       
  6853 
       
  6854 jQuery.fx.stop = function() {
       
  6855 	clearInterval( timerId );
       
  6856 	timerId = null;
       
  6857 };
       
  6858 
       
  6859 jQuery.fx.speeds = {
       
  6860 	slow: 600,
       
  6861 	fast: 200,
       
  6862 	// Default speed
       
  6863 	_default: 400
       
  6864 };
       
  6865 
       
  6866 
       
  6867 // Based off of the plugin by Clint Helfers, with permission.
       
  6868 // http://blindsignals.com/index.php/2009/07/jquery-delay/
       
  6869 jQuery.fn.delay = function( time, type ) {
       
  6870 	time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
       
  6871 	type = type || "fx";
       
  6872 
       
  6873 	return this.queue( type, function( next, hooks ) {
       
  6874 		var timeout = setTimeout( next, time );
       
  6875 		hooks.stop = function() {
       
  6876 			clearTimeout( timeout );
       
  6877 		};
       
  6878 	});
       
  6879 };
       
  6880 
       
  6881 
       
  6882 (function() {
       
  6883 	var input = document.createElement( "input" ),
       
  6884 		select = document.createElement( "select" ),
       
  6885 		opt = select.appendChild( document.createElement( "option" ) );
       
  6886 
       
  6887 	input.type = "checkbox";
       
  6888 
       
  6889 	// Support: iOS 5.1, Android 4.x, Android 2.3
       
  6890 	// Check the default checkbox/radio value ("" on old WebKit; "on" elsewhere)
       
  6891 	support.checkOn = input.value !== "";
       
  6892 
       
  6893 	// Must access the parent to make an option select properly
       
  6894 	// Support: IE9, IE10
       
  6895 	support.optSelected = opt.selected;
       
  6896 
       
  6897 	// Make sure that the options inside disabled selects aren't marked as disabled
       
  6898 	// (WebKit marks them as disabled)
       
  6899 	select.disabled = true;
       
  6900 	support.optDisabled = !opt.disabled;
       
  6901 
       
  6902 	// Check if an input maintains its value after becoming a radio
       
  6903 	// Support: IE9, IE10
       
  6904 	input = document.createElement( "input" );
       
  6905 	input.value = "t";
       
  6906 	input.type = "radio";
       
  6907 	support.radioValue = input.value === "t";
       
  6908 })();
       
  6909 
       
  6910 
       
  6911 var nodeHook, boolHook,
       
  6912 	attrHandle = jQuery.expr.attrHandle;
       
  6913 
       
  6914 jQuery.fn.extend({
       
  6915 	attr: function( name, value ) {
       
  6916 		return access( this, jQuery.attr, name, value, arguments.length > 1 );
       
  6917 	},
       
  6918 
       
  6919 	removeAttr: function( name ) {
       
  6920 		return this.each(function() {
       
  6921 			jQuery.removeAttr( this, name );
       
  6922 		});
       
  6923 	}
       
  6924 });
       
  6925 
       
  6926 jQuery.extend({
       
  6927 	attr: function( elem, name, value ) {
       
  6928 		var hooks, ret,
       
  6929 			nType = elem.nodeType;
       
  6930 
       
  6931 		// don't get/set attributes on text, comment and attribute nodes
       
  6932 		if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
       
  6933 			return;
       
  6934 		}
       
  6935 
       
  6936 		// Fallback to prop when attributes are not supported
       
  6937 		if ( typeof elem.getAttribute === strundefined ) {
       
  6938 			return jQuery.prop( elem, name, value );
       
  6939 		}
       
  6940 
       
  6941 		// All attributes are lowercase
       
  6942 		// Grab necessary hook if one is defined
       
  6943 		if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
       
  6944 			name = name.toLowerCase();
       
  6945 			hooks = jQuery.attrHooks[ name ] ||
       
  6946 				( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook );
       
  6947 		}
       
  6948 
       
  6949 		if ( value !== undefined ) {
       
  6950 
       
  6951 			if ( value === null ) {
       
  6952 				jQuery.removeAttr( elem, name );
       
  6953 
       
  6954 			} else if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
       
  6955 				return ret;
       
  6956 
       
  6957 			} else {
       
  6958 				elem.setAttribute( name, value + "" );
       
  6959 				return value;
       
  6960 			}
       
  6961 
       
  6962 		} else if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
       
  6963 			return ret;
       
  6964 
       
  6965 		} else {
       
  6966 			ret = jQuery.find.attr( elem, name );
       
  6967 
       
  6968 			// Non-existent attributes return null, we normalize to undefined
       
  6969 			return ret == null ?
       
  6970 				undefined :
       
  6971 				ret;
       
  6972 		}
       
  6973 	},
       
  6974 
       
  6975 	removeAttr: function( elem, value ) {
       
  6976 		var name, propName,
       
  6977 			i = 0,
       
  6978 			attrNames = value && value.match( rnotwhite );
       
  6979 
       
  6980 		if ( attrNames && elem.nodeType === 1 ) {
       
  6981 			while ( (name = attrNames[i++]) ) {
       
  6982 				propName = jQuery.propFix[ name ] || name;
       
  6983 
       
  6984 				// Boolean attributes get special treatment (#10870)
       
  6985 				if ( jQuery.expr.match.bool.test( name ) ) {
       
  6986 					// Set corresponding property to false
       
  6987 					elem[ propName ] = false;
       
  6988 				}
       
  6989 
       
  6990 				elem.removeAttribute( name );
       
  6991 			}
       
  6992 		}
       
  6993 	},
       
  6994 
       
  6995 	attrHooks: {
       
  6996 		type: {
       
  6997 			set: function( elem, value ) {
       
  6998 				if ( !support.radioValue && value === "radio" &&
       
  6999 					jQuery.nodeName( elem, "input" ) ) {
       
  7000 					// Setting the type on a radio button after the value resets the value in IE6-9
       
  7001 					// Reset value to default in case type is set after value during creation
       
  7002 					var val = elem.value;
       
  7003 					elem.setAttribute( "type", value );
       
  7004 					if ( val ) {
       
  7005 						elem.value = val;
       
  7006 					}
       
  7007 					return value;
       
  7008 				}
       
  7009 			}
       
  7010 		}
       
  7011 	}
       
  7012 });
       
  7013 
       
  7014 // Hooks for boolean attributes
       
  7015 boolHook = {
       
  7016 	set: function( elem, value, name ) {
       
  7017 		if ( value === false ) {
       
  7018 			// Remove boolean attributes when set to false
       
  7019 			jQuery.removeAttr( elem, name );
       
  7020 		} else {
       
  7021 			elem.setAttribute( name, name );
       
  7022 		}
       
  7023 		return name;
       
  7024 	}
       
  7025 };
       
  7026 jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) {
       
  7027 	var getter = attrHandle[ name ] || jQuery.find.attr;
       
  7028 
       
  7029 	attrHandle[ name ] = function( elem, name, isXML ) {
       
  7030 		var ret, handle;
       
  7031 		if ( !isXML ) {
       
  7032 			// Avoid an infinite loop by temporarily removing this function from the getter
       
  7033 			handle = attrHandle[ name ];
       
  7034 			attrHandle[ name ] = ret;
       
  7035 			ret = getter( elem, name, isXML ) != null ?
       
  7036 				name.toLowerCase() :
       
  7037 				null;
       
  7038 			attrHandle[ name ] = handle;
       
  7039 		}
       
  7040 		return ret;
       
  7041 	};
       
  7042 });
       
  7043 
       
  7044 
       
  7045 
       
  7046 
       
  7047 var rfocusable = /^(?:input|select|textarea|button)$/i;
       
  7048 
       
  7049 jQuery.fn.extend({
       
  7050 	prop: function( name, value ) {
       
  7051 		return access( this, jQuery.prop, name, value, arguments.length > 1 );
       
  7052 	},
       
  7053 
       
  7054 	removeProp: function( name ) {
       
  7055 		return this.each(function() {
       
  7056 			delete this[ jQuery.propFix[ name ] || name ];
       
  7057 		});
       
  7058 	}
       
  7059 });
       
  7060 
       
  7061 jQuery.extend({
       
  7062 	propFix: {
       
  7063 		"for": "htmlFor",
       
  7064 		"class": "className"
       
  7065 	},
       
  7066 
       
  7067 	prop: function( elem, name, value ) {
       
  7068 		var ret, hooks, notxml,
       
  7069 			nType = elem.nodeType;
       
  7070 
       
  7071 		// don't get/set properties on text, comment and attribute nodes
       
  7072 		if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
       
  7073 			return;
       
  7074 		}
       
  7075 
       
  7076 		notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
       
  7077 
       
  7078 		if ( notxml ) {
       
  7079 			// Fix name and attach hooks
       
  7080 			name = jQuery.propFix[ name ] || name;
       
  7081 			hooks = jQuery.propHooks[ name ];
       
  7082 		}
       
  7083 
       
  7084 		if ( value !== undefined ) {
       
  7085 			return hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ?
       
  7086 				ret :
       
  7087 				( elem[ name ] = value );
       
  7088 
       
  7089 		} else {
       
  7090 			return hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ?
       
  7091 				ret :
       
  7092 				elem[ name ];
       
  7093 		}
       
  7094 	},
       
  7095 
       
  7096 	propHooks: {
       
  7097 		tabIndex: {
       
  7098 			get: function( elem ) {
       
  7099 				return elem.hasAttribute( "tabindex" ) || rfocusable.test( elem.nodeName ) || elem.href ?
       
  7100 					elem.tabIndex :
       
  7101 					-1;
       
  7102 			}
       
  7103 		}
       
  7104 	}
       
  7105 });
       
  7106 
       
  7107 // Support: IE9+
       
  7108 // Selectedness for an option in an optgroup can be inaccurate
       
  7109 if ( !support.optSelected ) {
       
  7110 	jQuery.propHooks.selected = {
       
  7111 		get: function( elem ) {
       
  7112 			var parent = elem.parentNode;
       
  7113 			if ( parent && parent.parentNode ) {
       
  7114 				parent.parentNode.selectedIndex;
       
  7115 			}
       
  7116 			return null;
       
  7117 		}
       
  7118 	};
       
  7119 }
       
  7120 
       
  7121 jQuery.each([
       
  7122 	"tabIndex",
       
  7123 	"readOnly",
       
  7124 	"maxLength",
       
  7125 	"cellSpacing",
       
  7126 	"cellPadding",
       
  7127 	"rowSpan",
       
  7128 	"colSpan",
       
  7129 	"useMap",
       
  7130 	"frameBorder",
       
  7131 	"contentEditable"
       
  7132 ], function() {
       
  7133 	jQuery.propFix[ this.toLowerCase() ] = this;
       
  7134 });
       
  7135 
       
  7136 
       
  7137 
       
  7138 
       
  7139 var rclass = /[\t\r\n\f]/g;
       
  7140 
       
  7141 jQuery.fn.extend({
       
  7142 	addClass: function( value ) {
       
  7143 		var classes, elem, cur, clazz, j, finalValue,
       
  7144 			proceed = typeof value === "string" && value,
       
  7145 			i = 0,
       
  7146 			len = this.length;
       
  7147 
       
  7148 		if ( jQuery.isFunction( value ) ) {
       
  7149 			return this.each(function( j ) {
       
  7150 				jQuery( this ).addClass( value.call( this, j, this.className ) );
       
  7151 			});
       
  7152 		}
       
  7153 
       
  7154 		if ( proceed ) {
       
  7155 			// The disjunction here is for better compressibility (see removeClass)
       
  7156 			classes = ( value || "" ).match( rnotwhite ) || [];
       
  7157 
       
  7158 			for ( ; i < len; i++ ) {
       
  7159 				elem = this[ i ];
       
  7160 				cur = elem.nodeType === 1 && ( elem.className ?
       
  7161 					( " " + elem.className + " " ).replace( rclass, " " ) :
       
  7162 					" "
       
  7163 				);
       
  7164 
       
  7165 				if ( cur ) {
       
  7166 					j = 0;
       
  7167 					while ( (clazz = classes[j++]) ) {
       
  7168 						if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
       
  7169 							cur += clazz + " ";
       
  7170 						}
       
  7171 					}
       
  7172 
       
  7173 					// only assign if different to avoid unneeded rendering.
       
  7174 					finalValue = jQuery.trim( cur );
       
  7175 					if ( elem.className !== finalValue ) {
       
  7176 						elem.className = finalValue;
       
  7177 					}
       
  7178 				}
       
  7179 			}
       
  7180 		}
       
  7181 
       
  7182 		return this;
       
  7183 	},
       
  7184 
       
  7185 	removeClass: function( value ) {
       
  7186 		var classes, elem, cur, clazz, j, finalValue,
       
  7187 			proceed = arguments.length === 0 || typeof value === "string" && value,
       
  7188 			i = 0,
       
  7189 			len = this.length;
       
  7190 
       
  7191 		if ( jQuery.isFunction( value ) ) {
       
  7192 			return this.each(function( j ) {
       
  7193 				jQuery( this ).removeClass( value.call( this, j, this.className ) );
       
  7194 			});
       
  7195 		}
       
  7196 		if ( proceed ) {
       
  7197 			classes = ( value || "" ).match( rnotwhite ) || [];
       
  7198 
       
  7199 			for ( ; i < len; i++ ) {
       
  7200 				elem = this[ i ];
       
  7201 				// This expression is here for better compressibility (see addClass)
       
  7202 				cur = elem.nodeType === 1 && ( elem.className ?
       
  7203 					( " " + elem.className + " " ).replace( rclass, " " ) :
       
  7204 					""
       
  7205 				);
       
  7206 
       
  7207 				if ( cur ) {
       
  7208 					j = 0;
       
  7209 					while ( (clazz = classes[j++]) ) {
       
  7210 						// Remove *all* instances
       
  7211 						while ( cur.indexOf( " " + clazz + " " ) >= 0 ) {
       
  7212 							cur = cur.replace( " " + clazz + " ", " " );
       
  7213 						}
       
  7214 					}
       
  7215 
       
  7216 					// only assign if different to avoid unneeded rendering.
       
  7217 					finalValue = value ? jQuery.trim( cur ) : "";
       
  7218 					if ( elem.className !== finalValue ) {
       
  7219 						elem.className = finalValue;
       
  7220 					}
       
  7221 				}
       
  7222 			}
       
  7223 		}
       
  7224 
       
  7225 		return this;
       
  7226 	},
       
  7227 
       
  7228 	toggleClass: function( value, stateVal ) {
       
  7229 		var type = typeof value;
       
  7230 
       
  7231 		if ( typeof stateVal === "boolean" && type === "string" ) {
       
  7232 			return stateVal ? this.addClass( value ) : this.removeClass( value );
       
  7233 		}
       
  7234 
       
  7235 		if ( jQuery.isFunction( value ) ) {
       
  7236 			return this.each(function( i ) {
       
  7237 				jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
       
  7238 			});
       
  7239 		}
       
  7240 
       
  7241 		return this.each(function() {
       
  7242 			if ( type === "string" ) {
       
  7243 				// toggle individual class names
       
  7244 				var className,
       
  7245 					i = 0,
       
  7246 					self = jQuery( this ),
       
  7247 					classNames = value.match( rnotwhite ) || [];
       
  7248 
       
  7249 				while ( (className = classNames[ i++ ]) ) {
       
  7250 					// check each className given, space separated list
       
  7251 					if ( self.hasClass( className ) ) {
       
  7252 						self.removeClass( className );
       
  7253 					} else {
       
  7254 						self.addClass( className );
       
  7255 					}
       
  7256 				}
       
  7257 
       
  7258 			// Toggle whole class name
       
  7259 			} else if ( type === strundefined || type === "boolean" ) {
       
  7260 				if ( this.className ) {
       
  7261 					// store className if set
       
  7262 					data_priv.set( this, "__className__", this.className );
       
  7263 				}
       
  7264 
       
  7265 				// If the element has a class name or if we're passed "false",
       
  7266 				// then remove the whole classname (if there was one, the above saved it).
       
  7267 				// Otherwise bring back whatever was previously saved (if anything),
       
  7268 				// falling back to the empty string if nothing was stored.
       
  7269 				this.className = this.className || value === false ? "" : data_priv.get( this, "__className__" ) || "";
       
  7270 			}
       
  7271 		});
       
  7272 	},
       
  7273 
       
  7274 	hasClass: function( selector ) {
       
  7275 		var className = " " + selector + " ",
       
  7276 			i = 0,
       
  7277 			l = this.length;
       
  7278 		for ( ; i < l; i++ ) {
       
  7279 			if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
       
  7280 				return true;
       
  7281 			}
       
  7282 		}
       
  7283 
       
  7284 		return false;
       
  7285 	}
       
  7286 });
       
  7287 
       
  7288 
       
  7289 
       
  7290 
       
  7291 var rreturn = /\r/g;
       
  7292 
       
  7293 jQuery.fn.extend({
       
  7294 	val: function( value ) {
       
  7295 		var hooks, ret, isFunction,
       
  7296 			elem = this[0];
       
  7297 
       
  7298 		if ( !arguments.length ) {
       
  7299 			if ( elem ) {
       
  7300 				hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
       
  7301 
       
  7302 				if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
       
  7303 					return ret;
       
  7304 				}
       
  7305 
       
  7306 				ret = elem.value;
       
  7307 
       
  7308 				return typeof ret === "string" ?
       
  7309 					// handle most common string cases
       
  7310 					ret.replace(rreturn, "") :
       
  7311 					// handle cases where value is null/undef or number
       
  7312 					ret == null ? "" : ret;
       
  7313 			}
       
  7314 
       
  7315 			return;
       
  7316 		}
       
  7317 
       
  7318 		isFunction = jQuery.isFunction( value );
       
  7319 
       
  7320 		return this.each(function( i ) {
       
  7321 			var val;
       
  7322 
       
  7323 			if ( this.nodeType !== 1 ) {
       
  7324 				return;
       
  7325 			}
       
  7326 
       
  7327 			if ( isFunction ) {
       
  7328 				val = value.call( this, i, jQuery( this ).val() );
       
  7329 			} else {
       
  7330 				val = value;
       
  7331 			}
       
  7332 
       
  7333 			// Treat null/undefined as ""; convert numbers to string
       
  7334 			if ( val == null ) {
       
  7335 				val = "";
       
  7336 
       
  7337 			} else if ( typeof val === "number" ) {
       
  7338 				val += "";
       
  7339 
       
  7340 			} else if ( jQuery.isArray( val ) ) {
       
  7341 				val = jQuery.map( val, function( value ) {
       
  7342 					return value == null ? "" : value + "";
       
  7343 				});
       
  7344 			}
       
  7345 
       
  7346 			hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
       
  7347 
       
  7348 			// If set returns undefined, fall back to normal setting
       
  7349 			if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
       
  7350 				this.value = val;
       
  7351 			}
       
  7352 		});
       
  7353 	}
       
  7354 });
       
  7355 
       
  7356 jQuery.extend({
       
  7357 	valHooks: {
       
  7358 		option: {
       
  7359 			get: function( elem ) {
       
  7360 				var val = jQuery.find.attr( elem, "value" );
       
  7361 				return val != null ?
       
  7362 					val :
       
  7363 					// Support: IE10-11+
       
  7364 					// option.text throws exceptions (#14686, #14858)
       
  7365 					jQuery.trim( jQuery.text( elem ) );
       
  7366 			}
       
  7367 		},
       
  7368 		select: {
       
  7369 			get: function( elem ) {
       
  7370 				var value, option,
       
  7371 					options = elem.options,
       
  7372 					index = elem.selectedIndex,
       
  7373 					one = elem.type === "select-one" || index < 0,
       
  7374 					values = one ? null : [],
       
  7375 					max = one ? index + 1 : options.length,
       
  7376 					i = index < 0 ?
       
  7377 						max :
       
  7378 						one ? index : 0;
       
  7379 
       
  7380 				// Loop through all the selected options
       
  7381 				for ( ; i < max; i++ ) {
       
  7382 					option = options[ i ];
       
  7383 
       
  7384 					// IE6-9 doesn't update selected after form reset (#2551)
       
  7385 					if ( ( option.selected || i === index ) &&
       
  7386 							// Don't return options that are disabled or in a disabled optgroup
       
  7387 							( support.optDisabled ? !option.disabled : option.getAttribute( "disabled" ) === null ) &&
       
  7388 							( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
       
  7389 
       
  7390 						// Get the specific value for the option
       
  7391 						value = jQuery( option ).val();
       
  7392 
       
  7393 						// We don't need an array for one selects
       
  7394 						if ( one ) {
       
  7395 							return value;
       
  7396 						}
       
  7397 
       
  7398 						// Multi-Selects return an array
       
  7399 						values.push( value );
       
  7400 					}
       
  7401 				}
       
  7402 
       
  7403 				return values;
       
  7404 			},
       
  7405 
       
  7406 			set: function( elem, value ) {
       
  7407 				var optionSet, option,
       
  7408 					options = elem.options,
       
  7409 					values = jQuery.makeArray( value ),
       
  7410 					i = options.length;
       
  7411 
       
  7412 				while ( i-- ) {
       
  7413 					option = options[ i ];
       
  7414 					if ( (option.selected = jQuery.inArray( option.value, values ) >= 0) ) {
       
  7415 						optionSet = true;
       
  7416 					}
       
  7417 				}
       
  7418 
       
  7419 				// force browsers to behave consistently when non-matching value is set
       
  7420 				if ( !optionSet ) {
       
  7421 					elem.selectedIndex = -1;
       
  7422 				}
       
  7423 				return values;
       
  7424 			}
       
  7425 		}
       
  7426 	}
       
  7427 });
       
  7428 
       
  7429 // Radios and checkboxes getter/setter
       
  7430 jQuery.each([ "radio", "checkbox" ], function() {
       
  7431 	jQuery.valHooks[ this ] = {
       
  7432 		set: function( elem, value ) {
       
  7433 			if ( jQuery.isArray( value ) ) {
       
  7434 				return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
       
  7435 			}
       
  7436 		}
       
  7437 	};
       
  7438 	if ( !support.checkOn ) {
       
  7439 		jQuery.valHooks[ this ].get = function( elem ) {
       
  7440 			// Support: Webkit
       
  7441 			// "" is returned instead of "on" if a value isn't specified
       
  7442 			return elem.getAttribute("value") === null ? "on" : elem.value;
       
  7443 		};
       
  7444 	}
       
  7445 });
       
  7446 
       
  7447 
       
  7448 
       
  7449 
       
  7450 // Return jQuery for attributes-only inclusion
       
  7451 
       
  7452 
       
  7453 jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
       
  7454 	"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
       
  7455 	"change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
       
  7456 
       
  7457 	// Handle event binding
       
  7458 	jQuery.fn[ name ] = function( data, fn ) {
       
  7459 		return arguments.length > 0 ?
       
  7460 			this.on( name, null, data, fn ) :
       
  7461 			this.trigger( name );
       
  7462 	};
       
  7463 });
       
  7464 
       
  7465 jQuery.fn.extend({
       
  7466 	hover: function( fnOver, fnOut ) {
       
  7467 		return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
       
  7468 	},
       
  7469 
       
  7470 	bind: function( types, data, fn ) {
       
  7471 		return this.on( types, null, data, fn );
       
  7472 	},
       
  7473 	unbind: function( types, fn ) {
       
  7474 		return this.off( types, null, fn );
       
  7475 	},
       
  7476 
       
  7477 	delegate: function( selector, types, data, fn ) {
       
  7478 		return this.on( types, selector, data, fn );
       
  7479 	},
       
  7480 	undelegate: function( selector, types, fn ) {
       
  7481 		// ( namespace ) or ( selector, types [, fn] )
       
  7482 		return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
       
  7483 	}
       
  7484 });
       
  7485 
       
  7486 
       
  7487 var nonce = jQuery.now();
       
  7488 
       
  7489 var rquery = (/\?/);
       
  7490 
       
  7491 
       
  7492 
       
  7493 // Support: Android 2.3
       
  7494 // Workaround failure to string-cast null input
       
  7495 jQuery.parseJSON = function( data ) {
       
  7496 	return JSON.parse( data + "" );
       
  7497 };
       
  7498 
       
  7499 
       
  7500 // Cross-browser xml parsing
       
  7501 jQuery.parseXML = function( data ) {
       
  7502 	var xml, tmp;
       
  7503 	if ( !data || typeof data !== "string" ) {
       
  7504 		return null;
       
  7505 	}
       
  7506 
       
  7507 	// Support: IE9
       
  7508 	try {
       
  7509 		tmp = new DOMParser();
       
  7510 		xml = tmp.parseFromString( data, "text/xml" );
       
  7511 	} catch ( e ) {
       
  7512 		xml = undefined;
       
  7513 	}
       
  7514 
       
  7515 	if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) {
       
  7516 		jQuery.error( "Invalid XML: " + data );
       
  7517 	}
       
  7518 	return xml;
       
  7519 };
       
  7520 
       
  7521 
       
  7522 var
       
  7523 	// Document location
       
  7524 	ajaxLocParts,
       
  7525 	ajaxLocation,
       
  7526 
       
  7527 	rhash = /#.*$/,
       
  7528 	rts = /([?&])_=[^&]*/,
       
  7529 	rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg,
       
  7530 	// #7653, #8125, #8152: local protocol detection
       
  7531 	rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
       
  7532 	rnoContent = /^(?:GET|HEAD)$/,
       
  7533 	rprotocol = /^\/\//,
       
  7534 	rurl = /^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,
       
  7535 
       
  7536 	/* Prefilters
       
  7537 	 * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
       
  7538 	 * 2) These are called:
       
  7539 	 *    - BEFORE asking for a transport
       
  7540 	 *    - AFTER param serialization (s.data is a string if s.processData is true)
       
  7541 	 * 3) key is the dataType
       
  7542 	 * 4) the catchall symbol "*" can be used
       
  7543 	 * 5) execution will start with transport dataType and THEN continue down to "*" if needed
       
  7544 	 */
       
  7545 	prefilters = {},
       
  7546 
       
  7547 	/* Transports bindings
       
  7548 	 * 1) key is the dataType
       
  7549 	 * 2) the catchall symbol "*" can be used
       
  7550 	 * 3) selection will start with transport dataType and THEN go to "*" if needed
       
  7551 	 */
       
  7552 	transports = {},
       
  7553 
       
  7554 	// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
       
  7555 	allTypes = "*/".concat("*");
       
  7556 
       
  7557 // #8138, IE may throw an exception when accessing
       
  7558 // a field from window.location if document.domain has been set
       
  7559 try {
       
  7560 	ajaxLocation = location.href;
       
  7561 } catch( e ) {
       
  7562 	// Use the href attribute of an A element
       
  7563 	// since IE will modify it given document.location
       
  7564 	ajaxLocation = document.createElement( "a" );
       
  7565 	ajaxLocation.href = "";
       
  7566 	ajaxLocation = ajaxLocation.href;
       
  7567 }
       
  7568 
       
  7569 // Segment location into parts
       
  7570 ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
       
  7571 
       
  7572 // Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
       
  7573 function addToPrefiltersOrTransports( structure ) {
       
  7574 
       
  7575 	// dataTypeExpression is optional and defaults to "*"
       
  7576 	return function( dataTypeExpression, func ) {
       
  7577 
       
  7578 		if ( typeof dataTypeExpression !== "string" ) {
       
  7579 			func = dataTypeExpression;
       
  7580 			dataTypeExpression = "*";
       
  7581 		}
       
  7582 
       
  7583 		var dataType,
       
  7584 			i = 0,
       
  7585 			dataTypes = dataTypeExpression.toLowerCase().match( rnotwhite ) || [];
       
  7586 
       
  7587 		if ( jQuery.isFunction( func ) ) {
       
  7588 			// For each dataType in the dataTypeExpression
       
  7589 			while ( (dataType = dataTypes[i++]) ) {
       
  7590 				// Prepend if requested
       
  7591 				if ( dataType[0] === "+" ) {
       
  7592 					dataType = dataType.slice( 1 ) || "*";
       
  7593 					(structure[ dataType ] = structure[ dataType ] || []).unshift( func );
       
  7594 
       
  7595 				// Otherwise append
       
  7596 				} else {
       
  7597 					(structure[ dataType ] = structure[ dataType ] || []).push( func );
       
  7598 				}
       
  7599 			}
       
  7600 		}
       
  7601 	};
       
  7602 }
       
  7603 
       
  7604 // Base inspection function for prefilters and transports
       
  7605 function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
       
  7606 
       
  7607 	var inspected = {},
       
  7608 		seekingTransport = ( structure === transports );
       
  7609 
       
  7610 	function inspect( dataType ) {
       
  7611 		var selected;
       
  7612 		inspected[ dataType ] = true;
       
  7613 		jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
       
  7614 			var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
       
  7615 			if ( typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {
       
  7616 				options.dataTypes.unshift( dataTypeOrTransport );
       
  7617 				inspect( dataTypeOrTransport );
       
  7618 				return false;
       
  7619 			} else if ( seekingTransport ) {
       
  7620 				return !( selected = dataTypeOrTransport );
       
  7621 			}
       
  7622 		});
       
  7623 		return selected;
       
  7624 	}
       
  7625 
       
  7626 	return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
       
  7627 }
       
  7628 
       
  7629 // A special extend for ajax options
       
  7630 // that takes "flat" options (not to be deep extended)
       
  7631 // Fixes #9887
       
  7632 function ajaxExtend( target, src ) {
       
  7633 	var key, deep,
       
  7634 		flatOptions = jQuery.ajaxSettings.flatOptions || {};
       
  7635 
       
  7636 	for ( key in src ) {
       
  7637 		if ( src[ key ] !== undefined ) {
       
  7638 			( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ];
       
  7639 		}
       
  7640 	}
       
  7641 	if ( deep ) {
       
  7642 		jQuery.extend( true, target, deep );
       
  7643 	}
       
  7644 
       
  7645 	return target;
       
  7646 }
       
  7647 
       
  7648 /* Handles responses to an ajax request:
       
  7649  * - finds the right dataType (mediates between content-type and expected dataType)
       
  7650  * - returns the corresponding response
       
  7651  */
       
  7652 function ajaxHandleResponses( s, jqXHR, responses ) {
       
  7653 
       
  7654 	var ct, type, finalDataType, firstDataType,
       
  7655 		contents = s.contents,
       
  7656 		dataTypes = s.dataTypes;
       
  7657 
       
  7658 	// Remove auto dataType and get content-type in the process
       
  7659 	while ( dataTypes[ 0 ] === "*" ) {
       
  7660 		dataTypes.shift();
       
  7661 		if ( ct === undefined ) {
       
  7662 			ct = s.mimeType || jqXHR.getResponseHeader("Content-Type");
       
  7663 		}
       
  7664 	}
       
  7665 
       
  7666 	// Check if we're dealing with a known content-type
       
  7667 	if ( ct ) {
       
  7668 		for ( type in contents ) {
       
  7669 			if ( contents[ type ] && contents[ type ].test( ct ) ) {
       
  7670 				dataTypes.unshift( type );
       
  7671 				break;
       
  7672 			}
       
  7673 		}
       
  7674 	}
       
  7675 
       
  7676 	// Check to see if we have a response for the expected dataType
       
  7677 	if ( dataTypes[ 0 ] in responses ) {
       
  7678 		finalDataType = dataTypes[ 0 ];
       
  7679 	} else {
       
  7680 		// Try convertible dataTypes
       
  7681 		for ( type in responses ) {
       
  7682 			if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
       
  7683 				finalDataType = type;
       
  7684 				break;
       
  7685 			}
       
  7686 			if ( !firstDataType ) {
       
  7687 				firstDataType = type;
       
  7688 			}
       
  7689 		}
       
  7690 		// Or just use first one
       
  7691 		finalDataType = finalDataType || firstDataType;
       
  7692 	}
       
  7693 
       
  7694 	// If we found a dataType
       
  7695 	// We add the dataType to the list if needed
       
  7696 	// and return the corresponding response
       
  7697 	if ( finalDataType ) {
       
  7698 		if ( finalDataType !== dataTypes[ 0 ] ) {
       
  7699 			dataTypes.unshift( finalDataType );
       
  7700 		}
       
  7701 		return responses[ finalDataType ];
       
  7702 	}
       
  7703 }
       
  7704 
       
  7705 /* Chain conversions given the request and the original response
       
  7706  * Also sets the responseXXX fields on the jqXHR instance
       
  7707  */
       
  7708 function ajaxConvert( s, response, jqXHR, isSuccess ) {
       
  7709 	var conv2, current, conv, tmp, prev,
       
  7710 		converters = {},
       
  7711 		// Work with a copy of dataTypes in case we need to modify it for conversion
       
  7712 		dataTypes = s.dataTypes.slice();
       
  7713 
       
  7714 	// Create converters map with lowercased keys
       
  7715 	if ( dataTypes[ 1 ] ) {
       
  7716 		for ( conv in s.converters ) {
       
  7717 			converters[ conv.toLowerCase() ] = s.converters[ conv ];
       
  7718 		}
       
  7719 	}
       
  7720 
       
  7721 	current = dataTypes.shift();
       
  7722 
       
  7723 	// Convert to each sequential dataType
       
  7724 	while ( current ) {
       
  7725 
       
  7726 		if ( s.responseFields[ current ] ) {
       
  7727 			jqXHR[ s.responseFields[ current ] ] = response;
       
  7728 		}
       
  7729 
       
  7730 		// Apply the dataFilter if provided
       
  7731 		if ( !prev && isSuccess && s.dataFilter ) {
       
  7732 			response = s.dataFilter( response, s.dataType );
       
  7733 		}
       
  7734 
       
  7735 		prev = current;
       
  7736 		current = dataTypes.shift();
       
  7737 
       
  7738 		if ( current ) {
       
  7739 
       
  7740 		// There's only work to do if current dataType is non-auto
       
  7741 			if ( current === "*" ) {
       
  7742 
       
  7743 				current = prev;
       
  7744 
       
  7745 			// Convert response if prev dataType is non-auto and differs from current
       
  7746 			} else if ( prev !== "*" && prev !== current ) {
       
  7747 
       
  7748 				// Seek a direct converter
       
  7749 				conv = converters[ prev + " " + current ] || converters[ "* " + current ];
       
  7750 
       
  7751 				// If none found, seek a pair
       
  7752 				if ( !conv ) {
       
  7753 					for ( conv2 in converters ) {
       
  7754 
       
  7755 						// If conv2 outputs current
       
  7756 						tmp = conv2.split( " " );
       
  7757 						if ( tmp[ 1 ] === current ) {
       
  7758 
       
  7759 							// If prev can be converted to accepted input
       
  7760 							conv = converters[ prev + " " + tmp[ 0 ] ] ||
       
  7761 								converters[ "* " + tmp[ 0 ] ];
       
  7762 							if ( conv ) {
       
  7763 								// Condense equivalence converters
       
  7764 								if ( conv === true ) {
       
  7765 									conv = converters[ conv2 ];
       
  7766 
       
  7767 								// Otherwise, insert the intermediate dataType
       
  7768 								} else if ( converters[ conv2 ] !== true ) {
       
  7769 									current = tmp[ 0 ];
       
  7770 									dataTypes.unshift( tmp[ 1 ] );
       
  7771 								}
       
  7772 								break;
       
  7773 							}
       
  7774 						}
       
  7775 					}
       
  7776 				}
       
  7777 
       
  7778 				// Apply converter (if not an equivalence)
       
  7779 				if ( conv !== true ) {
       
  7780 
       
  7781 					// Unless errors are allowed to bubble, catch and return them
       
  7782 					if ( conv && s[ "throws" ] ) {
       
  7783 						response = conv( response );
       
  7784 					} else {
       
  7785 						try {
       
  7786 							response = conv( response );
       
  7787 						} catch ( e ) {
       
  7788 							return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current };
       
  7789 						}
       
  7790 					}
       
  7791 				}
       
  7792 			}
       
  7793 		}
       
  7794 	}
       
  7795 
       
  7796 	return { state: "success", data: response };
       
  7797 }
       
  7798 
       
  7799 jQuery.extend({
       
  7800 
       
  7801 	// Counter for holding the number of active queries
       
  7802 	active: 0,
       
  7803 
       
  7804 	// Last-Modified header cache for next request
       
  7805 	lastModified: {},
       
  7806 	etag: {},
       
  7807 
       
  7808 	ajaxSettings: {
       
  7809 		url: ajaxLocation,
       
  7810 		type: "GET",
       
  7811 		isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
       
  7812 		global: true,
       
  7813 		processData: true,
       
  7814 		async: true,
       
  7815 		contentType: "application/x-www-form-urlencoded; charset=UTF-8",
       
  7816 		/*
       
  7817 		timeout: 0,
       
  7818 		data: null,
       
  7819 		dataType: null,
       
  7820 		username: null,
       
  7821 		password: null,
       
  7822 		cache: null,
       
  7823 		throws: false,
       
  7824 		traditional: false,
       
  7825 		headers: {},
       
  7826 		*/
       
  7827 
       
  7828 		accepts: {
       
  7829 			"*": allTypes,
       
  7830 			text: "text/plain",
       
  7831 			html: "text/html",
       
  7832 			xml: "application/xml, text/xml",
       
  7833 			json: "application/json, text/javascript"
       
  7834 		},
       
  7835 
       
  7836 		contents: {
       
  7837 			xml: /xml/,
       
  7838 			html: /html/,
       
  7839 			json: /json/
       
  7840 		},
       
  7841 
       
  7842 		responseFields: {
       
  7843 			xml: "responseXML",
       
  7844 			text: "responseText",
       
  7845 			json: "responseJSON"
       
  7846 		},
       
  7847 
       
  7848 		// Data converters
       
  7849 		// Keys separate source (or catchall "*") and destination types with a single space
       
  7850 		converters: {
       
  7851 
       
  7852 			// Convert anything to text
       
  7853 			"* text": String,
       
  7854 
       
  7855 			// Text to html (true = no transformation)
       
  7856 			"text html": true,
       
  7857 
       
  7858 			// Evaluate text as a json expression
       
  7859 			"text json": jQuery.parseJSON,
       
  7860 
       
  7861 			// Parse text as xml
       
  7862 			"text xml": jQuery.parseXML
       
  7863 		},
       
  7864 
       
  7865 		// For options that shouldn't be deep extended:
       
  7866 		// you can add your own custom options here if
       
  7867 		// and when you create one that shouldn't be
       
  7868 		// deep extended (see ajaxExtend)
       
  7869 		flatOptions: {
       
  7870 			url: true,
       
  7871 			context: true
       
  7872 		}
       
  7873 	},
       
  7874 
       
  7875 	// Creates a full fledged settings object into target
       
  7876 	// with both ajaxSettings and settings fields.
       
  7877 	// If target is omitted, writes into ajaxSettings.
       
  7878 	ajaxSetup: function( target, settings ) {
       
  7879 		return settings ?
       
  7880 
       
  7881 			// Building a settings object
       
  7882 			ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
       
  7883 
       
  7884 			// Extending ajaxSettings
       
  7885 			ajaxExtend( jQuery.ajaxSettings, target );
       
  7886 	},
       
  7887 
       
  7888 	ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
       
  7889 	ajaxTransport: addToPrefiltersOrTransports( transports ),
       
  7890 
       
  7891 	// Main method
       
  7892 	ajax: function( url, options ) {
       
  7893 
       
  7894 		// If url is an object, simulate pre-1.5 signature
       
  7895 		if ( typeof url === "object" ) {
       
  7896 			options = url;
       
  7897 			url = undefined;
       
  7898 		}
       
  7899 
       
  7900 		// Force options to be an object
       
  7901 		options = options || {};
       
  7902 
       
  7903 		var transport,
       
  7904 			// URL without anti-cache param
       
  7905 			cacheURL,
       
  7906 			// Response headers
       
  7907 			responseHeadersString,
       
  7908 			responseHeaders,
       
  7909 			// timeout handle
       
  7910 			timeoutTimer,
       
  7911 			// Cross-domain detection vars
       
  7912 			parts,
       
  7913 			// To know if global events are to be dispatched
       
  7914 			fireGlobals,
       
  7915 			// Loop variable
       
  7916 			i,
       
  7917 			// Create the final options object
       
  7918 			s = jQuery.ajaxSetup( {}, options ),
       
  7919 			// Callbacks context
       
  7920 			callbackContext = s.context || s,
       
  7921 			// Context for global events is callbackContext if it is a DOM node or jQuery collection
       
  7922 			globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?
       
  7923 				jQuery( callbackContext ) :
       
  7924 				jQuery.event,
       
  7925 			// Deferreds
       
  7926 			deferred = jQuery.Deferred(),
       
  7927 			completeDeferred = jQuery.Callbacks("once memory"),
       
  7928 			// Status-dependent callbacks
       
  7929 			statusCode = s.statusCode || {},
       
  7930 			// Headers (they are sent all at once)
       
  7931 			requestHeaders = {},
       
  7932 			requestHeadersNames = {},
       
  7933 			// The jqXHR state
       
  7934 			state = 0,
       
  7935 			// Default abort message
       
  7936 			strAbort = "canceled",
       
  7937 			// Fake xhr
       
  7938 			jqXHR = {
       
  7939 				readyState: 0,
       
  7940 
       
  7941 				// Builds headers hashtable if needed
       
  7942 				getResponseHeader: function( key ) {
       
  7943 					var match;
       
  7944 					if ( state === 2 ) {
       
  7945 						if ( !responseHeaders ) {
       
  7946 							responseHeaders = {};
       
  7947 							while ( (match = rheaders.exec( responseHeadersString )) ) {
       
  7948 								responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
       
  7949 							}
       
  7950 						}
       
  7951 						match = responseHeaders[ key.toLowerCase() ];
       
  7952 					}
       
  7953 					return match == null ? null : match;
       
  7954 				},
       
  7955 
       
  7956 				// Raw string
       
  7957 				getAllResponseHeaders: function() {
       
  7958 					return state === 2 ? responseHeadersString : null;
       
  7959 				},
       
  7960 
       
  7961 				// Caches the header
       
  7962 				setRequestHeader: function( name, value ) {
       
  7963 					var lname = name.toLowerCase();
       
  7964 					if ( !state ) {
       
  7965 						name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
       
  7966 						requestHeaders[ name ] = value;
       
  7967 					}
       
  7968 					return this;
       
  7969 				},
       
  7970 
       
  7971 				// Overrides response content-type header
       
  7972 				overrideMimeType: function( type ) {
       
  7973 					if ( !state ) {
       
  7974 						s.mimeType = type;
       
  7975 					}
       
  7976 					return this;
       
  7977 				},
       
  7978 
       
  7979 				// Status-dependent callbacks
       
  7980 				statusCode: function( map ) {
       
  7981 					var code;
       
  7982 					if ( map ) {
       
  7983 						if ( state < 2 ) {
       
  7984 							for ( code in map ) {
       
  7985 								// Lazy-add the new callback in a way that preserves old ones
       
  7986 								statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
       
  7987 							}
       
  7988 						} else {
       
  7989 							// Execute the appropriate callbacks
       
  7990 							jqXHR.always( map[ jqXHR.status ] );
       
  7991 						}
       
  7992 					}
       
  7993 					return this;
       
  7994 				},
       
  7995 
       
  7996 				// Cancel the request
       
  7997 				abort: function( statusText ) {
       
  7998 					var finalText = statusText || strAbort;
       
  7999 					if ( transport ) {
       
  8000 						transport.abort( finalText );
       
  8001 					}
       
  8002 					done( 0, finalText );
       
  8003 					return this;
       
  8004 				}
       
  8005 			};
       
  8006 
       
  8007 		// Attach deferreds
       
  8008 		deferred.promise( jqXHR ).complete = completeDeferred.add;
       
  8009 		jqXHR.success = jqXHR.done;
       
  8010 		jqXHR.error = jqXHR.fail;
       
  8011 
       
  8012 		// Remove hash character (#7531: and string promotion)
       
  8013 		// Add protocol if not provided (prefilters might expect it)
       
  8014 		// Handle falsy url in the settings object (#10093: consistency with old signature)
       
  8015 		// We also use the url parameter if available
       
  8016 		s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" )
       
  8017 			.replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
       
  8018 
       
  8019 		// Alias method option to type as per ticket #12004
       
  8020 		s.type = options.method || options.type || s.method || s.type;
       
  8021 
       
  8022 		// Extract dataTypes list
       
  8023 		s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( rnotwhite ) || [ "" ];
       
  8024 
       
  8025 		// A cross-domain request is in order when we have a protocol:host:port mismatch
       
  8026 		if ( s.crossDomain == null ) {
       
  8027 			parts = rurl.exec( s.url.toLowerCase() );
       
  8028 			s.crossDomain = !!( parts &&
       
  8029 				( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
       
  8030 					( parts[ 3 ] || ( parts[ 1 ] === "http:" ? "80" : "443" ) ) !==
       
  8031 						( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? "80" : "443" ) ) )
       
  8032 			);
       
  8033 		}
       
  8034 
       
  8035 		// Convert data if not already a string
       
  8036 		if ( s.data && s.processData && typeof s.data !== "string" ) {
       
  8037 			s.data = jQuery.param( s.data, s.traditional );
       
  8038 		}
       
  8039 
       
  8040 		// Apply prefilters
       
  8041 		inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
       
  8042 
       
  8043 		// If request was aborted inside a prefilter, stop there
       
  8044 		if ( state === 2 ) {
       
  8045 			return jqXHR;
       
  8046 		}
       
  8047 
       
  8048 		// We can fire global events as of now if asked to
       
  8049 		fireGlobals = s.global;
       
  8050 
       
  8051 		// Watch for a new set of requests
       
  8052 		if ( fireGlobals && jQuery.active++ === 0 ) {
       
  8053 			jQuery.event.trigger("ajaxStart");
       
  8054 		}
       
  8055 
       
  8056 		// Uppercase the type
       
  8057 		s.type = s.type.toUpperCase();
       
  8058 
       
  8059 		// Determine if request has content
       
  8060 		s.hasContent = !rnoContent.test( s.type );
       
  8061 
       
  8062 		// Save the URL in case we're toying with the If-Modified-Since
       
  8063 		// and/or If-None-Match header later on
       
  8064 		cacheURL = s.url;
       
  8065 
       
  8066 		// More options handling for requests with no content
       
  8067 		if ( !s.hasContent ) {
       
  8068 
       
  8069 			// If data is available, append data to url
       
  8070 			if ( s.data ) {
       
  8071 				cacheURL = ( s.url += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data );
       
  8072 				// #9682: remove data so that it's not used in an eventual retry
       
  8073 				delete s.data;
       
  8074 			}
       
  8075 
       
  8076 			// Add anti-cache in url if needed
       
  8077 			if ( s.cache === false ) {
       
  8078 				s.url = rts.test( cacheURL ) ?
       
  8079 
       
  8080 					// If there is already a '_' parameter, set its value
       
  8081 					cacheURL.replace( rts, "$1_=" + nonce++ ) :
       
  8082 
       
  8083 					// Otherwise add one to the end
       
  8084 					cacheURL + ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + nonce++;
       
  8085 			}
       
  8086 		}
       
  8087 
       
  8088 		// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
       
  8089 		if ( s.ifModified ) {
       
  8090 			if ( jQuery.lastModified[ cacheURL ] ) {
       
  8091 				jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
       
  8092 			}
       
  8093 			if ( jQuery.etag[ cacheURL ] ) {
       
  8094 				jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
       
  8095 			}
       
  8096 		}
       
  8097 
       
  8098 		// Set the correct header, if data is being sent
       
  8099 		if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
       
  8100 			jqXHR.setRequestHeader( "Content-Type", s.contentType );
       
  8101 		}
       
  8102 
       
  8103 		// Set the Accepts header for the server, depending on the dataType
       
  8104 		jqXHR.setRequestHeader(
       
  8105 			"Accept",
       
  8106 			s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
       
  8107 				s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
       
  8108 				s.accepts[ "*" ]
       
  8109 		);
       
  8110 
       
  8111 		// Check for headers option
       
  8112 		for ( i in s.headers ) {
       
  8113 			jqXHR.setRequestHeader( i, s.headers[ i ] );
       
  8114 		}
       
  8115 
       
  8116 		// Allow custom headers/mimetypes and early abort
       
  8117 		if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
       
  8118 			// Abort if not done already and return
       
  8119 			return jqXHR.abort();
       
  8120 		}
       
  8121 
       
  8122 		// aborting is no longer a cancellation
       
  8123 		strAbort = "abort";
       
  8124 
       
  8125 		// Install callbacks on deferreds
       
  8126 		for ( i in { success: 1, error: 1, complete: 1 } ) {
       
  8127 			jqXHR[ i ]( s[ i ] );
       
  8128 		}
       
  8129 
       
  8130 		// Get transport
       
  8131 		transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
       
  8132 
       
  8133 		// If no transport, we auto-abort
       
  8134 		if ( !transport ) {
       
  8135 			done( -1, "No Transport" );
       
  8136 		} else {
       
  8137 			jqXHR.readyState = 1;
       
  8138 
       
  8139 			// Send global event
       
  8140 			if ( fireGlobals ) {
       
  8141 				globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
       
  8142 			}
       
  8143 			// Timeout
       
  8144 			if ( s.async && s.timeout > 0 ) {
       
  8145 				timeoutTimer = setTimeout(function() {
       
  8146 					jqXHR.abort("timeout");
       
  8147 				}, s.timeout );
       
  8148 			}
       
  8149 
       
  8150 			try {
       
  8151 				state = 1;
       
  8152 				transport.send( requestHeaders, done );
       
  8153 			} catch ( e ) {
       
  8154 				// Propagate exception as error if not done
       
  8155 				if ( state < 2 ) {
       
  8156 					done( -1, e );
       
  8157 				// Simply rethrow otherwise
       
  8158 				} else {
       
  8159 					throw e;
       
  8160 				}
       
  8161 			}
       
  8162 		}
       
  8163 
       
  8164 		// Callback for when everything is done
       
  8165 		function done( status, nativeStatusText, responses, headers ) {
       
  8166 			var isSuccess, success, error, response, modified,
       
  8167 				statusText = nativeStatusText;
       
  8168 
       
  8169 			// Called once
       
  8170 			if ( state === 2 ) {
       
  8171 				return;
       
  8172 			}
       
  8173 
       
  8174 			// State is "done" now
       
  8175 			state = 2;
       
  8176 
       
  8177 			// Clear timeout if it exists
       
  8178 			if ( timeoutTimer ) {
       
  8179 				clearTimeout( timeoutTimer );
       
  8180 			}
       
  8181 
       
  8182 			// Dereference transport for early garbage collection
       
  8183 			// (no matter how long the jqXHR object will be used)
       
  8184 			transport = undefined;
       
  8185 
       
  8186 			// Cache response headers
       
  8187 			responseHeadersString = headers || "";
       
  8188 
       
  8189 			// Set readyState
       
  8190 			jqXHR.readyState = status > 0 ? 4 : 0;
       
  8191 
       
  8192 			// Determine if successful
       
  8193 			isSuccess = status >= 200 && status < 300 || status === 304;
       
  8194 
       
  8195 			// Get response data
       
  8196 			if ( responses ) {
       
  8197 				response = ajaxHandleResponses( s, jqXHR, responses );
       
  8198 			}
       
  8199 
       
  8200 			// Convert no matter what (that way responseXXX fields are always set)
       
  8201 			response = ajaxConvert( s, response, jqXHR, isSuccess );
       
  8202 
       
  8203 			// If successful, handle type chaining
       
  8204 			if ( isSuccess ) {
       
  8205 
       
  8206 				// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
       
  8207 				if ( s.ifModified ) {
       
  8208 					modified = jqXHR.getResponseHeader("Last-Modified");
       
  8209 					if ( modified ) {
       
  8210 						jQuery.lastModified[ cacheURL ] = modified;
       
  8211 					}
       
  8212 					modified = jqXHR.getResponseHeader("etag");
       
  8213 					if ( modified ) {
       
  8214 						jQuery.etag[ cacheURL ] = modified;
       
  8215 					}
       
  8216 				}
       
  8217 
       
  8218 				// if no content
       
  8219 				if ( status === 204 || s.type === "HEAD" ) {
       
  8220 					statusText = "nocontent";
       
  8221 
       
  8222 				// if not modified
       
  8223 				} else if ( status === 304 ) {
       
  8224 					statusText = "notmodified";
       
  8225 
       
  8226 				// If we have data, let's convert it
       
  8227 				} else {
       
  8228 					statusText = response.state;
       
  8229 					success = response.data;
       
  8230 					error = response.error;
       
  8231 					isSuccess = !error;
       
  8232 				}
       
  8233 			} else {
       
  8234 				// We extract error from statusText
       
  8235 				// then normalize statusText and status for non-aborts
       
  8236 				error = statusText;
       
  8237 				if ( status || !statusText ) {
       
  8238 					statusText = "error";
       
  8239 					if ( status < 0 ) {
       
  8240 						status = 0;
       
  8241 					}
       
  8242 				}
       
  8243 			}
       
  8244 
       
  8245 			// Set data for the fake xhr object
       
  8246 			jqXHR.status = status;
       
  8247 			jqXHR.statusText = ( nativeStatusText || statusText ) + "";
       
  8248 
       
  8249 			// Success/Error
       
  8250 			if ( isSuccess ) {
       
  8251 				deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
       
  8252 			} else {
       
  8253 				deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
       
  8254 			}
       
  8255 
       
  8256 			// Status-dependent callbacks
       
  8257 			jqXHR.statusCode( statusCode );
       
  8258 			statusCode = undefined;
       
  8259 
       
  8260 			if ( fireGlobals ) {
       
  8261 				globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
       
  8262 					[ jqXHR, s, isSuccess ? success : error ] );
       
  8263 			}
       
  8264 
       
  8265 			// Complete
       
  8266 			completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
       
  8267 
       
  8268 			if ( fireGlobals ) {
       
  8269 				globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
       
  8270 				// Handle the global AJAX counter
       
  8271 				if ( !( --jQuery.active ) ) {
       
  8272 					jQuery.event.trigger("ajaxStop");
       
  8273 				}
       
  8274 			}
       
  8275 		}
       
  8276 
       
  8277 		return jqXHR;
       
  8278 	},
       
  8279 
       
  8280 	getJSON: function( url, data, callback ) {
       
  8281 		return jQuery.get( url, data, callback, "json" );
       
  8282 	},
       
  8283 
       
  8284 	getScript: function( url, callback ) {
       
  8285 		return jQuery.get( url, undefined, callback, "script" );
       
  8286 	}
       
  8287 });
       
  8288 
       
  8289 jQuery.each( [ "get", "post" ], function( i, method ) {
       
  8290 	jQuery[ method ] = function( url, data, callback, type ) {
       
  8291 		// shift arguments if data argument was omitted
       
  8292 		if ( jQuery.isFunction( data ) ) {
       
  8293 			type = type || callback;
       
  8294 			callback = data;
       
  8295 			data = undefined;
       
  8296 		}
       
  8297 
       
  8298 		return jQuery.ajax({
       
  8299 			url: url,
       
  8300 			type: method,
       
  8301 			dataType: type,
       
  8302 			data: data,
       
  8303 			success: callback
       
  8304 		});
       
  8305 	};
       
  8306 });
       
  8307 
       
  8308 // Attach a bunch of functions for handling common AJAX events
       
  8309 jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ) {
       
  8310 	jQuery.fn[ type ] = function( fn ) {
       
  8311 		return this.on( type, fn );
       
  8312 	};
       
  8313 });
       
  8314 
       
  8315 
       
  8316 jQuery._evalUrl = function( url ) {
       
  8317 	return jQuery.ajax({
       
  8318 		url: url,
       
  8319 		type: "GET",
       
  8320 		dataType: "script",
       
  8321 		async: false,
       
  8322 		global: false,
       
  8323 		"throws": true
       
  8324 	});
       
  8325 };
       
  8326 
       
  8327 
       
  8328 jQuery.fn.extend({
       
  8329 	wrapAll: function( html ) {
       
  8330 		var wrap;
       
  8331 
       
  8332 		if ( jQuery.isFunction( html ) ) {
       
  8333 			return this.each(function( i ) {
       
  8334 				jQuery( this ).wrapAll( html.call(this, i) );
       
  8335 			});
       
  8336 		}
       
  8337 
       
  8338 		if ( this[ 0 ] ) {
       
  8339 
       
  8340 			// The elements to wrap the target around
       
  8341 			wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );
       
  8342 
       
  8343 			if ( this[ 0 ].parentNode ) {
       
  8344 				wrap.insertBefore( this[ 0 ] );
       
  8345 			}
       
  8346 
       
  8347 			wrap.map(function() {
       
  8348 				var elem = this;
       
  8349 
       
  8350 				while ( elem.firstElementChild ) {
       
  8351 					elem = elem.firstElementChild;
       
  8352 				}
       
  8353 
       
  8354 				return elem;
       
  8355 			}).append( this );
       
  8356 		}
       
  8357 
       
  8358 		return this;
       
  8359 	},
       
  8360 
       
  8361 	wrapInner: function( html ) {
       
  8362 		if ( jQuery.isFunction( html ) ) {
       
  8363 			return this.each(function( i ) {
       
  8364 				jQuery( this ).wrapInner( html.call(this, i) );
       
  8365 			});
       
  8366 		}
       
  8367 
       
  8368 		return this.each(function() {
       
  8369 			var self = jQuery( this ),
       
  8370 				contents = self.contents();
       
  8371 
       
  8372 			if ( contents.length ) {
       
  8373 				contents.wrapAll( html );
       
  8374 
       
  8375 			} else {
       
  8376 				self.append( html );
       
  8377 			}
       
  8378 		});
       
  8379 	},
       
  8380 
       
  8381 	wrap: function( html ) {
       
  8382 		var isFunction = jQuery.isFunction( html );
       
  8383 
       
  8384 		return this.each(function( i ) {
       
  8385 			jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
       
  8386 		});
       
  8387 	},
       
  8388 
       
  8389 	unwrap: function() {
       
  8390 		return this.parent().each(function() {
       
  8391 			if ( !jQuery.nodeName( this, "body" ) ) {
       
  8392 				jQuery( this ).replaceWith( this.childNodes );
       
  8393 			}
       
  8394 		}).end();
       
  8395 	}
       
  8396 });
       
  8397 
       
  8398 
       
  8399 jQuery.expr.filters.hidden = function( elem ) {
       
  8400 	// Support: Opera <= 12.12
       
  8401 	// Opera reports offsetWidths and offsetHeights less than zero on some elements
       
  8402 	return elem.offsetWidth <= 0 && elem.offsetHeight <= 0;
       
  8403 };
       
  8404 jQuery.expr.filters.visible = function( elem ) {
       
  8405 	return !jQuery.expr.filters.hidden( elem );
       
  8406 };
       
  8407 
       
  8408 
       
  8409 
       
  8410 
       
  8411 var r20 = /%20/g,
       
  8412 	rbracket = /\[\]$/,
       
  8413 	rCRLF = /\r?\n/g,
       
  8414 	rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
       
  8415 	rsubmittable = /^(?:input|select|textarea|keygen)/i;
       
  8416 
       
  8417 function buildParams( prefix, obj, traditional, add ) {
       
  8418 	var name;
       
  8419 
       
  8420 	if ( jQuery.isArray( obj ) ) {
       
  8421 		// Serialize array item.
       
  8422 		jQuery.each( obj, function( i, v ) {
       
  8423 			if ( traditional || rbracket.test( prefix ) ) {
       
  8424 				// Treat each array item as a scalar.
       
  8425 				add( prefix, v );
       
  8426 
       
  8427 			} else {
       
  8428 				// Item is non-scalar (array or object), encode its numeric index.
       
  8429 				buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
       
  8430 			}
       
  8431 		});
       
  8432 
       
  8433 	} else if ( !traditional && jQuery.type( obj ) === "object" ) {
       
  8434 		// Serialize object item.
       
  8435 		for ( name in obj ) {
       
  8436 			buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
       
  8437 		}
       
  8438 
       
  8439 	} else {
       
  8440 		// Serialize scalar item.
       
  8441 		add( prefix, obj );
       
  8442 	}
       
  8443 }
       
  8444 
       
  8445 // Serialize an array of form elements or a set of
       
  8446 // key/values into a query string
       
  8447 jQuery.param = function( a, traditional ) {
       
  8448 	var prefix,
       
  8449 		s = [],
       
  8450 		add = function( key, value ) {
       
  8451 			// If value is a function, invoke it and return its value
       
  8452 			value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
       
  8453 			s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
       
  8454 		};
       
  8455 
       
  8456 	// Set traditional to true for jQuery <= 1.3.2 behavior.
       
  8457 	if ( traditional === undefined ) {
       
  8458 		traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
       
  8459 	}
       
  8460 
       
  8461 	// If an array was passed in, assume that it is an array of form elements.
       
  8462 	if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
       
  8463 		// Serialize the form elements
       
  8464 		jQuery.each( a, function() {
       
  8465 			add( this.name, this.value );
       
  8466 		});
       
  8467 
       
  8468 	} else {
       
  8469 		// If traditional, encode the "old" way (the way 1.3.2 or older
       
  8470 		// did it), otherwise encode params recursively.
       
  8471 		for ( prefix in a ) {
       
  8472 			buildParams( prefix, a[ prefix ], traditional, add );
       
  8473 		}
       
  8474 	}
       
  8475 
       
  8476 	// Return the resulting serialization
       
  8477 	return s.join( "&" ).replace( r20, "+" );
       
  8478 };
       
  8479 
       
  8480 jQuery.fn.extend({
       
  8481 	serialize: function() {
       
  8482 		return jQuery.param( this.serializeArray() );
       
  8483 	},
       
  8484 	serializeArray: function() {
       
  8485 		return this.map(function() {
       
  8486 			// Can add propHook for "elements" to filter or add form elements
       
  8487 			var elements = jQuery.prop( this, "elements" );
       
  8488 			return elements ? jQuery.makeArray( elements ) : this;
       
  8489 		})
       
  8490 		.filter(function() {
       
  8491 			var type = this.type;
       
  8492 
       
  8493 			// Use .is( ":disabled" ) so that fieldset[disabled] works
       
  8494 			return this.name && !jQuery( this ).is( ":disabled" ) &&
       
  8495 				rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
       
  8496 				( this.checked || !rcheckableType.test( type ) );
       
  8497 		})
       
  8498 		.map(function( i, elem ) {
       
  8499 			var val = jQuery( this ).val();
       
  8500 
       
  8501 			return val == null ?
       
  8502 				null :
       
  8503 				jQuery.isArray( val ) ?
       
  8504 					jQuery.map( val, function( val ) {
       
  8505 						return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
       
  8506 					}) :
       
  8507 					{ name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
       
  8508 		}).get();
       
  8509 	}
       
  8510 });
       
  8511 
       
  8512 
       
  8513 jQuery.ajaxSettings.xhr = function() {
       
  8514 	try {
       
  8515 		return new XMLHttpRequest();
       
  8516 	} catch( e ) {}
       
  8517 };
       
  8518 
       
  8519 var xhrId = 0,
       
  8520 	xhrCallbacks = {},
       
  8521 	xhrSuccessStatus = {
       
  8522 		// file protocol always yields status code 0, assume 200
       
  8523 		0: 200,
       
  8524 		// Support: IE9
       
  8525 		// #1450: sometimes IE returns 1223 when it should be 204
       
  8526 		1223: 204
       
  8527 	},
       
  8528 	xhrSupported = jQuery.ajaxSettings.xhr();
       
  8529 
       
  8530 // Support: IE9
       
  8531 // Open requests must be manually aborted on unload (#5280)
       
  8532 if ( window.ActiveXObject ) {
       
  8533 	jQuery( window ).on( "unload", function() {
       
  8534 		for ( var key in xhrCallbacks ) {
       
  8535 			xhrCallbacks[ key ]();
       
  8536 		}
       
  8537 	});
       
  8538 }
       
  8539 
       
  8540 support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
       
  8541 support.ajax = xhrSupported = !!xhrSupported;
       
  8542 
       
  8543 jQuery.ajaxTransport(function( options ) {
       
  8544 	var callback;
       
  8545 
       
  8546 	// Cross domain only allowed if supported through XMLHttpRequest
       
  8547 	if ( support.cors || xhrSupported && !options.crossDomain ) {
       
  8548 		return {
       
  8549 			send: function( headers, complete ) {
       
  8550 				var i,
       
  8551 					xhr = options.xhr(),
       
  8552 					id = ++xhrId;
       
  8553 
       
  8554 				xhr.open( options.type, options.url, options.async, options.username, options.password );
       
  8555 
       
  8556 				// Apply custom fields if provided
       
  8557 				if ( options.xhrFields ) {
       
  8558 					for ( i in options.xhrFields ) {
       
  8559 						xhr[ i ] = options.xhrFields[ i ];
       
  8560 					}
       
  8561 				}
       
  8562 
       
  8563 				// Override mime type if needed
       
  8564 				if ( options.mimeType && xhr.overrideMimeType ) {
       
  8565 					xhr.overrideMimeType( options.mimeType );
       
  8566 				}
       
  8567 
       
  8568 				// X-Requested-With header
       
  8569 				// For cross-domain requests, seeing as conditions for a preflight are
       
  8570 				// akin to a jigsaw puzzle, we simply never set it to be sure.
       
  8571 				// (it can always be set on a per-request basis or even using ajaxSetup)
       
  8572 				// For same-domain requests, won't change header if already provided.
       
  8573 				if ( !options.crossDomain && !headers["X-Requested-With"] ) {
       
  8574 					headers["X-Requested-With"] = "XMLHttpRequest";
       
  8575 				}
       
  8576 
       
  8577 				// Set headers
       
  8578 				for ( i in headers ) {
       
  8579 					xhr.setRequestHeader( i, headers[ i ] );
       
  8580 				}
       
  8581 
       
  8582 				// Callback
       
  8583 				callback = function( type ) {
       
  8584 					return function() {
       
  8585 						if ( callback ) {
       
  8586 							delete xhrCallbacks[ id ];
       
  8587 							callback = xhr.onload = xhr.onerror = null;
       
  8588 
       
  8589 							if ( type === "abort" ) {
       
  8590 								xhr.abort();
       
  8591 							} else if ( type === "error" ) {
       
  8592 								complete(
       
  8593 									// file: protocol always yields status 0; see #8605, #14207
       
  8594 									xhr.status,
       
  8595 									xhr.statusText
       
  8596 								);
       
  8597 							} else {
       
  8598 								complete(
       
  8599 									xhrSuccessStatus[ xhr.status ] || xhr.status,
       
  8600 									xhr.statusText,
       
  8601 									// Support: IE9
       
  8602 									// Accessing binary-data responseText throws an exception
       
  8603 									// (#11426)
       
  8604 									typeof xhr.responseText === "string" ? {
       
  8605 										text: xhr.responseText
       
  8606 									} : undefined,
       
  8607 									xhr.getAllResponseHeaders()
       
  8608 								);
       
  8609 							}
       
  8610 						}
       
  8611 					};
       
  8612 				};
       
  8613 
       
  8614 				// Listen to events
       
  8615 				xhr.onload = callback();
       
  8616 				xhr.onerror = callback("error");
       
  8617 
       
  8618 				// Create the abort callback
       
  8619 				callback = xhrCallbacks[ id ] = callback("abort");
       
  8620 
       
  8621 				try {
       
  8622 					// Do send the request (this may raise an exception)
       
  8623 					xhr.send( options.hasContent && options.data || null );
       
  8624 				} catch ( e ) {
       
  8625 					// #14683: Only rethrow if this hasn't been notified as an error yet
       
  8626 					if ( callback ) {
       
  8627 						throw e;
       
  8628 					}
       
  8629 				}
       
  8630 			},
       
  8631 
       
  8632 			abort: function() {
       
  8633 				if ( callback ) {
       
  8634 					callback();
       
  8635 				}
       
  8636 			}
       
  8637 		};
       
  8638 	}
       
  8639 });
       
  8640 
       
  8641 
       
  8642 
       
  8643 
       
  8644 // Install script dataType
       
  8645 jQuery.ajaxSetup({
       
  8646 	accepts: {
       
  8647 		script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
       
  8648 	},
       
  8649 	contents: {
       
  8650 		script: /(?:java|ecma)script/
       
  8651 	},
       
  8652 	converters: {
       
  8653 		"text script": function( text ) {
       
  8654 			jQuery.globalEval( text );
       
  8655 			return text;
       
  8656 		}
       
  8657 	}
       
  8658 });
       
  8659 
       
  8660 // Handle cache's special case and crossDomain
       
  8661 jQuery.ajaxPrefilter( "script", function( s ) {
       
  8662 	if ( s.cache === undefined ) {
       
  8663 		s.cache = false;
       
  8664 	}
       
  8665 	if ( s.crossDomain ) {
       
  8666 		s.type = "GET";
       
  8667 	}
       
  8668 });
       
  8669 
       
  8670 // Bind script tag hack transport
       
  8671 jQuery.ajaxTransport( "script", function( s ) {
       
  8672 	// This transport only deals with cross domain requests
       
  8673 	if ( s.crossDomain ) {
       
  8674 		var script, callback;
       
  8675 		return {
       
  8676 			send: function( _, complete ) {
       
  8677 				script = jQuery("<script>").prop({
       
  8678 					async: true,
       
  8679 					charset: s.scriptCharset,
       
  8680 					src: s.url
       
  8681 				}).on(
       
  8682 					"load error",
       
  8683 					callback = function( evt ) {
       
  8684 						script.remove();
       
  8685 						callback = null;
       
  8686 						if ( evt ) {
       
  8687 							complete( evt.type === "error" ? 404 : 200, evt.type );
       
  8688 						}
       
  8689 					}
       
  8690 				);
       
  8691 				document.head.appendChild( script[ 0 ] );
       
  8692 			},
       
  8693 			abort: function() {
       
  8694 				if ( callback ) {
       
  8695 					callback();
       
  8696 				}
       
  8697 			}
       
  8698 		};
       
  8699 	}
       
  8700 });
       
  8701 
       
  8702 
       
  8703 
       
  8704 
       
  8705 var oldCallbacks = [],
       
  8706 	rjsonp = /(=)\?(?=&|$)|\?\?/;
       
  8707 
       
  8708 // Default jsonp settings
       
  8709 jQuery.ajaxSetup({
       
  8710 	jsonp: "callback",
       
  8711 	jsonpCallback: function() {
       
  8712 		var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) );
       
  8713 		this[ callback ] = true;
       
  8714 		return callback;
       
  8715 	}
       
  8716 });
       
  8717 
       
  8718 // Detect, normalize options and install callbacks for jsonp requests
       
  8719 jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
       
  8720 
       
  8721 	var callbackName, overwritten, responseContainer,
       
  8722 		jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
       
  8723 			"url" :
       
  8724 			typeof s.data === "string" && !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && rjsonp.test( s.data ) && "data"
       
  8725 		);
       
  8726 
       
  8727 	// Handle iff the expected data type is "jsonp" or we have a parameter to set
       
  8728 	if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
       
  8729 
       
  8730 		// Get callback name, remembering preexisting value associated with it
       
  8731 		callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
       
  8732 			s.jsonpCallback() :
       
  8733 			s.jsonpCallback;
       
  8734 
       
  8735 		// Insert callback into url or form data
       
  8736 		if ( jsonProp ) {
       
  8737 			s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
       
  8738 		} else if ( s.jsonp !== false ) {
       
  8739 			s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
       
  8740 		}
       
  8741 
       
  8742 		// Use data converter to retrieve json after script execution
       
  8743 		s.converters["script json"] = function() {
       
  8744 			if ( !responseContainer ) {
       
  8745 				jQuery.error( callbackName + " was not called" );
       
  8746 			}
       
  8747 			return responseContainer[ 0 ];
       
  8748 		};
       
  8749 
       
  8750 		// force json dataType
       
  8751 		s.dataTypes[ 0 ] = "json";
       
  8752 
       
  8753 		// Install callback
       
  8754 		overwritten = window[ callbackName ];
       
  8755 		window[ callbackName ] = function() {
       
  8756 			responseContainer = arguments;
       
  8757 		};
       
  8758 
       
  8759 		// Clean-up function (fires after converters)
       
  8760 		jqXHR.always(function() {
       
  8761 			// Restore preexisting value
       
  8762 			window[ callbackName ] = overwritten;
       
  8763 
       
  8764 			// Save back as free
       
  8765 			if ( s[ callbackName ] ) {
       
  8766 				// make sure that re-using the options doesn't screw things around
       
  8767 				s.jsonpCallback = originalSettings.jsonpCallback;
       
  8768 
       
  8769 				// save the callback name for future use
       
  8770 				oldCallbacks.push( callbackName );
       
  8771 			}
       
  8772 
       
  8773 			// Call if it was a function and we have a response
       
  8774 			if ( responseContainer && jQuery.isFunction( overwritten ) ) {
       
  8775 				overwritten( responseContainer[ 0 ] );
       
  8776 			}
       
  8777 
       
  8778 			responseContainer = overwritten = undefined;
       
  8779 		});
       
  8780 
       
  8781 		// Delegate to script
       
  8782 		return "script";
       
  8783 	}
       
  8784 });
       
  8785 
       
  8786 
       
  8787 
       
  8788 
       
  8789 // data: string of html
       
  8790 // context (optional): If specified, the fragment will be created in this context, defaults to document
       
  8791 // keepScripts (optional): If true, will include scripts passed in the html string
       
  8792 jQuery.parseHTML = function( data, context, keepScripts ) {
       
  8793 	if ( !data || typeof data !== "string" ) {
       
  8794 		return null;
       
  8795 	}
       
  8796 	if ( typeof context === "boolean" ) {
       
  8797 		keepScripts = context;
       
  8798 		context = false;
       
  8799 	}
       
  8800 	context = context || document;
       
  8801 
       
  8802 	var parsed = rsingleTag.exec( data ),
       
  8803 		scripts = !keepScripts && [];
       
  8804 
       
  8805 	// Single tag
       
  8806 	if ( parsed ) {
       
  8807 		return [ context.createElement( parsed[1] ) ];
       
  8808 	}
       
  8809 
       
  8810 	parsed = jQuery.buildFragment( [ data ], context, scripts );
       
  8811 
       
  8812 	if ( scripts && scripts.length ) {
       
  8813 		jQuery( scripts ).remove();
       
  8814 	}
       
  8815 
       
  8816 	return jQuery.merge( [], parsed.childNodes );
       
  8817 };
       
  8818 
       
  8819 
       
  8820 // Keep a copy of the old load method
       
  8821 var _load = jQuery.fn.load;
       
  8822 
       
  8823 /**
       
  8824  * Load a url into a page
       
  8825  */
       
  8826 jQuery.fn.load = function( url, params, callback ) {
       
  8827 	if ( typeof url !== "string" && _load ) {
       
  8828 		return _load.apply( this, arguments );
       
  8829 	}
       
  8830 
       
  8831 	var selector, type, response,
       
  8832 		self = this,
       
  8833 		off = url.indexOf(" ");
       
  8834 
       
  8835 	if ( off >= 0 ) {
       
  8836 		selector = jQuery.trim( url.slice( off ) );
       
  8837 		url = url.slice( 0, off );
       
  8838 	}
       
  8839 
       
  8840 	// If it's a function
       
  8841 	if ( jQuery.isFunction( params ) ) {
       
  8842 
       
  8843 		// We assume that it's the callback
       
  8844 		callback = params;
       
  8845 		params = undefined;
       
  8846 
       
  8847 	// Otherwise, build a param string
       
  8848 	} else if ( params && typeof params === "object" ) {
       
  8849 		type = "POST";
       
  8850 	}
       
  8851 
       
  8852 	// If we have elements to modify, make the request
       
  8853 	if ( self.length > 0 ) {
       
  8854 		jQuery.ajax({
       
  8855 			url: url,
       
  8856 
       
  8857 			// if "type" variable is undefined, then "GET" method will be used
       
  8858 			type: type,
       
  8859 			dataType: "html",
       
  8860 			data: params
       
  8861 		}).done(function( responseText ) {
       
  8862 
       
  8863 			// Save response for use in complete callback
       
  8864 			response = arguments;
       
  8865 
       
  8866 			self.html( selector ?
       
  8867 
       
  8868 				// If a selector was specified, locate the right elements in a dummy div
       
  8869 				// Exclude scripts to avoid IE 'Permission Denied' errors
       
  8870 				jQuery("<div>").append( jQuery.parseHTML( responseText ) ).find( selector ) :
       
  8871 
       
  8872 				// Otherwise use the full result
       
  8873 				responseText );
       
  8874 
       
  8875 		}).complete( callback && function( jqXHR, status ) {
       
  8876 			self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );
       
  8877 		});
       
  8878 	}
       
  8879 
       
  8880 	return this;
       
  8881 };
       
  8882 
       
  8883 
       
  8884 
       
  8885 
       
  8886 jQuery.expr.filters.animated = function( elem ) {
       
  8887 	return jQuery.grep(jQuery.timers, function( fn ) {
       
  8888 		return elem === fn.elem;
       
  8889 	}).length;
       
  8890 };
       
  8891 
       
  8892 
       
  8893 
       
  8894 
       
  8895 var docElem = window.document.documentElement;
       
  8896 
       
  8897 /**
       
  8898  * Gets a window from an element
       
  8899  */
       
  8900 function getWindow( elem ) {
       
  8901 	return jQuery.isWindow( elem ) ? elem : elem.nodeType === 9 && elem.defaultView;
       
  8902 }
       
  8903 
       
  8904 jQuery.offset = {
       
  8905 	setOffset: function( elem, options, i ) {
       
  8906 		var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,
       
  8907 			position = jQuery.css( elem, "position" ),
       
  8908 			curElem = jQuery( elem ),
       
  8909 			props = {};
       
  8910 
       
  8911 		// Set position first, in-case top/left are set even on static elem
       
  8912 		if ( position === "static" ) {
       
  8913 			elem.style.position = "relative";
       
  8914 		}
       
  8915 
       
  8916 		curOffset = curElem.offset();
       
  8917 		curCSSTop = jQuery.css( elem, "top" );
       
  8918 		curCSSLeft = jQuery.css( elem, "left" );
       
  8919 		calculatePosition = ( position === "absolute" || position === "fixed" ) &&
       
  8920 			( curCSSTop + curCSSLeft ).indexOf("auto") > -1;
       
  8921 
       
  8922 		// Need to be able to calculate position if either top or left is auto and position is either absolute or fixed
       
  8923 		if ( calculatePosition ) {
       
  8924 			curPosition = curElem.position();
       
  8925 			curTop = curPosition.top;
       
  8926 			curLeft = curPosition.left;
       
  8927 
       
  8928 		} else {
       
  8929 			curTop = parseFloat( curCSSTop ) || 0;
       
  8930 			curLeft = parseFloat( curCSSLeft ) || 0;
       
  8931 		}
       
  8932 
       
  8933 		if ( jQuery.isFunction( options ) ) {
       
  8934 			options = options.call( elem, i, curOffset );
       
  8935 		}
       
  8936 
       
  8937 		if ( options.top != null ) {
       
  8938 			props.top = ( options.top - curOffset.top ) + curTop;
       
  8939 		}
       
  8940 		if ( options.left != null ) {
       
  8941 			props.left = ( options.left - curOffset.left ) + curLeft;
       
  8942 		}
       
  8943 
       
  8944 		if ( "using" in options ) {
       
  8945 			options.using.call( elem, props );
       
  8946 
       
  8947 		} else {
       
  8948 			curElem.css( props );
       
  8949 		}
       
  8950 	}
       
  8951 };
       
  8952 
       
  8953 jQuery.fn.extend({
       
  8954 	offset: function( options ) {
       
  8955 		if ( arguments.length ) {
       
  8956 			return options === undefined ?
       
  8957 				this :
       
  8958 				this.each(function( i ) {
       
  8959 					jQuery.offset.setOffset( this, options, i );
       
  8960 				});
       
  8961 		}
       
  8962 
       
  8963 		var docElem, win,
       
  8964 			elem = this[ 0 ],
       
  8965 			box = { top: 0, left: 0 },
       
  8966 			doc = elem && elem.ownerDocument;
       
  8967 
       
  8968 		if ( !doc ) {
       
  8969 			return;
       
  8970 		}
       
  8971 
       
  8972 		docElem = doc.documentElement;
       
  8973 
       
  8974 		// Make sure it's not a disconnected DOM node
       
  8975 		if ( !jQuery.contains( docElem, elem ) ) {
       
  8976 			return box;
       
  8977 		}
       
  8978 
       
  8979 		// If we don't have gBCR, just use 0,0 rather than error
       
  8980 		// BlackBerry 5, iOS 3 (original iPhone)
       
  8981 		if ( typeof elem.getBoundingClientRect !== strundefined ) {
       
  8982 			box = elem.getBoundingClientRect();
       
  8983 		}
       
  8984 		win = getWindow( doc );
       
  8985 		return {
       
  8986 			top: box.top + win.pageYOffset - docElem.clientTop,
       
  8987 			left: box.left + win.pageXOffset - docElem.clientLeft
       
  8988 		};
       
  8989 	},
       
  8990 
       
  8991 	position: function() {
       
  8992 		if ( !this[ 0 ] ) {
       
  8993 			return;
       
  8994 		}
       
  8995 
       
  8996 		var offsetParent, offset,
       
  8997 			elem = this[ 0 ],
       
  8998 			parentOffset = { top: 0, left: 0 };
       
  8999 
       
  9000 		// Fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is its only offset parent
       
  9001 		if ( jQuery.css( elem, "position" ) === "fixed" ) {
       
  9002 			// We assume that getBoundingClientRect is available when computed position is fixed
       
  9003 			offset = elem.getBoundingClientRect();
       
  9004 
       
  9005 		} else {
       
  9006 			// Get *real* offsetParent
       
  9007 			offsetParent = this.offsetParent();
       
  9008 
       
  9009 			// Get correct offsets
       
  9010 			offset = this.offset();
       
  9011 			if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) {
       
  9012 				parentOffset = offsetParent.offset();
       
  9013 			}
       
  9014 
       
  9015 			// Add offsetParent borders
       
  9016 			parentOffset.top += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true );
       
  9017 			parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true );
       
  9018 		}
       
  9019 
       
  9020 		// Subtract parent offsets and element margins
       
  9021 		return {
       
  9022 			top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
       
  9023 			left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true )
       
  9024 		};
       
  9025 	},
       
  9026 
       
  9027 	offsetParent: function() {
       
  9028 		return this.map(function() {
       
  9029 			var offsetParent = this.offsetParent || docElem;
       
  9030 
       
  9031 			while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) && jQuery.css( offsetParent, "position" ) === "static" ) ) {
       
  9032 				offsetParent = offsetParent.offsetParent;
       
  9033 			}
       
  9034 
       
  9035 			return offsetParent || docElem;
       
  9036 		});
       
  9037 	}
       
  9038 });
       
  9039 
       
  9040 // Create scrollLeft and scrollTop methods
       
  9041 jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) {
       
  9042 	var top = "pageYOffset" === prop;
       
  9043 
       
  9044 	jQuery.fn[ method ] = function( val ) {
       
  9045 		return access( this, function( elem, method, val ) {
       
  9046 			var win = getWindow( elem );
       
  9047 
       
  9048 			if ( val === undefined ) {
       
  9049 				return win ? win[ prop ] : elem[ method ];
       
  9050 			}
       
  9051 
       
  9052 			if ( win ) {
       
  9053 				win.scrollTo(
       
  9054 					!top ? val : window.pageXOffset,
       
  9055 					top ? val : window.pageYOffset
       
  9056 				);
       
  9057 
       
  9058 			} else {
       
  9059 				elem[ method ] = val;
       
  9060 			}
       
  9061 		}, method, val, arguments.length, null );
       
  9062 	};
       
  9063 });
       
  9064 
       
  9065 // Add the top/left cssHooks using jQuery.fn.position
       
  9066 // Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
       
  9067 // getComputedStyle returns percent when specified for top/left/bottom/right
       
  9068 // rather than make the css module depend on the offset module, we just check for it here
       
  9069 jQuery.each( [ "top", "left" ], function( i, prop ) {
       
  9070 	jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,
       
  9071 		function( elem, computed ) {
       
  9072 			if ( computed ) {
       
  9073 				computed = curCSS( elem, prop );
       
  9074 				// if curCSS returns percentage, fallback to offset
       
  9075 				return rnumnonpx.test( computed ) ?
       
  9076 					jQuery( elem ).position()[ prop ] + "px" :
       
  9077 					computed;
       
  9078 			}
       
  9079 		}
       
  9080 	);
       
  9081 });
       
  9082 
       
  9083 
       
  9084 // Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
       
  9085 jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
       
  9086 	jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) {
       
  9087 		// margin is only for outerHeight, outerWidth
       
  9088 		jQuery.fn[ funcName ] = function( margin, value ) {
       
  9089 			var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
       
  9090 				extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
       
  9091 
       
  9092 			return access( this, function( elem, type, value ) {
       
  9093 				var doc;
       
  9094 
       
  9095 				if ( jQuery.isWindow( elem ) ) {
       
  9096 					// As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
       
  9097 					// isn't a whole lot we can do. See pull request at this URL for discussion:
       
  9098 					// https://github.com/jquery/jquery/pull/764
       
  9099 					return elem.document.documentElement[ "client" + name ];
       
  9100 				}
       
  9101 
       
  9102 				// Get document width or height
       
  9103 				if ( elem.nodeType === 9 ) {
       
  9104 					doc = elem.documentElement;
       
  9105 
       
  9106 					// Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],
       
  9107 					// whichever is greatest
       
  9108 					return Math.max(
       
  9109 						elem.body[ "scroll" + name ], doc[ "scroll" + name ],
       
  9110 						elem.body[ "offset" + name ], doc[ "offset" + name ],
       
  9111 						doc[ "client" + name ]
       
  9112 					);
       
  9113 				}
       
  9114 
       
  9115 				return value === undefined ?
       
  9116 					// Get width or height on the element, requesting but not forcing parseFloat
       
  9117 					jQuery.css( elem, type, extra ) :
       
  9118 
       
  9119 					// Set width or height on the element
       
  9120 					jQuery.style( elem, type, value, extra );
       
  9121 			}, type, chainable ? margin : undefined, chainable, null );
       
  9122 		};
       
  9123 	});
       
  9124 });
       
  9125 
       
  9126 
       
  9127 // The number of elements contained in the matched element set
       
  9128 jQuery.fn.size = function() {
       
  9129 	return this.length;
       
  9130 };
       
  9131 
       
  9132 jQuery.fn.andSelf = jQuery.fn.addBack;
       
  9133 
       
  9134 
       
  9135 
       
  9136 
       
  9137 // Register as a named AMD module, since jQuery can be concatenated with other
       
  9138 // files that may use define, but not via a proper concatenation script that
       
  9139 // understands anonymous AMD modules. A named AMD is safest and most robust
       
  9140 // way to register. Lowercase jquery is used because AMD module names are
       
  9141 // derived from file names, and jQuery is normally delivered in a lowercase
       
  9142 // file name. Do this after creating the global so that if an AMD module wants
       
  9143 // to call noConflict to hide this version of jQuery, it will work.
       
  9144 
       
  9145 // Note that for maximum portability, libraries that are not jQuery should
       
  9146 // declare themselves as anonymous modules, and avoid setting a global if an
       
  9147 // AMD loader is present. jQuery is a special case. For more information, see
       
  9148 // https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon
       
  9149 
       
  9150 if ( typeof define === "function" && define.amd ) {
       
  9151 	define( "jquery", [], function() {
       
  9152 		return jQuery;
       
  9153 	});
       
  9154 }
       
  9155 
       
  9156 
       
  9157 
       
  9158 
       
  9159 var
       
  9160 	// Map over jQuery in case of overwrite
       
  9161 	_jQuery = window.jQuery,
       
  9162 
       
  9163 	// Map over the $ in case of overwrite
       
  9164 	_$ = window.$;
       
  9165 
       
  9166 jQuery.noConflict = function( deep ) {
       
  9167 	if ( window.$ === jQuery ) {
       
  9168 		window.$ = _$;
       
  9169 	}
       
  9170 
       
  9171 	if ( deep && window.jQuery === jQuery ) {
       
  9172 		window.jQuery = _jQuery;
       
  9173 	}
       
  9174 
       
  9175 	return jQuery;
       
  9176 };
       
  9177 
       
  9178 // Expose jQuery and $ identifiers, even in
       
  9179 // AMD (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
       
  9180 // and CommonJS for browser emulators (#13566)
       
  9181 if ( typeof noGlobal === strundefined ) {
       
  9182 	window.jQuery = window.$ = jQuery;
       
  9183 }
       
  9184 
       
  9185 
       
  9186 
       
  9187 
       
  9188 return jQuery;
       
  9189 
       
  9190 }));
       
  9191 
       
  9192 /**
       
  9193  * @license AngularJS v1.3.0-rc.5
       
  9194  * (c) 2010-2014 Google, Inc. http://angularjs.org
       
  9195  * License: MIT
       
  9196  */
       
  9197 (function(window, document, undefined) {'use strict';
       
  9198 
       
  9199 /**
       
  9200  * @description
       
  9201  *
       
  9202  * This object provides a utility for producing rich Error messages within
       
  9203  * Angular. It can be called as follows:
       
  9204  *
       
  9205  * var exampleMinErr = minErr('example');
       
  9206  * throw exampleMinErr('one', 'This {0} is {1}', foo, bar);
       
  9207  *
       
  9208  * The above creates an instance of minErr in the example namespace. The
       
  9209  * resulting error will have a namespaced error code of example.one.  The
       
  9210  * resulting error will replace {0} with the value of foo, and {1} with the
       
  9211  * value of bar. The object is not restricted in the number of arguments it can
       
  9212  * take.
       
  9213  *
       
  9214  * If fewer arguments are specified than necessary for interpolation, the extra
       
  9215  * interpolation markers will be preserved in the final string.
       
  9216  *
       
  9217  * Since data will be parsed statically during a build step, some restrictions
       
  9218  * are applied with respect to how minErr instances are created and called.
       
  9219  * Instances should have names of the form namespaceMinErr for a minErr created
       
  9220  * using minErr('namespace') . Error codes, namespaces and template strings
       
  9221  * should all be static strings, not variables or general expressions.
       
  9222  *
       
  9223  * @param {string} module The namespace to use for the new minErr instance.
       
  9224  * @param {function} ErrorConstructor Custom error constructor to be instantiated when returning
       
  9225  *   error from returned function, for cases when a particular type of error is useful.
       
  9226  * @returns {function(code:string, template:string, ...templateArgs): Error} minErr instance
       
  9227  */
       
  9228 
       
  9229 function minErr(module, ErrorConstructor) {
       
  9230   ErrorConstructor = ErrorConstructor || Error;
       
  9231   return function () {
       
  9232     var code = arguments[0],
       
  9233       prefix = '[' + (module ? module + ':' : '') + code + '] ',
       
  9234       template = arguments[1],
       
  9235       templateArgs = arguments,
       
  9236       stringify = function (obj) {
       
  9237         if (typeof obj === 'function') {
       
  9238           return obj.toString().replace(/ \{[\s\S]*$/, '');
       
  9239         } else if (typeof obj === 'undefined') {
       
  9240           return 'undefined';
       
  9241         } else if (typeof obj !== 'string') {
       
  9242           return JSON.stringify(obj);
       
  9243         }
       
  9244         return obj;
       
  9245       },
       
  9246       message, i;
       
  9247 
       
  9248     message = prefix + template.replace(/\{\d+\}/g, function (match) {
       
  9249       var index = +match.slice(1, -1), arg;
       
  9250 
       
  9251       if (index + 2 < templateArgs.length) {
       
  9252         arg = templateArgs[index + 2];
       
  9253         if (typeof arg === 'function') {
       
  9254           return arg.toString().replace(/ ?\{[\s\S]*$/, '');
       
  9255         } else if (typeof arg === 'undefined') {
       
  9256           return 'undefined';
       
  9257         } else if (typeof arg !== 'string') {
       
  9258           return toJson(arg);
       
  9259         }
       
  9260         return arg;
       
  9261       }
       
  9262       return match;
       
  9263     });
       
  9264 
       
  9265     message = message + '\nhttp://errors.angularjs.org/1.3.0-rc.5/' +
       
  9266       (module ? module + '/' : '') + code;
       
  9267     for (i = 2; i < arguments.length; i++) {
       
  9268       message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' +
       
  9269         encodeURIComponent(stringify(arguments[i]));
       
  9270     }
       
  9271     return new ErrorConstructor(message);
       
  9272   };
       
  9273 }
       
  9274 
       
  9275 /* We need to tell jshint what variables are being exported */
       
  9276 /* global angular: true,
       
  9277   msie: true,
       
  9278   jqLite: true,
       
  9279   jQuery: true,
       
  9280   slice: true,
       
  9281   splice: true,
       
  9282   push: true,
       
  9283   toString: true,
       
  9284   ngMinErr: true,
       
  9285   angularModule: true,
       
  9286   uid: true,
       
  9287   REGEX_STRING_REGEXP: true,
       
  9288   VALIDITY_STATE_PROPERTY: true,
       
  9289 
       
  9290   lowercase: true,
       
  9291   uppercase: true,
       
  9292   manualLowercase: true,
       
  9293   manualUppercase: true,
       
  9294   nodeName_: true,
       
  9295   isArrayLike: true,
       
  9296   forEach: true,
       
  9297   sortedKeys: true,
       
  9298   forEachSorted: true,
       
  9299   reverseParams: true,
       
  9300   nextUid: true,
       
  9301   setHashKey: true,
       
  9302   extend: true,
       
  9303   int: true,
       
  9304   inherit: true,
       
  9305   noop: true,
       
  9306   identity: true,
       
  9307   valueFn: true,
       
  9308   isUndefined: true,
       
  9309   isDefined: true,
       
  9310   isObject: true,
       
  9311   isString: true,
       
  9312   isNumber: true,
       
  9313   isDate: true,
       
  9314   isArray: true,
       
  9315   isFunction: true,
       
  9316   isRegExp: true,
       
  9317   isWindow: true,
       
  9318   isScope: true,
       
  9319   isFile: true,
       
  9320   isBlob: true,
       
  9321   isBoolean: true,
       
  9322   isPromiseLike: true,
       
  9323   trim: true,
       
  9324   isElement: true,
       
  9325   makeMap: true,
       
  9326   size: true,
       
  9327   includes: true,
       
  9328   arrayRemove: true,
       
  9329   isLeafNode: true,
       
  9330   copy: true,
       
  9331   shallowCopy: true,
       
  9332   equals: true,
       
  9333   csp: true,
       
  9334   concat: true,
       
  9335   sliceArgs: true,
       
  9336   bind: true,
       
  9337   toJsonReplacer: true,
       
  9338   toJson: true,
       
  9339   fromJson: true,
       
  9340   startingTag: true,
       
  9341   tryDecodeURIComponent: true,
       
  9342   parseKeyValue: true,
       
  9343   toKeyValue: true,
       
  9344   encodeUriSegment: true,
       
  9345   encodeUriQuery: true,
       
  9346   angularInit: true,
       
  9347   bootstrap: true,
       
  9348   getTestability: true,
       
  9349   snake_case: true,
       
  9350   bindJQuery: true,
       
  9351   assertArg: true,
       
  9352   assertArgFn: true,
       
  9353   assertNotHasOwnProperty: true,
       
  9354   getter: true,
       
  9355   getBlockNodes: true,
       
  9356   hasOwnProperty: true,
       
  9357   createMap: true,
       
  9358 
       
  9359   NODE_TYPE_ELEMENT: true,
       
  9360   NODE_TYPE_TEXT: true,
       
  9361   NODE_TYPE_COMMENT: true,
       
  9362   NODE_TYPE_DOCUMENT: true,
       
  9363   NODE_TYPE_DOCUMENT_FRAGMENT: true,
       
  9364 */
       
  9365 
       
  9366 ////////////////////////////////////
       
  9367 
       
  9368 /**
       
  9369  * @ngdoc module
       
  9370  * @name ng
       
  9371  * @module ng
       
  9372  * @description
       
  9373  *
       
  9374  * # ng (core module)
       
  9375  * The ng module is loaded by default when an AngularJS application is started. The module itself
       
  9376  * contains the essential components for an AngularJS application to function. The table below
       
  9377  * lists a high level breakdown of each of the services/factories, filters, directives and testing
       
  9378  * components available within this core module.
       
  9379  *
       
  9380  * <div doc-module-components="ng"></div>
       
  9381  */
       
  9382 
       
  9383 var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/;
       
  9384 
       
  9385 // The name of a form control's ValidityState property.
       
  9386 // This is used so that it's possible for internal tests to create mock ValidityStates.
       
  9387 var VALIDITY_STATE_PROPERTY = 'validity';
       
  9388 
       
  9389 /**
       
  9390  * @ngdoc function
       
  9391  * @name angular.lowercase
       
  9392  * @module ng
       
  9393  * @kind function
       
  9394  *
       
  9395  * @description Converts the specified string to lowercase.
       
  9396  * @param {string} string String to be converted to lowercase.
       
  9397  * @returns {string} Lowercased string.
       
  9398  */
       
  9399 var lowercase = function(string){return isString(string) ? string.toLowerCase() : string;};
       
  9400 var hasOwnProperty = Object.prototype.hasOwnProperty;
       
  9401 
       
  9402 /**
       
  9403  * @ngdoc function
       
  9404  * @name angular.uppercase
       
  9405  * @module ng
       
  9406  * @kind function
       
  9407  *
       
  9408  * @description Converts the specified string to uppercase.
       
  9409  * @param {string} string String to be converted to uppercase.
       
  9410  * @returns {string} Uppercased string.
       
  9411  */
       
  9412 var uppercase = function(string){return isString(string) ? string.toUpperCase() : string;};
       
  9413 
       
  9414 
       
  9415 var manualLowercase = function(s) {
       
  9416   /* jshint bitwise: false */
       
  9417   return isString(s)
       
  9418       ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);})
       
  9419       : s;
       
  9420 };
       
  9421 var manualUppercase = function(s) {
       
  9422   /* jshint bitwise: false */
       
  9423   return isString(s)
       
  9424       ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);})
       
  9425       : s;
       
  9426 };
       
  9427 
       
  9428 
       
  9429 // String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
       
  9430 // locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
       
  9431 // with correct but slower alternatives.
       
  9432 if ('i' !== 'I'.toLowerCase()) {
       
  9433   lowercase = manualLowercase;
       
  9434   uppercase = manualUppercase;
       
  9435 }
       
  9436 
       
  9437 
       
  9438 var /** holds major version number for IE or NaN for real browsers */
       
  9439     msie,
       
  9440     jqLite,           // delay binding since jQuery could be loaded after us.
       
  9441     jQuery,           // delay binding
       
  9442     slice             = [].slice,
       
  9443     splice            = [].splice,
       
  9444     push              = [].push,
       
  9445     toString          = Object.prototype.toString,
       
  9446     ngMinErr          = minErr('ng'),
       
  9447 
       
  9448     /** @name angular */
       
  9449     angular           = window.angular || (window.angular = {}),
       
  9450     angularModule,
       
  9451     uid               = 0;
       
  9452 
       
  9453 /**
       
  9454  * documentMode is an IE-only property
       
  9455  * http://msdn.microsoft.com/en-us/library/ie/cc196988(v=vs.85).aspx
       
  9456  */
       
  9457 msie = document.documentMode;
       
  9458 
       
  9459 
       
  9460 /**
       
  9461  * @private
       
  9462  * @param {*} obj
       
  9463  * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments,
       
  9464  *                   String ...)
       
  9465  */
       
  9466 function isArrayLike(obj) {
       
  9467   if (obj == null || isWindow(obj)) {
       
  9468     return false;
       
  9469   }
       
  9470 
       
  9471   var length = obj.length;
       
  9472 
       
  9473   if (obj.nodeType === NODE_TYPE_ELEMENT && length) {
       
  9474     return true;
       
  9475   }
       
  9476 
       
  9477   return isString(obj) || isArray(obj) || length === 0 ||
       
  9478          typeof length === 'number' && length > 0 && (length - 1) in obj;
       
  9479 }
       
  9480 
       
  9481 /**
       
  9482  * @ngdoc function
       
  9483  * @name angular.forEach
       
  9484  * @module ng
       
  9485  * @kind function
       
  9486  *
       
  9487  * @description
       
  9488  * Invokes the `iterator` function once for each item in `obj` collection, which can be either an
       
  9489  * object or an array. The `iterator` function is invoked with `iterator(value, key, obj)`, where `value`
       
  9490  * is the value of an object property or an array element, `key` is the object property key or
       
  9491  * array element index and obj is the `obj` itself. Specifying a `context` for the function is optional.
       
  9492  *
       
  9493  * It is worth noting that `.forEach` does not iterate over inherited properties because it filters
       
  9494  * using the `hasOwnProperty` method.
       
  9495  *
       
  9496    ```js
       
  9497      var values = {name: 'misko', gender: 'male'};
       
  9498      var log = [];
       
  9499      angular.forEach(values, function(value, key) {
       
  9500        this.push(key + ': ' + value);
       
  9501      }, log);
       
  9502      expect(log).toEqual(['name: misko', 'gender: male']);
       
  9503    ```
       
  9504  *
       
  9505  * @param {Object|Array} obj Object to iterate over.
       
  9506  * @param {Function} iterator Iterator function.
       
  9507  * @param {Object=} context Object to become context (`this`) for the iterator function.
       
  9508  * @returns {Object|Array} Reference to `obj`.
       
  9509  */
       
  9510 
       
  9511 function forEach(obj, iterator, context) {
       
  9512   var key, length;
       
  9513   if (obj) {
       
  9514     if (isFunction(obj)) {
       
  9515       for (key in obj) {
       
  9516         // Need to check if hasOwnProperty exists,
       
  9517         // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
       
  9518         if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
       
  9519           iterator.call(context, obj[key], key, obj);
       
  9520         }
       
  9521       }
       
  9522     } else if (isArray(obj) || isArrayLike(obj)) {
       
  9523       var isPrimitive = typeof obj !== 'object';
       
  9524       for (key = 0, length = obj.length; key < length; key++) {
       
  9525         if (isPrimitive || key in obj) {
       
  9526           iterator.call(context, obj[key], key, obj);
       
  9527         }
       
  9528       }
       
  9529     } else if (obj.forEach && obj.forEach !== forEach) {
       
  9530         obj.forEach(iterator, context, obj);
       
  9531     } else {
       
  9532       for (key in obj) {
       
  9533         if (obj.hasOwnProperty(key)) {
       
  9534           iterator.call(context, obj[key], key, obj);
       
  9535         }
       
  9536       }
       
  9537     }
       
  9538   }
       
  9539   return obj;
       
  9540 }
       
  9541 
       
  9542 function sortedKeys(obj) {
       
  9543   var keys = [];
       
  9544   for (var key in obj) {
       
  9545     if (obj.hasOwnProperty(key)) {
       
  9546       keys.push(key);
       
  9547     }
       
  9548   }
       
  9549   return keys.sort();
       
  9550 }
       
  9551 
       
  9552 function forEachSorted(obj, iterator, context) {
       
  9553   var keys = sortedKeys(obj);
       
  9554   for ( var i = 0; i < keys.length; i++) {
       
  9555     iterator.call(context, obj[keys[i]], keys[i]);
       
  9556   }
       
  9557   return keys;
       
  9558 }
       
  9559 
       
  9560 
       
  9561 /**
       
  9562  * when using forEach the params are value, key, but it is often useful to have key, value.
       
  9563  * @param {function(string, *)} iteratorFn
       
  9564  * @returns {function(*, string)}
       
  9565  */
       
  9566 function reverseParams(iteratorFn) {
       
  9567   return function(value, key) { iteratorFn(key, value); };
       
  9568 }
       
  9569 
       
  9570 /**
       
  9571  * A consistent way of creating unique IDs in angular.
       
  9572  *
       
  9573  * Using simple numbers allows us to generate 28.6 million unique ids per second for 10 years before
       
  9574  * we hit number precision issues in JavaScript.
       
  9575  *
       
  9576  * Math.pow(2,53) / 60 / 60 / 24 / 365 / 10 = 28.6M
       
  9577  *
       
  9578  * @returns {number} an unique alpha-numeric string
       
  9579  */
       
  9580 function nextUid() {
       
  9581   return ++uid;
       
  9582 }
       
  9583 
       
  9584 
       
  9585 /**
       
  9586  * Set or clear the hashkey for an object.
       
  9587  * @param obj object
       
  9588  * @param h the hashkey (!truthy to delete the hashkey)
       
  9589  */
       
  9590 function setHashKey(obj, h) {
       
  9591   if (h) {
       
  9592     obj.$$hashKey = h;
       
  9593   }
       
  9594   else {
       
  9595     delete obj.$$hashKey;
       
  9596   }
       
  9597 }
       
  9598 
       
  9599 /**
       
  9600  * @ngdoc function
       
  9601  * @name angular.extend
       
  9602  * @module ng
       
  9603  * @kind function
       
  9604  *
       
  9605  * @description
       
  9606  * Extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
       
  9607  * to `dst`. You can specify multiple `src` objects.
       
  9608  *
       
  9609  * @param {Object} dst Destination object.
       
  9610  * @param {...Object} src Source object(s).
       
  9611  * @returns {Object} Reference to `dst`.
       
  9612  */
       
  9613 function extend(dst) {
       
  9614   var h = dst.$$hashKey;
       
  9615 
       
  9616   for (var i = 1, ii = arguments.length; i < ii; i++) {
       
  9617     var obj = arguments[i];
       
  9618     if (obj) {
       
  9619       var keys = Object.keys(obj);
       
  9620       for (var j = 0, jj = keys.length; j < jj; j++) {
       
  9621         var key = keys[j];
       
  9622         dst[key] = obj[key];
       
  9623       }
       
  9624     }
       
  9625   }
       
  9626 
       
  9627   setHashKey(dst, h);
       
  9628   return dst;
       
  9629 }
       
  9630 
       
  9631 function int(str) {
       
  9632   return parseInt(str, 10);
       
  9633 }
       
  9634 
       
  9635 
       
  9636 function inherit(parent, extra) {
       
  9637   return extend(new (extend(function() {}, {prototype:parent}))(), extra);
       
  9638 }
       
  9639 
       
  9640 /**
       
  9641  * @ngdoc function
       
  9642  * @name angular.noop
       
  9643  * @module ng
       
  9644  * @kind function
       
  9645  *
       
  9646  * @description
       
  9647  * A function that performs no operations. This function can be useful when writing code in the
       
  9648  * functional style.
       
  9649    ```js
       
  9650      function foo(callback) {
       
  9651        var result = calculateResult();
       
  9652        (callback || angular.noop)(result);
       
  9653      }
       
  9654    ```
       
  9655  */
       
  9656 function noop() {}
       
  9657 noop.$inject = [];
       
  9658 
       
  9659 
       
  9660 /**
       
  9661  * @ngdoc function
       
  9662  * @name angular.identity
       
  9663  * @module ng
       
  9664  * @kind function
       
  9665  *
       
  9666  * @description
       
  9667  * A function that returns its first argument. This function is useful when writing code in the
       
  9668  * functional style.
       
  9669  *
       
  9670    ```js
       
  9671      function transformer(transformationFn, value) {
       
  9672        return (transformationFn || angular.identity)(value);
       
  9673      };
       
  9674    ```
       
  9675  */
       
  9676 function identity($) {return $;}
       
  9677 identity.$inject = [];
       
  9678 
       
  9679 
       
  9680 function valueFn(value) {return function() {return value;};}
       
  9681 
       
  9682 /**
       
  9683  * @ngdoc function
       
  9684  * @name angular.isUndefined
       
  9685  * @module ng
       
  9686  * @kind function
       
  9687  *
       
  9688  * @description
       
  9689  * Determines if a reference is undefined.
       
  9690  *
       
  9691  * @param {*} value Reference to check.
       
  9692  * @returns {boolean} True if `value` is undefined.
       
  9693  */
       
  9694 function isUndefined(value){return typeof value === 'undefined';}
       
  9695 
       
  9696 
       
  9697 /**
       
  9698  * @ngdoc function
       
  9699  * @name angular.isDefined
       
  9700  * @module ng
       
  9701  * @kind function
       
  9702  *
       
  9703  * @description
       
  9704  * Determines if a reference is defined.
       
  9705  *
       
  9706  * @param {*} value Reference to check.
       
  9707  * @returns {boolean} True if `value` is defined.
       
  9708  */
       
  9709 function isDefined(value){return typeof value !== 'undefined';}
       
  9710 
       
  9711 
       
  9712 /**
       
  9713  * @ngdoc function
       
  9714  * @name angular.isObject
       
  9715  * @module ng
       
  9716  * @kind function
       
  9717  *
       
  9718  * @description
       
  9719  * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not
       
  9720  * considered to be objects. Note that JavaScript arrays are objects.
       
  9721  *
       
  9722  * @param {*} value Reference to check.
       
  9723  * @returns {boolean} True if `value` is an `Object` but not `null`.
       
  9724  */
       
  9725 function isObject(value){
       
  9726   // http://jsperf.com/isobject4
       
  9727   return value !== null && typeof value === 'object';
       
  9728 }
       
  9729 
       
  9730 
       
  9731 /**
       
  9732  * @ngdoc function
       
  9733  * @name angular.isString
       
  9734  * @module ng
       
  9735  * @kind function
       
  9736  *
       
  9737  * @description
       
  9738  * Determines if a reference is a `String`.
       
  9739  *
       
  9740  * @param {*} value Reference to check.
       
  9741  * @returns {boolean} True if `value` is a `String`.
       
  9742  */
       
  9743 function isString(value){return typeof value === 'string';}
       
  9744 
       
  9745 
       
  9746 /**
       
  9747  * @ngdoc function
       
  9748  * @name angular.isNumber
       
  9749  * @module ng
       
  9750  * @kind function
       
  9751  *
       
  9752  * @description
       
  9753  * Determines if a reference is a `Number`.
       
  9754  *
       
  9755  * @param {*} value Reference to check.
       
  9756  * @returns {boolean} True if `value` is a `Number`.
       
  9757  */
       
  9758 function isNumber(value){return typeof value === 'number';}
       
  9759 
       
  9760 
       
  9761 /**
       
  9762  * @ngdoc function
       
  9763  * @name angular.isDate
       
  9764  * @module ng
       
  9765  * @kind function
       
  9766  *
       
  9767  * @description
       
  9768  * Determines if a value is a date.
       
  9769  *
       
  9770  * @param {*} value Reference to check.
       
  9771  * @returns {boolean} True if `value` is a `Date`.
       
  9772  */
       
  9773 function isDate(value) {
       
  9774   return toString.call(value) === '[object Date]';
       
  9775 }
       
  9776 
       
  9777 
       
  9778 /**
       
  9779  * @ngdoc function
       
  9780  * @name angular.isArray
       
  9781  * @module ng
       
  9782  * @kind function
       
  9783  *
       
  9784  * @description
       
  9785  * Determines if a reference is an `Array`.
       
  9786  *
       
  9787  * @param {*} value Reference to check.
       
  9788  * @returns {boolean} True if `value` is an `Array`.
       
  9789  */
       
  9790 var isArray = Array.isArray;
       
  9791 
       
  9792 /**
       
  9793  * @ngdoc function
       
  9794  * @name angular.isFunction
       
  9795  * @module ng
       
  9796  * @kind function
       
  9797  *
       
  9798  * @description
       
  9799  * Determines if a reference is a `Function`.
       
  9800  *
       
  9801  * @param {*} value Reference to check.
       
  9802  * @returns {boolean} True if `value` is a `Function`.
       
  9803  */
       
  9804 function isFunction(value){return typeof value === 'function';}
       
  9805 
       
  9806 
       
  9807 /**
       
  9808  * Determines if a value is a regular expression object.
       
  9809  *
       
  9810  * @private
       
  9811  * @param {*} value Reference to check.
       
  9812  * @returns {boolean} True if `value` is a `RegExp`.
       
  9813  */
       
  9814 function isRegExp(value) {
       
  9815   return toString.call(value) === '[object RegExp]';
       
  9816 }
       
  9817 
       
  9818 
       
  9819 /**
       
  9820  * Checks if `obj` is a window object.
       
  9821  *
       
  9822  * @private
       
  9823  * @param {*} obj Object to check
       
  9824  * @returns {boolean} True if `obj` is a window obj.
       
  9825  */
       
  9826 function isWindow(obj) {
       
  9827   return obj && obj.window === obj;
       
  9828 }
       
  9829 
       
  9830 
       
  9831 function isScope(obj) {
       
  9832   return obj && obj.$evalAsync && obj.$watch;
       
  9833 }
       
  9834 
       
  9835 
       
  9836 function isFile(obj) {
       
  9837   return toString.call(obj) === '[object File]';
       
  9838 }
       
  9839 
       
  9840 
       
  9841 function isBlob(obj) {
       
  9842   return toString.call(obj) === '[object Blob]';
       
  9843 }
       
  9844 
       
  9845 
       
  9846 function isBoolean(value) {
       
  9847   return typeof value === 'boolean';
       
  9848 }
       
  9849 
       
  9850 
       
  9851 function isPromiseLike(obj) {
       
  9852   return obj && isFunction(obj.then);
       
  9853 }
       
  9854 
       
  9855 
       
  9856 var trim = function(value) {
       
  9857   return isString(value) ? value.trim() : value;
       
  9858 };
       
  9859 
       
  9860 
       
  9861 /**
       
  9862  * @ngdoc function
       
  9863  * @name angular.isElement
       
  9864  * @module ng
       
  9865  * @kind function
       
  9866  *
       
  9867  * @description
       
  9868  * Determines if a reference is a DOM element (or wrapped jQuery element).
       
  9869  *
       
  9870  * @param {*} value Reference to check.
       
  9871  * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element).
       
  9872  */
       
  9873 function isElement(node) {
       
  9874   return !!(node &&
       
  9875     (node.nodeName  // we are a direct element
       
  9876     || (node.prop && node.attr && node.find)));  // we have an on and find method part of jQuery API
       
  9877 }
       
  9878 
       
  9879 /**
       
  9880  * @param str 'key1,key2,...'
       
  9881  * @returns {object} in the form of {key1:true, key2:true, ...}
       
  9882  */
       
  9883 function makeMap(str) {
       
  9884   var obj = {}, items = str.split(","), i;
       
  9885   for ( i = 0; i < items.length; i++ )
       
  9886     obj[ items[i] ] = true;
       
  9887   return obj;
       
  9888 }
       
  9889 
       
  9890 
       
  9891 function nodeName_(element) {
       
  9892   return lowercase(element.nodeName || element[0].nodeName);
       
  9893 }
       
  9894 
       
  9895 
       
  9896 /**
       
  9897  * @description
       
  9898  * Determines the number of elements in an array, the number of properties an object has, or
       
  9899  * the length of a string.
       
  9900  *
       
  9901  * Note: This function is used to augment the Object type in Angular expressions. See
       
  9902  * {@link angular.Object} for more information about Angular arrays.
       
  9903  *
       
  9904  * @param {Object|Array|string} obj Object, array, or string to inspect.
       
  9905  * @param {boolean} [ownPropsOnly=false] Count only "own" properties in an object
       
  9906  * @returns {number} The size of `obj` or `0` if `obj` is neither an object nor an array.
       
  9907  */
       
  9908 function size(obj, ownPropsOnly) {
       
  9909   var count = 0, key;
       
  9910 
       
  9911   if (isArray(obj) || isString(obj)) {
       
  9912     return obj.length;
       
  9913   } else if (isObject(obj)) {
       
  9914     for (key in obj)
       
  9915       if (!ownPropsOnly || obj.hasOwnProperty(key))
       
  9916         count++;
       
  9917   }
       
  9918 
       
  9919   return count;
       
  9920 }
       
  9921 
       
  9922 
       
  9923 function includes(array, obj) {
       
  9924   return Array.prototype.indexOf.call(array, obj) != -1;
       
  9925 }
       
  9926 
       
  9927 function arrayRemove(array, value) {
       
  9928   var index = array.indexOf(value);
       
  9929   if (index >=0)
       
  9930     array.splice(index, 1);
       
  9931   return value;
       
  9932 }
       
  9933 
       
  9934 function isLeafNode (node) {
       
  9935   if (node) {
       
  9936     switch (nodeName_(node)) {
       
  9937     case "option":
       
  9938     case "pre":
       
  9939     case "title":
       
  9940       return true;
       
  9941     }
       
  9942   }
       
  9943   return false;
       
  9944 }
       
  9945 
       
  9946 /**
       
  9947  * @ngdoc function
       
  9948  * @name angular.copy
       
  9949  * @module ng
       
  9950  * @kind function
       
  9951  *
       
  9952  * @description
       
  9953  * Creates a deep copy of `source`, which should be an object or an array.
       
  9954  *
       
  9955  * * If no destination is supplied, a copy of the object or array is created.
       
  9956  * * If a destination is provided, all of its elements (for array) or properties (for objects)
       
  9957  *   are deleted and then all elements/properties from the source are copied to it.
       
  9958  * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned.
       
  9959  * * If `source` is identical to 'destination' an exception will be thrown.
       
  9960  *
       
  9961  * @param {*} source The source that will be used to make a copy.
       
  9962  *                   Can be any type, including primitives, `null`, and `undefined`.
       
  9963  * @param {(Object|Array)=} destination Destination into which the source is copied. If
       
  9964  *     provided, must be of the same type as `source`.
       
  9965  * @returns {*} The copy or updated `destination`, if `destination` was specified.
       
  9966  *
       
  9967  * @example
       
  9968  <example module="copyExample">
       
  9969  <file name="index.html">
       
  9970  <div ng-controller="ExampleController">
       
  9971  <form novalidate class="simple-form">
       
  9972  Name: <input type="text" ng-model="user.name" /><br />
       
  9973  E-mail: <input type="email" ng-model="user.email" /><br />
       
  9974  Gender: <input type="radio" ng-model="user.gender" value="male" />male
       
  9975  <input type="radio" ng-model="user.gender" value="female" />female<br />
       
  9976  <button ng-click="reset()">RESET</button>
       
  9977  <button ng-click="update(user)">SAVE</button>
       
  9978  </form>
       
  9979  <pre>form = {{user | json}}</pre>
       
  9980  <pre>master = {{master | json}}</pre>
       
  9981  </div>
       
  9982 
       
  9983  <script>
       
  9984   angular.module('copyExample', [])
       
  9985     .controller('ExampleController', ['$scope', function($scope) {
       
  9986       $scope.master= {};
       
  9987 
       
  9988       $scope.update = function(user) {
       
  9989         // Example with 1 argument
       
  9990         $scope.master= angular.copy(user);
       
  9991       };
       
  9992 
       
  9993       $scope.reset = function() {
       
  9994         // Example with 2 arguments
       
  9995         angular.copy($scope.master, $scope.user);
       
  9996       };
       
  9997 
       
  9998       $scope.reset();
       
  9999     }]);
       
 10000  </script>
       
 10001  </file>
       
 10002  </example>
       
 10003  */
       
 10004 function copy(source, destination, stackSource, stackDest) {
       
 10005   if (isWindow(source) || isScope(source)) {
       
 10006     throw ngMinErr('cpws',
       
 10007       "Can't copy! Making copies of Window or Scope instances is not supported.");
       
 10008   }
       
 10009 
       
 10010   if (!destination) {
       
 10011     destination = source;
       
 10012     if (source) {
       
 10013       if (isArray(source)) {
       
 10014         destination = copy(source, [], stackSource, stackDest);
       
 10015       } else if (isDate(source)) {
       
 10016         destination = new Date(source.getTime());
       
 10017       } else if (isRegExp(source)) {
       
 10018         destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
       
 10019         destination.lastIndex = source.lastIndex;
       
 10020       } else if (isObject(source)) {
       
 10021         var emptyObject = Object.create(Object.getPrototypeOf(source));
       
 10022         destination = copy(source, emptyObject, stackSource, stackDest);
       
 10023       }
       
 10024     }
       
 10025   } else {
       
 10026     if (source === destination) throw ngMinErr('cpi',
       
 10027       "Can't copy! Source and destination are identical.");
       
 10028 
       
 10029     stackSource = stackSource || [];
       
 10030     stackDest = stackDest || [];
       
 10031 
       
 10032     if (isObject(source)) {
       
 10033       var index = stackSource.indexOf(source);
       
 10034       if (index !== -1) return stackDest[index];
       
 10035 
       
 10036       stackSource.push(source);
       
 10037       stackDest.push(destination);
       
 10038     }
       
 10039 
       
 10040     var result;
       
 10041     if (isArray(source)) {
       
 10042       destination.length = 0;
       
 10043       for ( var i = 0; i < source.length; i++) {
       
 10044         result = copy(source[i], null, stackSource, stackDest);
       
 10045         if (isObject(source[i])) {
       
 10046           stackSource.push(source[i]);
       
 10047           stackDest.push(result);
       
 10048         }
       
 10049         destination.push(result);
       
 10050       }
       
 10051     } else {
       
 10052       var h = destination.$$hashKey;
       
 10053       if (isArray(destination)) {
       
 10054         destination.length = 0;
       
 10055       } else {
       
 10056         forEach(destination, function(value, key) {
       
 10057           delete destination[key];
       
 10058         });
       
 10059       }
       
 10060       for ( var key in source) {
       
 10061         if(source.hasOwnProperty(key)) {
       
 10062           result = copy(source[key], null, stackSource, stackDest);
       
 10063           if (isObject(source[key])) {
       
 10064             stackSource.push(source[key]);
       
 10065             stackDest.push(result);
       
 10066           }
       
 10067           destination[key] = result;
       
 10068         }
       
 10069       }
       
 10070       setHashKey(destination,h);
       
 10071     }
       
 10072 
       
 10073   }
       
 10074   return destination;
       
 10075 }
       
 10076 
       
 10077 /**
       
 10078  * Creates a shallow copy of an object, an array or a primitive.
       
 10079  *
       
 10080  * Assumes that there are no proto properties for objects.
       
 10081  */
       
 10082 function shallowCopy(src, dst) {
       
 10083   if (isArray(src)) {
       
 10084     dst = dst || [];
       
 10085 
       
 10086     for (var i = 0, ii = src.length; i < ii; i++) {
       
 10087       dst[i] = src[i];
       
 10088     }
       
 10089   } else if (isObject(src)) {
       
 10090     dst = dst || {};
       
 10091 
       
 10092     for (var key in src) {
       
 10093       if (!(key.charAt(0) === '$' && key.charAt(1) === '$')) {
       
 10094         dst[key] = src[key];
       
 10095       }
       
 10096     }
       
 10097   }
       
 10098 
       
 10099   return dst || src;
       
 10100 }
       
 10101 
       
 10102 
       
 10103 /**
       
 10104  * @ngdoc function
       
 10105  * @name angular.equals
       
 10106  * @module ng
       
 10107  * @kind function
       
 10108  *
       
 10109  * @description
       
 10110  * Determines if two objects or two values are equivalent. Supports value types, regular
       
 10111  * expressions, arrays and objects.
       
 10112  *
       
 10113  * Two objects or values are considered equivalent if at least one of the following is true:
       
 10114  *
       
 10115  * * Both objects or values pass `===` comparison.
       
 10116  * * Both objects or values are of the same type and all of their properties are equal by
       
 10117  *   comparing them with `angular.equals`.
       
 10118  * * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal)
       
 10119  * * Both values represent the same regular expression (In JavaScript,
       
 10120  *   /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual
       
 10121  *   representation matches).
       
 10122  *
       
 10123  * During a property comparison, properties of `function` type and properties with names
       
 10124  * that begin with `$` are ignored.
       
 10125  *
       
 10126  * Scope and DOMWindow objects are being compared only by identify (`===`).
       
 10127  *
       
 10128  * @param {*} o1 Object or value to compare.
       
 10129  * @param {*} o2 Object or value to compare.
       
 10130  * @returns {boolean} True if arguments are equal.
       
 10131  */
       
 10132 function equals(o1, o2) {
       
 10133   if (o1 === o2) return true;
       
 10134   if (o1 === null || o2 === null) return false;
       
 10135   if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
       
 10136   var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
       
 10137   if (t1 == t2) {
       
 10138     if (t1 == 'object') {
       
 10139       if (isArray(o1)) {
       
 10140         if (!isArray(o2)) return false;
       
 10141         if ((length = o1.length) == o2.length) {
       
 10142           for(key=0; key<length; key++) {
       
 10143             if (!equals(o1[key], o2[key])) return false;
       
 10144           }
       
 10145           return true;
       
 10146         }
       
 10147       } else if (isDate(o1)) {
       
 10148         if (!isDate(o2)) return false;
       
 10149         return equals(o1.getTime(), o2.getTime());
       
 10150       } else if (isRegExp(o1) && isRegExp(o2)) {
       
 10151         return o1.toString() == o2.toString();
       
 10152       } else {
       
 10153         if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) || isArray(o2)) return false;
       
 10154         keySet = {};
       
 10155         for(key in o1) {
       
 10156           if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
       
 10157           if (!equals(o1[key], o2[key])) return false;
       
 10158           keySet[key] = true;
       
 10159         }
       
 10160         for(key in o2) {
       
 10161           if (!keySet.hasOwnProperty(key) &&
       
 10162               key.charAt(0) !== '$' &&
       
 10163               o2[key] !== undefined &&
       
 10164               !isFunction(o2[key])) return false;
       
 10165         }
       
 10166         return true;
       
 10167       }
       
 10168     }
       
 10169   }
       
 10170   return false;
       
 10171 }
       
 10172 
       
 10173 var csp = function() {
       
 10174   if (isDefined(csp.isActive_)) return csp.isActive_;
       
 10175 
       
 10176   var active = !!(document.querySelector('[ng-csp]') ||
       
 10177                   document.querySelector('[data-ng-csp]'));
       
 10178 
       
 10179   if (!active) {
       
 10180     try {
       
 10181       /* jshint -W031, -W054 */
       
 10182       new Function('');
       
 10183       /* jshint +W031, +W054 */
       
 10184     } catch (e) {
       
 10185       active = true;
       
 10186     }
       
 10187   }
       
 10188 
       
 10189   return (csp.isActive_ = active);
       
 10190 };
       
 10191 
       
 10192 
       
 10193 
       
 10194 function concat(array1, array2, index) {
       
 10195   return array1.concat(slice.call(array2, index));
       
 10196 }
       
 10197 
       
 10198 function sliceArgs(args, startIndex) {
       
 10199   return slice.call(args, startIndex || 0);
       
 10200 }
       
 10201 
       
 10202 
       
 10203 /* jshint -W101 */
       
 10204 /**
       
 10205  * @ngdoc function
       
 10206  * @name angular.bind
       
 10207  * @module ng
       
 10208  * @kind function
       
 10209  *
       
 10210  * @description
       
 10211  * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
       
 10212  * `fn`). You can supply optional `args` that are prebound to the function. This feature is also
       
 10213  * known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as
       
 10214  * distinguished from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application).
       
 10215  *
       
 10216  * @param {Object} self Context which `fn` should be evaluated in.
       
 10217  * @param {function()} fn Function to be bound.
       
 10218  * @param {...*} args Optional arguments to be prebound to the `fn` function call.
       
 10219  * @returns {function()} Function that wraps the `fn` with all the specified bindings.
       
 10220  */
       
 10221 /* jshint +W101 */
       
 10222 function bind(self, fn) {
       
 10223   var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : [];
       
 10224   if (isFunction(fn) && !(fn instanceof RegExp)) {
       
 10225     return curryArgs.length
       
 10226       ? function() {
       
 10227           return arguments.length
       
 10228             ? fn.apply(self, curryArgs.concat(slice.call(arguments, 0)))
       
 10229             : fn.apply(self, curryArgs);
       
 10230         }
       
 10231       : function() {
       
 10232           return arguments.length
       
 10233             ? fn.apply(self, arguments)
       
 10234             : fn.call(self);
       
 10235         };
       
 10236   } else {
       
 10237     // in IE, native methods are not functions so they cannot be bound (note: they don't need to be)
       
 10238     return fn;
       
 10239   }
       
 10240 }
       
 10241 
       
 10242 
       
 10243 function toJsonReplacer(key, value) {
       
 10244   var val = value;
       
 10245 
       
 10246   if (typeof key === 'string' && key.charAt(0) === '$' && key.charAt(1) === '$') {
       
 10247     val = undefined;
       
 10248   } else if (isWindow(value)) {
       
 10249     val = '$WINDOW';
       
 10250   } else if (value &&  document === value) {
       
 10251     val = '$DOCUMENT';
       
 10252   } else if (isScope(value)) {
       
 10253     val = '$SCOPE';
       
 10254   }
       
 10255 
       
 10256   return val;
       
 10257 }
       
 10258 
       
 10259 
       
 10260 /**
       
 10261  * @ngdoc function
       
 10262  * @name angular.toJson
       
 10263  * @module ng
       
 10264  * @kind function
       
 10265  *
       
 10266  * @description
       
 10267  * Serializes input into a JSON-formatted string. Properties with leading $$ characters will be
       
 10268  * stripped since angular uses this notation internally.
       
 10269  *
       
 10270  * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON.
       
 10271  * @param {boolean=} pretty If set to true, the JSON output will contain newlines and whitespace.
       
 10272  * @returns {string|undefined} JSON-ified string representing `obj`.
       
 10273  */
       
 10274 function toJson(obj, pretty) {
       
 10275   if (typeof obj === 'undefined') return undefined;
       
 10276   return JSON.stringify(obj, toJsonReplacer, pretty ? '  ' : null);
       
 10277 }
       
 10278 
       
 10279 
       
 10280 /**
       
 10281  * @ngdoc function
       
 10282  * @name angular.fromJson
       
 10283  * @module ng
       
 10284  * @kind function
       
 10285  *
       
 10286  * @description
       
 10287  * Deserializes a JSON string.
       
 10288  *
       
 10289  * @param {string} json JSON string to deserialize.
       
 10290  * @returns {Object|Array|string|number} Deserialized thingy.
       
 10291  */
       
 10292 function fromJson(json) {
       
 10293   return isString(json)
       
 10294       ? JSON.parse(json)
       
 10295       : json;
       
 10296 }
       
 10297 
       
 10298 
       
 10299 /**
       
 10300  * @returns {string} Returns the string representation of the element.
       
 10301  */
       
 10302 function startingTag(element) {
       
 10303   element = jqLite(element).clone();
       
 10304   try {
       
 10305     // turns out IE does not let you set .html() on elements which
       
 10306     // are not allowed to have children. So we just ignore it.
       
 10307     element.empty();
       
 10308   } catch(e) {}
       
 10309   var elemHtml = jqLite('<div>').append(element).html();
       
 10310   try {
       
 10311     return element[0].nodeType === NODE_TYPE_TEXT ? lowercase(elemHtml) :
       
 10312         elemHtml.
       
 10313           match(/^(<[^>]+>)/)[1].
       
 10314           replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });
       
 10315   } catch(e) {
       
 10316     return lowercase(elemHtml);
       
 10317   }
       
 10318 
       
 10319 }
       
 10320 
       
 10321 
       
 10322 /////////////////////////////////////////////////
       
 10323 
       
 10324 /**
       
 10325  * Tries to decode the URI component without throwing an exception.
       
 10326  *
       
 10327  * @private
       
 10328  * @param str value potential URI component to check.
       
 10329  * @returns {boolean} True if `value` can be decoded
       
 10330  * with the decodeURIComponent function.
       
 10331  */
       
 10332 function tryDecodeURIComponent(value) {
       
 10333   try {
       
 10334     return decodeURIComponent(value);
       
 10335   } catch(e) {
       
 10336     // Ignore any invalid uri component
       
 10337   }
       
 10338 }
       
 10339 
       
 10340 
       
 10341 /**
       
 10342  * Parses an escaped url query string into key-value pairs.
       
 10343  * @returns {Object.<string,boolean|Array>}
       
 10344  */
       
 10345 function parseKeyValue(/**string*/keyValue) {
       
 10346   var obj = {}, key_value, key;
       
 10347   forEach((keyValue || "").split('&'), function(keyValue) {
       
 10348     if ( keyValue ) {
       
 10349       key_value = keyValue.replace(/\+/g,'%20').split('=');
       
 10350       key = tryDecodeURIComponent(key_value[0]);
       
 10351       if ( isDefined(key) ) {
       
 10352         var val = isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true;
       
 10353         if (!hasOwnProperty.call(obj, key)) {
       
 10354           obj[key] = val;
       
 10355         } else if(isArray(obj[key])) {
       
 10356           obj[key].push(val);
       
 10357         } else {
       
 10358           obj[key] = [obj[key],val];
       
 10359         }
       
 10360       }
       
 10361     }
       
 10362   });
       
 10363   return obj;
       
 10364 }
       
 10365 
       
 10366 function toKeyValue(obj) {
       
 10367   var parts = [];
       
 10368   forEach(obj, function(value, key) {
       
 10369     if (isArray(value)) {
       
 10370       forEach(value, function(arrayValue) {
       
 10371         parts.push(encodeUriQuery(key, true) +
       
 10372                    (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true)));
       
 10373       });
       
 10374     } else {
       
 10375     parts.push(encodeUriQuery(key, true) +
       
 10376                (value === true ? '' : '=' + encodeUriQuery(value, true)));
       
 10377     }
       
 10378   });
       
 10379   return parts.length ? parts.join('&') : '';
       
 10380 }
       
 10381 
       
 10382 
       
 10383 /**
       
 10384  * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
       
 10385  * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
       
 10386  * segments:
       
 10387  *    segment       = *pchar
       
 10388  *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
       
 10389  *    pct-encoded   = "%" HEXDIG HEXDIG
       
 10390  *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
       
 10391  *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
       
 10392  *                     / "*" / "+" / "," / ";" / "="
       
 10393  */
       
 10394 function encodeUriSegment(val) {
       
 10395   return encodeUriQuery(val, true).
       
 10396              replace(/%26/gi, '&').
       
 10397              replace(/%3D/gi, '=').
       
 10398              replace(/%2B/gi, '+');
       
 10399 }
       
 10400 
       
 10401 
       
 10402 /**
       
 10403  * This method is intended for encoding *key* or *value* parts of query component. We need a custom
       
 10404  * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
       
 10405  * encoded per http://tools.ietf.org/html/rfc3986:
       
 10406  *    query       = *( pchar / "/" / "?" )
       
 10407  *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
       
 10408  *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
       
 10409  *    pct-encoded   = "%" HEXDIG HEXDIG
       
 10410  *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
       
 10411  *                     / "*" / "+" / "," / ";" / "="
       
 10412  */
       
 10413 function encodeUriQuery(val, pctEncodeSpaces) {
       
 10414   return encodeURIComponent(val).
       
 10415              replace(/%40/gi, '@').
       
 10416              replace(/%3A/gi, ':').
       
 10417              replace(/%24/g, '$').
       
 10418              replace(/%2C/gi, ',').
       
 10419              replace(/%3B/gi, ';').
       
 10420              replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
       
 10421 }
       
 10422 
       
 10423 var ngAttrPrefixes = ['ng-', 'data-ng-', 'ng:', 'x-ng-'];
       
 10424 
       
 10425 function getNgAttribute(element, ngAttr) {
       
 10426   var attr, i, ii = ngAttrPrefixes.length;
       
 10427   element = jqLite(element);
       
 10428   for (i=0; i<ii; ++i) {
       
 10429     attr = ngAttrPrefixes[i] + ngAttr;
       
 10430     if (isString(attr = element.attr(attr))) {
       
 10431       return attr;
       
 10432     }
       
 10433   }
       
 10434   return null;
       
 10435 }
       
 10436 
       
 10437 /**
       
 10438  * @ngdoc directive
       
 10439  * @name ngApp
       
 10440  * @module ng
       
 10441  *
       
 10442  * @element ANY
       
 10443  * @param {angular.Module} ngApp an optional application
       
 10444  *   {@link angular.module module} name to load.
       
 10445  * @param {boolean=} ngStrictDi if this attribute is present on the app element, the injector will be
       
 10446  *   created in "strict-di" mode. This means that the application will fail to invoke functions which
       
 10447  *   do not use explicit function annotation (and are thus unsuitable for minification), as described
       
 10448  *   in {@link guide/di the Dependency Injection guide}, and useful debugging info will assist in
       
 10449  *   tracking down the root of these bugs.
       
 10450  *
       
 10451  * @description
       
 10452  *
       
 10453  * Use this directive to **auto-bootstrap** an AngularJS application. The `ngApp` directive
       
 10454  * designates the **root element** of the application and is typically placed near the root element
       
 10455  * of the page - e.g. on the `<body>` or `<html>` tags.
       
 10456  *
       
 10457  * Only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngApp`
       
 10458  * found in the document will be used to define the root element to auto-bootstrap as an
       
 10459  * application. To run multiple applications in an HTML document you must manually bootstrap them using
       
 10460  * {@link angular.bootstrap} instead. AngularJS applications cannot be nested within each other.
       
 10461  *
       
 10462  * You can specify an **AngularJS module** to be used as the root module for the application.  This
       
 10463  * module will be loaded into the {@link auto.$injector} when the application is bootstrapped and
       
 10464  * should contain the application code needed or have dependencies on other modules that will
       
 10465  * contain the code. See {@link angular.module} for more information.
       
 10466  *
       
 10467  * In the example below if the `ngApp` directive were not placed on the `html` element then the
       
 10468  * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}`
       
 10469  * would not be resolved to `3`.
       
 10470  *
       
 10471  * `ngApp` is the easiest, and most common, way to bootstrap an application.
       
 10472  *
       
 10473  <example module="ngAppDemo">
       
 10474    <file name="index.html">
       
 10475    <div ng-controller="ngAppDemoController">
       
 10476      I can add: {{a}} + {{b}} =  {{ a+b }}
       
 10477    </div>
       
 10478    </file>
       
 10479    <file name="script.js">
       
 10480    angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) {
       
 10481      $scope.a = 1;
       
 10482      $scope.b = 2;
       
 10483    });
       
 10484    </file>
       
 10485  </example>
       
 10486  *
       
 10487  * Using `ngStrictDi`, you would see something like this:
       
 10488  *
       
 10489  <example ng-app-included="true">
       
 10490    <file name="index.html">
       
 10491    <div ng-app="ngAppStrictDemo" ng-strict-di>
       
 10492        <div ng-controller="GoodController1">
       
 10493            I can add: {{a}} + {{b}} =  {{ a+b }}
       
 10494 
       
 10495            <p>This renders because the controller does not fail to
       
 10496               instantiate, by using explicit annotation style (see
       
 10497               script.js for details)
       
 10498            </p>
       
 10499        </div>
       
 10500 
       
 10501        <div ng-controller="GoodController2">
       
 10502            Name: <input ng-model="name"><br />
       
 10503            Hello, {{name}}!
       
 10504 
       
 10505            <p>This renders because the controller does not fail to
       
 10506               instantiate, by using explicit annotation style
       
 10507               (see script.js for details)
       
 10508            </p>
       
 10509        </div>
       
 10510 
       
 10511        <div ng-controller="BadController">
       
 10512            I can add: {{a}} + {{b}} =  {{ a+b }}
       
 10513 
       
 10514            <p>The controller could not be instantiated, due to relying
       
 10515               on automatic function annotations (which are disabled in
       
 10516               strict mode). As such, the content of this section is not
       
 10517               interpolated, and there should be an error in your web console.
       
 10518            </p>
       
 10519        </div>
       
 10520    </div>
       
 10521    </file>
       
 10522    <file name="script.js">
       
 10523    angular.module('ngAppStrictDemo', [])
       
 10524      // BadController will fail to instantiate, due to relying on automatic function annotation,
       
 10525      // rather than an explicit annotation
       
 10526      .controller('BadController', function($scope) {
       
 10527        $scope.a = 1;
       
 10528        $scope.b = 2;
       
 10529      })
       
 10530      // Unlike BadController, GoodController1 and GoodController2 will not fail to be instantiated,
       
 10531      // due to using explicit annotations using the array style and $inject property, respectively.
       
 10532      .controller('GoodController1', ['$scope', function($scope) {
       
 10533        $scope.a = 1;
       
 10534        $scope.b = 2;
       
 10535      }])
       
 10536      .controller('GoodController2', GoodController2);
       
 10537      function GoodController2($scope) {
       
 10538        $scope.name = "World";
       
 10539      }
       
 10540      GoodController2.$inject = ['$scope'];
       
 10541    </file>
       
 10542    <file name="style.css">
       
 10543    div[ng-controller] {
       
 10544        margin-bottom: 1em;
       
 10545        -webkit-border-radius: 4px;
       
 10546        border-radius: 4px;
       
 10547        border: 1px solid;
       
 10548        padding: .5em;
       
 10549    }
       
 10550    div[ng-controller^=Good] {
       
 10551        border-color: #d6e9c6;
       
 10552        background-color: #dff0d8;
       
 10553        color: #3c763d;
       
 10554    }
       
 10555    div[ng-controller^=Bad] {
       
 10556        border-color: #ebccd1;
       
 10557        background-color: #f2dede;
       
 10558        color: #a94442;
       
 10559        margin-bottom: 0;
       
 10560    }
       
 10561    </file>
       
 10562  </example>
       
 10563  */
       
 10564 function angularInit(element, bootstrap) {
       
 10565   var appElement,
       
 10566       module,
       
 10567       config = {};
       
 10568 
       
 10569   // The element `element` has priority over any other element
       
 10570   forEach(ngAttrPrefixes, function(prefix) {
       
 10571     var name = prefix + 'app';
       
 10572 
       
 10573     if (!appElement && element.hasAttribute && element.hasAttribute(name)) {
       
 10574       appElement = element;
       
 10575       module = element.getAttribute(name);
       
 10576     }
       
 10577   });
       
 10578   forEach(ngAttrPrefixes, function(prefix) {
       
 10579     var name = prefix + 'app';
       
 10580     var candidate;
       
 10581 
       
 10582     if (!appElement && (candidate = element.querySelector('[' + name.replace(':', '\\:') + ']'))) {
       
 10583       appElement = candidate;
       
 10584       module = candidate.getAttribute(name);
       
 10585     }
       
 10586   });
       
 10587   if (appElement) {
       
 10588     config.strictDi = getNgAttribute(appElement, "strict-di") !== null;
       
 10589     bootstrap(appElement, module ? [module] : [], config);
       
 10590   }
       
 10591 }
       
 10592 
       
 10593 /**
       
 10594  * @ngdoc function
       
 10595  * @name angular.bootstrap
       
 10596  * @module ng
       
 10597  * @description
       
 10598  * Use this function to manually start up angular application.
       
 10599  *
       
 10600  * See: {@link guide/bootstrap Bootstrap}
       
 10601  *
       
 10602  * Note that Protractor based end-to-end tests cannot use this function to bootstrap manually.
       
 10603  * They must use {@link ng.directive:ngApp ngApp}.
       
 10604  *
       
 10605  * Angular will detect if it has been loaded into the browser more than once and only allow the
       
 10606  * first loaded script to be bootstrapped and will report a warning to the browser console for
       
 10607  * each of the subsequent scripts. This prevents strange results in applications, where otherwise
       
 10608  * multiple instances of Angular try to work on the DOM.
       
 10609  *
       
 10610  * ```html
       
 10611  * <!doctype html>
       
 10612  * <html>
       
 10613  * <body>
       
 10614  * <div ng-controller="WelcomeController">
       
 10615  *   {{greeting}}
       
 10616  * </div>
       
 10617  *
       
 10618  * <script src="angular.js"></script>
       
 10619  * <script>
       
 10620  *   var app = angular.module('demo', [])
       
 10621  *   .controller('WelcomeController', function($scope) {
       
 10622  *       $scope.greeting = 'Welcome!';
       
 10623  *   });
       
 10624  *   angular.bootstrap(document, ['demo']);
       
 10625  * </script>
       
 10626  * </body>
       
 10627  * </html>
       
 10628  * ```
       
 10629  *
       
 10630  * @param {DOMElement} element DOM element which is the root of angular application.
       
 10631  * @param {Array<String|Function|Array>=} modules an array of modules to load into the application.
       
 10632  *     Each item in the array should be the name of a predefined module or a (DI annotated)
       
 10633  *     function that will be invoked by the injector as a run block.
       
 10634  *     See: {@link angular.module modules}
       
 10635  * @param {Object=} config an object for defining configuration options for the application. The
       
 10636  *     following keys are supported:
       
 10637  *
       
 10638  *     - `strictDi`: disable automatic function annotation for the application. This is meant to
       
 10639  *       assist in finding bugs which break minified code.
       
 10640  *
       
 10641  * @returns {auto.$injector} Returns the newly created injector for this app.
       
 10642  */
       
 10643 function bootstrap(element, modules, config) {
       
 10644   if (!isObject(config)) config = {};
       
 10645   var defaultConfig = {
       
 10646     strictDi: false
       
 10647   };
       
 10648   config = extend(defaultConfig, config);
       
 10649   var doBootstrap = function() {
       
 10650     element = jqLite(element);
       
 10651 
       
 10652     if (element.injector()) {
       
 10653       var tag = (element[0] === document) ? 'document' : startingTag(element);
       
 10654       //Encode angle brackets to prevent input from being sanitized to empty string #8683
       
 10655       throw ngMinErr(
       
 10656           'btstrpd',
       
 10657           "App Already Bootstrapped with this Element '{0}'",
       
 10658           tag.replace(/</,'&lt;').replace(/>/,'&gt;'));
       
 10659     }
       
 10660 
       
 10661     modules = modules || [];
       
 10662     modules.unshift(['$provide', function($provide) {
       
 10663       $provide.value('$rootElement', element);
       
 10664     }]);
       
 10665 
       
 10666     if (config.debugInfoEnabled) {
       
 10667       // Pushing so that this overrides `debugInfoEnabled` setting defined in user's `modules`.
       
 10668       modules.push(['$compileProvider', function($compileProvider) {
       
 10669         $compileProvider.debugInfoEnabled(true);
       
 10670       }]);
       
 10671     }
       
 10672 
       
 10673     modules.unshift('ng');
       
 10674     var injector = createInjector(modules, config.strictDi);
       
 10675     injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector',
       
 10676        function bootstrapApply(scope, element, compile, injector) {
       
 10677         scope.$apply(function() {
       
 10678           element.data('$injector', injector);
       
 10679           compile(element)(scope);
       
 10680         });
       
 10681       }]
       
 10682     );
       
 10683     return injector;
       
 10684   };
       
 10685 
       
 10686   var NG_ENABLE_DEBUG_INFO = /^NG_ENABLE_DEBUG_INFO!/;
       
 10687   var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;
       
 10688 
       
 10689   if (window && NG_ENABLE_DEBUG_INFO.test(window.name)) {
       
 10690     config.debugInfoEnabled = true;
       
 10691     window.name = window.name.replace(NG_ENABLE_DEBUG_INFO, '');
       
 10692   }
       
 10693 
       
 10694   if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
       
 10695     return doBootstrap();
       
 10696   }
       
 10697 
       
 10698   window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
       
 10699   angular.resumeBootstrap = function(extraModules) {
       
 10700     forEach(extraModules, function(module) {
       
 10701       modules.push(module);
       
 10702     });
       
 10703     doBootstrap();
       
 10704   };
       
 10705 }
       
 10706 
       
 10707 /**
       
 10708  * @ngdoc function
       
 10709  * @name angular.reloadWithDebugInfo
       
 10710  * @module ng
       
 10711  * @description
       
 10712  * Use this function to reload the current application with debug information turned on.
       
 10713  * This takes precedence over a call to `$compileProvider.debugInfoEnabled(false)`.
       
 10714  *
       
 10715  * See {@link ng.$compileProvider#debugInfoEnabled} for more.
       
 10716  */
       
 10717 function reloadWithDebugInfo() {
       
 10718   window.name = 'NG_ENABLE_DEBUG_INFO!' + window.name;
       
 10719   window.location.reload();
       
 10720 }
       
 10721 
       
 10722 /**
       
 10723  * @name angular.getTestability
       
 10724  * @module ng
       
 10725  * @description
       
 10726  * Get the testability service for the instance of Angular on the given
       
 10727  * element.
       
 10728  * @param {DOMElement} element DOM element which is the root of angular application.
       
 10729  */
       
 10730 function getTestability(rootElement) {
       
 10731   return angular.element(rootElement).injector().get('$$testability');
       
 10732 }
       
 10733 
       
 10734 var SNAKE_CASE_REGEXP = /[A-Z]/g;
       
 10735 function snake_case(name, separator) {
       
 10736   separator = separator || '_';
       
 10737   return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) {
       
 10738     return (pos ? separator : '') + letter.toLowerCase();
       
 10739   });
       
 10740 }
       
 10741 
       
 10742 var bindJQueryFired = false;
       
 10743 var skipDestroyOnNextJQueryCleanData;
       
 10744 function bindJQuery() {
       
 10745   var originalCleanData;
       
 10746 
       
 10747   if (bindJQueryFired) {
       
 10748     return;
       
 10749   }
       
 10750 
       
 10751   // bind to jQuery if present;
       
 10752   jQuery = window.jQuery;
       
 10753   // Use jQuery if it exists with proper functionality, otherwise default to us.
       
 10754   // Angular 1.2+ requires jQuery 1.7+ for on()/off() support.
       
 10755   // Angular 1.3+ technically requires at least jQuery 2.1+ but it may work with older
       
 10756   // versions. It will not work for sure with jQuery <1.7, though.
       
 10757   if (jQuery && jQuery.fn.on) {
       
 10758     jqLite = jQuery;
       
 10759     extend(jQuery.fn, {
       
 10760       scope: JQLitePrototype.scope,
       
 10761       isolateScope: JQLitePrototype.isolateScope,
       
 10762       controller: JQLitePrototype.controller,
       
 10763       injector: JQLitePrototype.injector,
       
 10764       inheritedData: JQLitePrototype.inheritedData
       
 10765     });
       
 10766 
       
 10767     // All nodes removed from the DOM via various jQuery APIs like .remove()
       
 10768     // are passed through jQuery.cleanData. Monkey-patch this method to fire
       
 10769     // the $destroy event on all removed nodes.
       
 10770     originalCleanData = jQuery.cleanData;
       
 10771     jQuery.cleanData = function(elems) {
       
 10772       var events;
       
 10773       if (!skipDestroyOnNextJQueryCleanData) {
       
 10774         for (var i = 0, elem; (elem = elems[i]) != null; i++) {
       
 10775           events = jQuery._data(elem, "events");
       
 10776           if (events && events.$destroy) {
       
 10777             jQuery(elem).triggerHandler('$destroy');
       
 10778           }
       
 10779         }
       
 10780       } else {
       
 10781         skipDestroyOnNextJQueryCleanData = false;
       
 10782       }
       
 10783       originalCleanData(elems);
       
 10784     };
       
 10785   } else {
       
 10786     jqLite = JQLite;
       
 10787   }
       
 10788 
       
 10789   angular.element = jqLite;
       
 10790 
       
 10791   // Prevent double-proxying.
       
 10792   bindJQueryFired = true;
       
 10793 }
       
 10794 
       
 10795 /**
       
 10796  * throw error if the argument is falsy.
       
 10797  */
       
 10798 function assertArg(arg, name, reason) {
       
 10799   if (!arg) {
       
 10800     throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required"));
       
 10801   }
       
 10802   return arg;
       
 10803 }
       
 10804 
       
 10805 function assertArgFn(arg, name, acceptArrayAnnotation) {
       
 10806   if (acceptArrayAnnotation && isArray(arg)) {
       
 10807       arg = arg[arg.length - 1];
       
 10808   }
       
 10809 
       
 10810   assertArg(isFunction(arg), name, 'not a function, got ' +
       
 10811       (arg && typeof arg === 'object' ? arg.constructor.name || 'Object' : typeof arg));
       
 10812   return arg;
       
 10813 }
       
 10814 
       
 10815 /**
       
 10816  * throw error if the name given is hasOwnProperty
       
 10817  * @param  {String} name    the name to test
       
 10818  * @param  {String} context the context in which the name is used, such as module or directive
       
 10819  */
       
 10820 function assertNotHasOwnProperty(name, context) {
       
 10821   if (name === 'hasOwnProperty') {
       
 10822     throw ngMinErr('badname', "hasOwnProperty is not a valid {0} name", context);
       
 10823   }
       
 10824 }
       
 10825 
       
 10826 /**
       
 10827  * Return the value accessible from the object by path. Any undefined traversals are ignored
       
 10828  * @param {Object} obj starting object
       
 10829  * @param {String} path path to traverse
       
 10830  * @param {boolean} [bindFnToScope=true]
       
 10831  * @returns {Object} value as accessible by path
       
 10832  */
       
 10833 //TODO(misko): this function needs to be removed
       
 10834 function getter(obj, path, bindFnToScope) {
       
 10835   if (!path) return obj;
       
 10836   var keys = path.split('.');
       
 10837   var key;
       
 10838   var lastInstance = obj;
       
 10839   var len = keys.length;
       
 10840 
       
 10841   for (var i = 0; i < len; i++) {
       
 10842     key = keys[i];
       
 10843     if (obj) {
       
 10844       obj = (lastInstance = obj)[key];
       
 10845     }
       
 10846   }
       
 10847   if (!bindFnToScope && isFunction(obj)) {
       
 10848     return bind(lastInstance, obj);
       
 10849   }
       
 10850   return obj;
       
 10851 }
       
 10852 
       
 10853 /**
       
 10854  * Return the DOM siblings between the first and last node in the given array.
       
 10855  * @param {Array} array like object
       
 10856  * @returns {jqLite} jqLite collection containing the nodes
       
 10857  */
       
 10858 function getBlockNodes(nodes) {
       
 10859   // TODO(perf): just check if all items in `nodes` are siblings and if they are return the original
       
 10860   //             collection, otherwise update the original collection.
       
 10861   var node = nodes[0];
       
 10862   var endNode = nodes[nodes.length - 1];
       
 10863   var blockNodes = [node];
       
 10864 
       
 10865   do {
       
 10866     node = node.nextSibling;
       
 10867     if (!node) break;
       
 10868     blockNodes.push(node);
       
 10869   } while (node !== endNode);
       
 10870 
       
 10871   return jqLite(blockNodes);
       
 10872 }
       
 10873 
       
 10874 
       
 10875 /**
       
 10876  * Creates a new object without a prototype. This object is useful for lookup without having to
       
 10877  * guard against prototypically inherited properties via hasOwnProperty.
       
 10878  *
       
 10879  * Related micro-benchmarks:
       
 10880  * - http://jsperf.com/object-create2
       
 10881  * - http://jsperf.com/proto-map-lookup/2
       
 10882  * - http://jsperf.com/for-in-vs-object-keys2
       
 10883  *
       
 10884  * @returns {Object}
       
 10885  */
       
 10886 function createMap() {
       
 10887   return Object.create(null);
       
 10888 }
       
 10889 
       
 10890 var NODE_TYPE_ELEMENT = 1;
       
 10891 var NODE_TYPE_TEXT = 3;
       
 10892 var NODE_TYPE_COMMENT = 8;
       
 10893 var NODE_TYPE_DOCUMENT = 9;
       
 10894 var NODE_TYPE_DOCUMENT_FRAGMENT = 11;
       
 10895 
       
 10896 /**
       
 10897  * @ngdoc type
       
 10898  * @name angular.Module
       
 10899  * @module ng
       
 10900  * @description
       
 10901  *
       
 10902  * Interface for configuring angular {@link angular.module modules}.
       
 10903  */
       
 10904 
       
 10905 function setupModuleLoader(window) {
       
 10906 
       
 10907   var $injectorMinErr = minErr('$injector');
       
 10908   var ngMinErr = minErr('ng');
       
 10909 
       
 10910   function ensure(obj, name, factory) {
       
 10911     return obj[name] || (obj[name] = factory());
       
 10912   }
       
 10913 
       
 10914   var angular = ensure(window, 'angular', Object);
       
 10915 
       
 10916   // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap
       
 10917   angular.$$minErr = angular.$$minErr || minErr;
       
 10918 
       
 10919   return ensure(angular, 'module', function() {
       
 10920     /** @type {Object.<string, angular.Module>} */
       
 10921     var modules = {};
       
 10922 
       
 10923     /**
       
 10924      * @ngdoc function
       
 10925      * @name angular.module
       
 10926      * @module ng
       
 10927      * @description
       
 10928      *
       
 10929      * The `angular.module` is a global place for creating, registering and retrieving Angular
       
 10930      * modules.
       
 10931      * All modules (angular core or 3rd party) that should be available to an application must be
       
 10932      * registered using this mechanism.
       
 10933      *
       
 10934      * When passed two or more arguments, a new module is created.  If passed only one argument, an
       
 10935      * existing module (the name passed as the first argument to `module`) is retrieved.
       
 10936      *
       
 10937      *
       
 10938      * # Module
       
 10939      *
       
 10940      * A module is a collection of services, directives, controllers, filters, and configuration information.
       
 10941      * `angular.module` is used to configure the {@link auto.$injector $injector}.
       
 10942      *
       
 10943      * ```js
       
 10944      * // Create a new module
       
 10945      * var myModule = angular.module('myModule', []);
       
 10946      *
       
 10947      * // register a new service
       
 10948      * myModule.value('appName', 'MyCoolApp');
       
 10949      *
       
 10950      * // configure existing services inside initialization blocks.
       
 10951      * myModule.config(['$locationProvider', function($locationProvider) {
       
 10952      *   // Configure existing providers
       
 10953      *   $locationProvider.hashPrefix('!');
       
 10954      * }]);
       
 10955      * ```
       
 10956      *
       
 10957      * Then you can create an injector and load your modules like this:
       
 10958      *
       
 10959      * ```js
       
 10960      * var injector = angular.injector(['ng', 'myModule'])
       
 10961      * ```
       
 10962      *
       
 10963      * However it's more likely that you'll just use
       
 10964      * {@link ng.directive:ngApp ngApp} or
       
 10965      * {@link angular.bootstrap} to simplify this process for you.
       
 10966      *
       
 10967      * @param {!string} name The name of the module to create or retrieve.
       
 10968      * @param {!Array.<string>=} requires If specified then new module is being created. If
       
 10969      *        unspecified then the module is being retrieved for further configuration.
       
 10970      * @param {Function=} configFn Optional configuration function for the module. Same as
       
 10971      *        {@link angular.Module#config Module#config()}.
       
 10972      * @returns {module} new module with the {@link angular.Module} api.
       
 10973      */
       
 10974     return function module(name, requires, configFn) {
       
 10975       var assertNotHasOwnProperty = function(name, context) {
       
 10976         if (name === 'hasOwnProperty') {
       
 10977           throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
       
 10978         }
       
 10979       };
       
 10980 
       
 10981       assertNotHasOwnProperty(name, 'module');
       
 10982       if (requires && modules.hasOwnProperty(name)) {
       
 10983         modules[name] = null;
       
 10984       }
       
 10985       return ensure(modules, name, function() {
       
 10986         if (!requires) {
       
 10987           throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " +
       
 10988              "the module name or forgot to load it. If registering a module ensure that you " +
       
 10989              "specify the dependencies as the second argument.", name);
       
 10990         }
       
 10991 
       
 10992         /** @type {!Array.<Array.<*>>} */
       
 10993         var invokeQueue = [];
       
 10994 
       
 10995         /** @type {!Array.<Function>} */
       
 10996         var configBlocks = [];
       
 10997 
       
 10998         /** @type {!Array.<Function>} */
       
 10999         var runBlocks = [];
       
 11000 
       
 11001         var config = invokeLater('$injector', 'invoke', 'push', configBlocks);
       
 11002 
       
 11003         /** @type {angular.Module} */
       
 11004         var moduleInstance = {
       
 11005           // Private state
       
 11006           _invokeQueue: invokeQueue,
       
 11007           _configBlocks: configBlocks,
       
 11008           _runBlocks: runBlocks,
       
 11009 
       
 11010           /**
       
 11011            * @ngdoc property
       
 11012            * @name angular.Module#requires
       
 11013            * @module ng
       
 11014            *
       
 11015            * @description
       
 11016            * Holds the list of modules which the injector will load before the current module is
       
 11017            * loaded.
       
 11018            */
       
 11019           requires: requires,
       
 11020 
       
 11021           /**
       
 11022            * @ngdoc property
       
 11023            * @name angular.Module#name
       
 11024            * @module ng
       
 11025            *
       
 11026            * @description
       
 11027            * Name of the module.
       
 11028            */
       
 11029           name: name,
       
 11030 
       
 11031 
       
 11032           /**
       
 11033            * @ngdoc method
       
 11034            * @name angular.Module#provider
       
 11035            * @module ng
       
 11036            * @param {string} name service name
       
 11037            * @param {Function} providerType Construction function for creating new instance of the
       
 11038            *                                service.
       
 11039            * @description
       
 11040            * See {@link auto.$provide#provider $provide.provider()}.
       
 11041            */
       
 11042           provider: invokeLater('$provide', 'provider'),
       
 11043 
       
 11044           /**
       
 11045            * @ngdoc method
       
 11046            * @name angular.Module#factory
       
 11047            * @module ng
       
 11048            * @param {string} name service name
       
 11049            * @param {Function} providerFunction Function for creating new instance of the service.
       
 11050            * @description
       
 11051            * See {@link auto.$provide#factory $provide.factory()}.
       
 11052            */
       
 11053           factory: invokeLater('$provide', 'factory'),
       
 11054 
       
 11055           /**
       
 11056            * @ngdoc method
       
 11057            * @name angular.Module#service
       
 11058            * @module ng
       
 11059            * @param {string} name service name
       
 11060            * @param {Function} constructor A constructor function that will be instantiated.
       
 11061            * @description
       
 11062            * See {@link auto.$provide#service $provide.service()}.
       
 11063            */
       
 11064           service: invokeLater('$provide', 'service'),
       
 11065 
       
 11066           /**
       
 11067            * @ngdoc method
       
 11068            * @name angular.Module#value
       
 11069            * @module ng
       
 11070            * @param {string} name service name
       
 11071            * @param {*} object Service instance object.
       
 11072            * @description
       
 11073            * See {@link auto.$provide#value $provide.value()}.
       
 11074            */
       
 11075           value: invokeLater('$provide', 'value'),
       
 11076 
       
 11077           /**
       
 11078            * @ngdoc method
       
 11079            * @name angular.Module#constant
       
 11080            * @module ng
       
 11081            * @param {string} name constant name
       
 11082            * @param {*} object Constant value.
       
 11083            * @description
       
 11084            * Because the constant are fixed, they get applied before other provide methods.
       
 11085            * See {@link auto.$provide#constant $provide.constant()}.
       
 11086            */
       
 11087           constant: invokeLater('$provide', 'constant', 'unshift'),
       
 11088 
       
 11089           /**
       
 11090            * @ngdoc method
       
 11091            * @name angular.Module#animation
       
 11092            * @module ng
       
 11093            * @param {string} name animation name
       
 11094            * @param {Function} animationFactory Factory function for creating new instance of an
       
 11095            *                                    animation.
       
 11096            * @description
       
 11097            *
       
 11098            * **NOTE**: animations take effect only if the **ngAnimate** module is loaded.
       
 11099            *
       
 11100            *
       
 11101            * Defines an animation hook that can be later used with
       
 11102            * {@link ngAnimate.$animate $animate} service and directives that use this service.
       
 11103            *
       
 11104            * ```js
       
 11105            * module.animation('.animation-name', function($inject1, $inject2) {
       
 11106            *   return {
       
 11107            *     eventName : function(element, done) {
       
 11108            *       //code to run the animation
       
 11109            *       //once complete, then run done()
       
 11110            *       return function cancellationFunction(element) {
       
 11111            *         //code to cancel the animation
       
 11112            *       }
       
 11113            *     }
       
 11114            *   }
       
 11115            * })
       
 11116            * ```
       
 11117            *
       
 11118            * See {@link ngAnimate.$animateProvider#register $animateProvider.register()} and
       
 11119            * {@link ngAnimate ngAnimate module} for more information.
       
 11120            */
       
 11121           animation: invokeLater('$animateProvider', 'register'),
       
 11122 
       
 11123           /**
       
 11124            * @ngdoc method
       
 11125            * @name angular.Module#filter
       
 11126            * @module ng
       
 11127            * @param {string} name Filter name.
       
 11128            * @param {Function} filterFactory Factory function for creating new instance of filter.
       
 11129            * @description
       
 11130            * See {@link ng.$filterProvider#register $filterProvider.register()}.
       
 11131            */
       
 11132           filter: invokeLater('$filterProvider', 'register'),
       
 11133 
       
 11134           /**
       
 11135            * @ngdoc method
       
 11136            * @name angular.Module#controller
       
 11137            * @module ng
       
 11138            * @param {string|Object} name Controller name, or an object map of controllers where the
       
 11139            *    keys are the names and the values are the constructors.
       
 11140            * @param {Function} constructor Controller constructor function.
       
 11141            * @description
       
 11142            * See {@link ng.$controllerProvider#register $controllerProvider.register()}.
       
 11143            */
       
 11144           controller: invokeLater('$controllerProvider', 'register'),
       
 11145 
       
 11146           /**
       
 11147            * @ngdoc method
       
 11148            * @name angular.Module#directive
       
 11149            * @module ng
       
 11150            * @param {string|Object} name Directive name, or an object map of directives where the
       
 11151            *    keys are the names and the values are the factories.
       
 11152            * @param {Function} directiveFactory Factory function for creating new instance of
       
 11153            * directives.
       
 11154            * @description
       
 11155            * See {@link ng.$compileProvider#directive $compileProvider.directive()}.
       
 11156            */
       
 11157           directive: invokeLater('$compileProvider', 'directive'),
       
 11158 
       
 11159           /**
       
 11160            * @ngdoc method
       
 11161            * @name angular.Module#config
       
 11162            * @module ng
       
 11163            * @param {Function} configFn Execute this function on module load. Useful for service
       
 11164            *    configuration.
       
 11165            * @description
       
 11166            * Use this method to register work which needs to be performed on module loading.
       
 11167            * For more about how to configure services, see
       
 11168            * {@link providers#providers_provider-recipe Provider Recipe}.
       
 11169            */
       
 11170           config: config,
       
 11171 
       
 11172           /**
       
 11173            * @ngdoc method
       
 11174            * @name angular.Module#run
       
 11175            * @module ng
       
 11176            * @param {Function} initializationFn Execute this function after injector creation.
       
 11177            *    Useful for application initialization.
       
 11178            * @description
       
 11179            * Use this method to register work which should be performed when the injector is done
       
 11180            * loading all modules.
       
 11181            */
       
 11182           run: function(block) {
       
 11183             runBlocks.push(block);
       
 11184             return this;
       
 11185           }
       
 11186         };
       
 11187 
       
 11188         if (configFn) {
       
 11189           config(configFn);
       
 11190         }
       
 11191 
       
 11192         return  moduleInstance;
       
 11193 
       
 11194         /**
       
 11195          * @param {string} provider
       
 11196          * @param {string} method
       
 11197          * @param {String=} insertMethod
       
 11198          * @returns {angular.Module}
       
 11199          */
       
 11200         function invokeLater(provider, method, insertMethod, queue) {
       
 11201           if (!queue) queue = invokeQueue;
       
 11202           return function() {
       
 11203             queue[insertMethod || 'push']([provider, method, arguments]);
       
 11204             return moduleInstance;
       
 11205           };
       
 11206         }
       
 11207       });
       
 11208     };
       
 11209   });
       
 11210 
       
 11211 }
       
 11212 
       
 11213 /* global angularModule: true,
       
 11214   version: true,
       
 11215 
       
 11216   $LocaleProvider,
       
 11217   $CompileProvider,
       
 11218 
       
 11219   htmlAnchorDirective,
       
 11220   inputDirective,
       
 11221   inputDirective,
       
 11222   formDirective,
       
 11223   scriptDirective,
       
 11224   selectDirective,
       
 11225   styleDirective,
       
 11226   optionDirective,
       
 11227   ngBindDirective,
       
 11228   ngBindHtmlDirective,
       
 11229   ngBindTemplateDirective,
       
 11230   ngClassDirective,
       
 11231   ngClassEvenDirective,
       
 11232   ngClassOddDirective,
       
 11233   ngCspDirective,
       
 11234   ngCloakDirective,
       
 11235   ngControllerDirective,
       
 11236   ngFormDirective,
       
 11237   ngHideDirective,
       
 11238   ngIfDirective,
       
 11239   ngIncludeDirective,
       
 11240   ngIncludeFillContentDirective,
       
 11241   ngInitDirective,
       
 11242   ngNonBindableDirective,
       
 11243   ngPluralizeDirective,
       
 11244   ngRepeatDirective,
       
 11245   ngShowDirective,
       
 11246   ngStyleDirective,
       
 11247   ngSwitchDirective,
       
 11248   ngSwitchWhenDirective,
       
 11249   ngSwitchDefaultDirective,
       
 11250   ngOptionsDirective,
       
 11251   ngTranscludeDirective,
       
 11252   ngModelDirective,
       
 11253   ngListDirective,
       
 11254   ngChangeDirective,
       
 11255   patternDirective,
       
 11256   patternDirective,
       
 11257   requiredDirective,
       
 11258   requiredDirective,
       
 11259   minlengthDirective,
       
 11260   minlengthDirective,
       
 11261   maxlengthDirective,
       
 11262   maxlengthDirective,
       
 11263   ngValueDirective,
       
 11264   ngModelOptionsDirective,
       
 11265   ngAttributeAliasDirectives,
       
 11266   ngEventDirectives,
       
 11267 
       
 11268   $AnchorScrollProvider,
       
 11269   $AnimateProvider,
       
 11270   $BrowserProvider,
       
 11271   $CacheFactoryProvider,
       
 11272   $ControllerProvider,
       
 11273   $DocumentProvider,
       
 11274   $ExceptionHandlerProvider,
       
 11275   $FilterProvider,
       
 11276   $InterpolateProvider,
       
 11277   $IntervalProvider,
       
 11278   $HttpProvider,
       
 11279   $HttpBackendProvider,
       
 11280   $LocationProvider,
       
 11281   $LogProvider,
       
 11282   $ParseProvider,
       
 11283   $RootScopeProvider,
       
 11284   $QProvider,
       
 11285   $$QProvider,
       
 11286   $$SanitizeUriProvider,
       
 11287   $SceProvider,
       
 11288   $SceDelegateProvider,
       
 11289   $SnifferProvider,
       
 11290   $TemplateCacheProvider,
       
 11291   $TemplateRequestProvider,
       
 11292   $$TestabilityProvider,
       
 11293   $TimeoutProvider,
       
 11294   $$RAFProvider,
       
 11295   $$AsyncCallbackProvider,
       
 11296   $WindowProvider
       
 11297 */
       
 11298 
       
 11299 
       
 11300 /**
       
 11301  * @ngdoc object
       
 11302  * @name angular.version
       
 11303  * @module ng
       
 11304  * @description
       
 11305  * An object that contains information about the current AngularJS version. This object has the
       
 11306  * following properties:
       
 11307  *
       
 11308  * - `full` – `{string}` – Full version string, such as "0.9.18".
       
 11309  * - `major` – `{number}` – Major version number, such as "0".
       
 11310  * - `minor` – `{number}` – Minor version number, such as "9".
       
 11311  * - `dot` – `{number}` – Dot version number, such as "18".
       
 11312  * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
       
 11313  */
       
 11314 var version = {
       
 11315   full: '1.3.0-rc.5',    // all of these placeholder strings will be replaced by grunt's
       
 11316   major: 1,    // package task
       
 11317   minor: 3,
       
 11318   dot: 0,
       
 11319   codeName: 'impossible-choreography'
       
 11320 };
       
 11321 
       
 11322 
       
 11323 function publishExternalAPI(angular){
       
 11324   extend(angular, {
       
 11325     'bootstrap': bootstrap,
       
 11326     'copy': copy,
       
 11327     'extend': extend,
       
 11328     'equals': equals,
       
 11329     'element': jqLite,
       
 11330     'forEach': forEach,
       
 11331     'injector': createInjector,
       
 11332     'noop': noop,
       
 11333     'bind': bind,
       
 11334     'toJson': toJson,
       
 11335     'fromJson': fromJson,
       
 11336     'identity': identity,
       
 11337     'isUndefined': isUndefined,
       
 11338     'isDefined': isDefined,
       
 11339     'isString': isString,
       
 11340     'isFunction': isFunction,
       
 11341     'isObject': isObject,
       
 11342     'isNumber': isNumber,
       
 11343     'isElement': isElement,
       
 11344     'isArray': isArray,
       
 11345     'version': version,
       
 11346     'isDate': isDate,
       
 11347     'lowercase': lowercase,
       
 11348     'uppercase': uppercase,
       
 11349     'callbacks': {counter: 0},
       
 11350     'getTestability': getTestability,
       
 11351     '$$minErr': minErr,
       
 11352     '$$csp': csp,
       
 11353     'reloadWithDebugInfo': reloadWithDebugInfo
       
 11354   });
       
 11355 
       
 11356   angularModule = setupModuleLoader(window);
       
 11357   try {
       
 11358     angularModule('ngLocale');
       
 11359   } catch (e) {
       
 11360     angularModule('ngLocale', []).provider('$locale', $LocaleProvider);
       
 11361   }
       
 11362 
       
 11363   angularModule('ng', ['ngLocale'], ['$provide',
       
 11364     function ngModule($provide) {
       
 11365       // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it.
       
 11366       $provide.provider({
       
 11367         $$sanitizeUri: $$SanitizeUriProvider
       
 11368       });
       
 11369       $provide.provider('$compile', $CompileProvider).
       
 11370         directive({
       
 11371             a: htmlAnchorDirective,
       
 11372             input: inputDirective,
       
 11373             textarea: inputDirective,
       
 11374             form: formDirective,
       
 11375             script: scriptDirective,
       
 11376             select: selectDirective,
       
 11377             style: styleDirective,
       
 11378             option: optionDirective,
       
 11379             ngBind: ngBindDirective,
       
 11380             ngBindHtml: ngBindHtmlDirective,
       
 11381             ngBindTemplate: ngBindTemplateDirective,
       
 11382             ngClass: ngClassDirective,
       
 11383             ngClassEven: ngClassEvenDirective,
       
 11384             ngClassOdd: ngClassOddDirective,
       
 11385             ngCloak: ngCloakDirective,
       
 11386             ngController: ngControllerDirective,
       
 11387             ngForm: ngFormDirective,
       
 11388             ngHide: ngHideDirective,
       
 11389             ngIf: ngIfDirective,
       
 11390             ngInclude: ngIncludeDirective,
       
 11391             ngInit: ngInitDirective,
       
 11392             ngNonBindable: ngNonBindableDirective,
       
 11393             ngPluralize: ngPluralizeDirective,
       
 11394             ngRepeat: ngRepeatDirective,
       
 11395             ngShow: ngShowDirective,
       
 11396             ngStyle: ngStyleDirective,
       
 11397             ngSwitch: ngSwitchDirective,
       
 11398             ngSwitchWhen: ngSwitchWhenDirective,
       
 11399             ngSwitchDefault: ngSwitchDefaultDirective,
       
 11400             ngOptions: ngOptionsDirective,
       
 11401             ngTransclude: ngTranscludeDirective,
       
 11402             ngModel: ngModelDirective,
       
 11403             ngList: ngListDirective,
       
 11404             ngChange: ngChangeDirective,
       
 11405             pattern: patternDirective,
       
 11406             ngPattern: patternDirective,
       
 11407             required: requiredDirective,
       
 11408             ngRequired: requiredDirective,
       
 11409             minlength: minlengthDirective,
       
 11410             ngMinlength: minlengthDirective,
       
 11411             maxlength: maxlengthDirective,
       
 11412             ngMaxlength: maxlengthDirective,
       
 11413             ngValue: ngValueDirective,
       
 11414             ngModelOptions: ngModelOptionsDirective
       
 11415         }).
       
 11416         directive({
       
 11417           ngInclude: ngIncludeFillContentDirective
       
 11418         }).
       
 11419         directive(ngAttributeAliasDirectives).
       
 11420         directive(ngEventDirectives);
       
 11421       $provide.provider({
       
 11422         $anchorScroll: $AnchorScrollProvider,
       
 11423         $animate: $AnimateProvider,
       
 11424         $browser: $BrowserProvider,
       
 11425         $cacheFactory: $CacheFactoryProvider,
       
 11426         $controller: $ControllerProvider,
       
 11427         $document: $DocumentProvider,
       
 11428         $exceptionHandler: $ExceptionHandlerProvider,
       
 11429         $filter: $FilterProvider,
       
 11430         $interpolate: $InterpolateProvider,
       
 11431         $interval: $IntervalProvider,
       
 11432         $http: $HttpProvider,
       
 11433         $httpBackend: $HttpBackendProvider,
       
 11434         $location: $LocationProvider,
       
 11435         $log: $LogProvider,
       
 11436         $parse: $ParseProvider,
       
 11437         $rootScope: $RootScopeProvider,
       
 11438         $q: $QProvider,
       
 11439         $$q: $$QProvider,
       
 11440         $sce: $SceProvider,
       
 11441         $sceDelegate: $SceDelegateProvider,
       
 11442         $sniffer: $SnifferProvider,
       
 11443         $templateCache: $TemplateCacheProvider,
       
 11444         $templateRequest: $TemplateRequestProvider,
       
 11445         $$testability: $$TestabilityProvider,
       
 11446         $timeout: $TimeoutProvider,
       
 11447         $window: $WindowProvider,
       
 11448         $$rAF: $$RAFProvider,
       
 11449         $$asyncCallback : $$AsyncCallbackProvider
       
 11450       });
       
 11451     }
       
 11452   ]);
       
 11453 }
       
 11454 
       
 11455 /* global JQLitePrototype: true,
       
 11456   addEventListenerFn: true,
       
 11457   removeEventListenerFn: true,
       
 11458   BOOLEAN_ATTR: true,
       
 11459   ALIASED_ATTR: true,
       
 11460 */
       
 11461 
       
 11462 //////////////////////////////////
       
 11463 //JQLite
       
 11464 //////////////////////////////////
       
 11465 
       
 11466 /**
       
 11467  * @ngdoc function
       
 11468  * @name angular.element
       
 11469  * @module ng
       
 11470  * @kind function
       
 11471  *
       
 11472  * @description
       
 11473  * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element.
       
 11474  *
       
 11475  * If jQuery is available, `angular.element` is an alias for the
       
 11476  * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element`
       
 11477  * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or "jqLite."
       
 11478  *
       
 11479  * <div class="alert alert-success">jqLite is a tiny, API-compatible subset of jQuery that allows
       
 11480  * Angular to manipulate the DOM in a cross-browser compatible way. **jqLite** implements only the most
       
 11481  * commonly needed functionality with the goal of having a very small footprint.</div>
       
 11482  *
       
 11483  * To use jQuery, simply load it before `DOMContentLoaded` event fired.
       
 11484  *
       
 11485  * <div class="alert">**Note:** all element references in Angular are always wrapped with jQuery or
       
 11486  * jqLite; they are never raw DOM references.</div>
       
 11487  *
       
 11488  * ## Angular's jqLite
       
 11489  * jqLite provides only the following jQuery methods:
       
 11490  *
       
 11491  * - [`addClass()`](http://api.jquery.com/addClass/)
       
 11492  * - [`after()`](http://api.jquery.com/after/)
       
 11493  * - [`append()`](http://api.jquery.com/append/)
       
 11494  * - [`attr()`](http://api.jquery.com/attr/)
       
 11495  * - [`bind()`](http://api.jquery.com/bind/) - Does not support namespaces, selectors or eventData
       
 11496  * - [`children()`](http://api.jquery.com/children/) - Does not support selectors
       
 11497  * - [`clone()`](http://api.jquery.com/clone/)
       
 11498  * - [`contents()`](http://api.jquery.com/contents/)
       
 11499  * - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyles()`
       
 11500  * - [`data()`](http://api.jquery.com/data/)
       
 11501  * - [`detach()`](http://api.jquery.com/detach/)
       
 11502  * - [`empty()`](http://api.jquery.com/empty/)
       
 11503  * - [`eq()`](http://api.jquery.com/eq/)
       
 11504  * - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name
       
 11505  * - [`hasClass()`](http://api.jquery.com/hasClass/)
       
 11506  * - [`html()`](http://api.jquery.com/html/)
       
 11507  * - [`next()`](http://api.jquery.com/next/) - Does not support selectors
       
 11508  * - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
       
 11509  * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces or selectors
       
 11510  * - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors
       
 11511  * - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors
       
 11512  * - [`prepend()`](http://api.jquery.com/prepend/)
       
 11513  * - [`prop()`](http://api.jquery.com/prop/)
       
 11514  * - [`ready()`](http://api.jquery.com/ready/)
       
 11515  * - [`remove()`](http://api.jquery.com/remove/)
       
 11516  * - [`removeAttr()`](http://api.jquery.com/removeAttr/)
       
 11517  * - [`removeClass()`](http://api.jquery.com/removeClass/)
       
 11518  * - [`removeData()`](http://api.jquery.com/removeData/)
       
 11519  * - [`replaceWith()`](http://api.jquery.com/replaceWith/)
       
 11520  * - [`text()`](http://api.jquery.com/text/)
       
 11521  * - [`toggleClass()`](http://api.jquery.com/toggleClass/)
       
 11522  * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers.
       
 11523  * - [`unbind()`](http://api.jquery.com/unbind/) - Does not support namespaces
       
 11524  * - [`val()`](http://api.jquery.com/val/)
       
 11525  * - [`wrap()`](http://api.jquery.com/wrap/)
       
 11526  *
       
 11527  * ## jQuery/jqLite Extras
       
 11528  * Angular also provides the following additional methods and events to both jQuery and jqLite:
       
 11529  *
       
 11530  * ### Events
       
 11531  * - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction apis and fires this event
       
 11532  *    on all DOM nodes being removed.  This can be used to clean up any 3rd party bindings to the DOM
       
 11533  *    element before it is removed.
       
 11534  *
       
 11535  * ### Methods
       
 11536  * - `controller(name)` - retrieves the controller of the current element or its parent. By default
       
 11537  *   retrieves controller associated with the `ngController` directive. If `name` is provided as
       
 11538  *   camelCase directive name, then the controller for this directive will be retrieved (e.g.
       
 11539  *   `'ngModel'`).
       
 11540  * - `injector()` - retrieves the injector of the current element or its parent.
       
 11541  * - `scope()` - retrieves the {@link ng.$rootScope.Scope scope} of the current
       
 11542  *   element or its parent.
       
 11543  * - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the
       
 11544  *   current element. This getter should be used only on elements that contain a directive which starts a new isolate
       
 11545  *   scope. Calling `scope()` on this element always returns the original non-isolate scope.
       
 11546  * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
       
 11547  *   parent element is reached.
       
 11548  *
       
 11549  * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.
       
 11550  * @returns {Object} jQuery object.
       
 11551  */
       
 11552 
       
 11553 JQLite.expando = 'ng339';
       
 11554 
       
 11555 var jqCache = JQLite.cache = {},
       
 11556     jqId = 1,
       
 11557     addEventListenerFn = function(element, type, fn) {
       
 11558       element.addEventListener(type, fn, false);
       
 11559     },
       
 11560     removeEventListenerFn = function(element, type, fn) {
       
 11561       element.removeEventListener(type, fn, false);
       
 11562     };
       
 11563 
       
 11564 /*
       
 11565  * !!! This is an undocumented "private" function !!!
       
 11566  */
       
 11567 JQLite._data = function(node) {
       
 11568   //jQuery always returns an object on cache miss
       
 11569   return this.cache[node[this.expando]] || {};
       
 11570 };
       
 11571 
       
 11572 function jqNextId() { return ++jqId; }
       
 11573 
       
 11574 
       
 11575 var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
       
 11576 var MOZ_HACK_REGEXP = /^moz([A-Z])/;
       
 11577 var MOUSE_EVENT_MAP= { mouseleave : "mouseout", mouseenter : "mouseover"};
       
 11578 var jqLiteMinErr = minErr('jqLite');
       
 11579 
       
 11580 /**
       
 11581  * Converts snake_case to camelCase.
       
 11582  * Also there is special case for Moz prefix starting with upper case letter.
       
 11583  * @param name Name to normalize
       
 11584  */
       
 11585 function camelCase(name) {
       
 11586   return name.
       
 11587     replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
       
 11588       return offset ? letter.toUpperCase() : letter;
       
 11589     }).
       
 11590     replace(MOZ_HACK_REGEXP, 'Moz$1');
       
 11591 }
       
 11592 
       
 11593 var SINGLE_TAG_REGEXP = /^<(\w+)\s*\/?>(?:<\/\1>|)$/;
       
 11594 var HTML_REGEXP = /<|&#?\w+;/;
       
 11595 var TAG_NAME_REGEXP = /<([\w:]+)/;
       
 11596 var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi;
       
 11597 
       
 11598 var wrapMap = {
       
 11599   'option': [1, '<select multiple="multiple">', '</select>'],
       
 11600 
       
 11601   'thead': [1, '<table>', '</table>'],
       
 11602   'col': [2, '<table><colgroup>', '</colgroup></table>'],
       
 11603   'tr': [2, '<table><tbody>', '</tbody></table>'],
       
 11604   'td': [3, '<table><tbody><tr>', '</tr></tbody></table>'],
       
 11605   '_default': [0, "", ""]
       
 11606 };
       
 11607 
       
 11608 wrapMap.optgroup = wrapMap.option;
       
 11609 wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
       
 11610 wrapMap.th = wrapMap.td;
       
 11611 
       
 11612 
       
 11613 function jqLiteIsTextNode(html) {
       
 11614   return !HTML_REGEXP.test(html);
       
 11615 }
       
 11616 
       
 11617 function jqLiteAcceptsData(node) {
       
 11618   // The window object can accept data but has no nodeType
       
 11619   // Otherwise we are only interested in elements (1) and documents (9)
       
 11620   var nodeType = node.nodeType;
       
 11621   return nodeType === NODE_TYPE_ELEMENT || !nodeType || nodeType === NODE_TYPE_DOCUMENT;
       
 11622 }
       
 11623 
       
 11624 function jqLiteBuildFragment(html, context) {
       
 11625   var tmp, tag, wrap,
       
 11626       fragment = context.createDocumentFragment(),
       
 11627       nodes = [], i;
       
 11628 
       
 11629   if (jqLiteIsTextNode(html)) {
       
 11630     // Convert non-html into a text node
       
 11631     nodes.push(context.createTextNode(html));
       
 11632   } else {
       
 11633     // Convert html into DOM nodes
       
 11634     tmp = tmp || fragment.appendChild(context.createElement("div"));
       
 11635     tag = (TAG_NAME_REGEXP.exec(html) || ["", ""])[1].toLowerCase();
       
 11636     wrap = wrapMap[tag] || wrapMap._default;
       
 11637     tmp.innerHTML = wrap[1] + html.replace(XHTML_TAG_REGEXP, "<$1></$2>") + wrap[2];
       
 11638 
       
 11639     // Descend through wrappers to the right content
       
 11640     i = wrap[0];
       
 11641     while (i--) {
       
 11642       tmp = tmp.lastChild;
       
 11643     }
       
 11644 
       
 11645     nodes = concat(nodes, tmp.childNodes);
       
 11646 
       
 11647     tmp = fragment.firstChild;
       
 11648     tmp.textContent = "";
       
 11649   }
       
 11650 
       
 11651   // Remove wrapper from fragment
       
 11652   fragment.textContent = "";
       
 11653   fragment.innerHTML = ""; // Clear inner HTML
       
 11654   forEach(nodes, function(node) {
       
 11655     fragment.appendChild(node);
       
 11656   });
       
 11657 
       
 11658   return fragment;
       
 11659 }
       
 11660 
       
 11661 function jqLiteParseHTML(html, context) {
       
 11662   context = context || document;
       
 11663   var parsed;
       
 11664 
       
 11665   if ((parsed = SINGLE_TAG_REGEXP.exec(html))) {
       
 11666     return [context.createElement(parsed[1])];
       
 11667   }
       
 11668 
       
 11669   if ((parsed = jqLiteBuildFragment(html, context))) {
       
 11670     return parsed.childNodes;
       
 11671   }
       
 11672 
       
 11673   return [];
       
 11674 }
       
 11675 
       
 11676 /////////////////////////////////////////////
       
 11677 function JQLite(element) {
       
 11678   if (element instanceof JQLite) {
       
 11679     return element;
       
 11680   }
       
 11681 
       
 11682   var argIsString;
       
 11683 
       
 11684   if (isString(element)) {
       
 11685     element = trim(element);
       
 11686     argIsString = true;
       
 11687   }
       
 11688   if (!(this instanceof JQLite)) {
       
 11689     if (argIsString && element.charAt(0) != '<') {
       
 11690       throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');
       
 11691     }
       
 11692     return new JQLite(element);
       
 11693   }
       
 11694 
       
 11695   if (argIsString) {
       
 11696     jqLiteAddNodes(this, jqLiteParseHTML(element));
       
 11697   } else {
       
 11698     jqLiteAddNodes(this, element);
       
 11699   }
       
 11700 }
       
 11701 
       
 11702 function jqLiteClone(element) {
       
 11703   return element.cloneNode(true);
       
 11704 }
       
 11705 
       
 11706 function jqLiteDealoc(element, onlyDescendants){
       
 11707   if (!onlyDescendants) jqLiteRemoveData(element);
       
 11708 
       
 11709   if (element.querySelectorAll) {
       
 11710     var descendants = element.querySelectorAll('*');
       
 11711     for (var i = 0, l = descendants.length; i < l; i++) {
       
 11712       jqLiteRemoveData(descendants[i]);
       
 11713     }
       
 11714   }
       
 11715 }
       
 11716 
       
 11717 function jqLiteOff(element, type, fn, unsupported) {
       
 11718   if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument');
       
 11719 
       
 11720   var expandoStore = jqLiteExpandoStore(element);
       
 11721   var events = expandoStore && expandoStore.events;
       
 11722   var handle = expandoStore && expandoStore.handle;
       
 11723 
       
 11724   if (!handle) return; //no listeners registered
       
 11725 
       
 11726   if (!type) {
       
 11727     for (type in events) {
       
 11728       if (type !== '$destroy') {
       
 11729         removeEventListenerFn(element, type, events[type]);
       
 11730       }
       
 11731       delete events[type];
       
 11732     }
       
 11733   } else {
       
 11734     forEach(type.split(' '), function(type) {
       
 11735       if (isUndefined(fn)) {
       
 11736         removeEventListenerFn(element, type, events[type]);
       
 11737         delete events[type];
       
 11738       } else {
       
 11739         arrayRemove(events[type] || [], fn);
       
 11740       }
       
 11741     });
       
 11742   }
       
 11743 }
       
 11744 
       
 11745 function jqLiteRemoveData(element, name) {
       
 11746   var expandoId = element.ng339;
       
 11747   var expandoStore = expandoId && jqCache[expandoId];
       
 11748 
       
 11749   if (expandoStore) {
       
 11750     if (name) {
       
 11751       delete expandoStore.data[name];
       
 11752       return;
       
 11753     }
       
 11754 
       
 11755     if (expandoStore.handle) {
       
 11756       if (expandoStore.events.$destroy) {
       
 11757         expandoStore.handle({}, '$destroy');
       
 11758       }
       
 11759       jqLiteOff(element);
       
 11760     }
       
 11761     delete jqCache[expandoId];
       
 11762     element.ng339 = undefined; // don't delete DOM expandos. IE and Chrome don't like it
       
 11763   }
       
 11764 }
       
 11765 
       
 11766 
       
 11767 function jqLiteExpandoStore(element, createIfNecessary) {
       
 11768   var expandoId = element.ng339,
       
 11769       expandoStore = expandoId && jqCache[expandoId];
       
 11770 
       
 11771   if (createIfNecessary && !expandoStore) {
       
 11772     element.ng339 = expandoId = jqNextId();
       
 11773     expandoStore = jqCache[expandoId] = {events: {}, data: {}, handle: undefined};
       
 11774   }
       
 11775 
       
 11776   return expandoStore;
       
 11777 }
       
 11778 
       
 11779 
       
 11780 function jqLiteData(element, key, value) {
       
 11781   if (jqLiteAcceptsData(element)) {
       
 11782 
       
 11783     var isSimpleSetter = isDefined(value);
       
 11784     var isSimpleGetter = !isSimpleSetter && key && !isObject(key);
       
 11785     var massGetter = !key;
       
 11786     var expandoStore = jqLiteExpandoStore(element, !isSimpleGetter);
       
 11787     var data = expandoStore && expandoStore.data;
       
 11788 
       
 11789     if (isSimpleSetter) { // data('key', value)
       
 11790       data[key] = value;
       
 11791     } else {
       
 11792       if (massGetter) {  // data()
       
 11793         return data;
       
 11794       } else {
       
 11795         if (isSimpleGetter) { // data('key')
       
 11796           // don't force creation of expandoStore if it doesn't exist yet
       
 11797           return data && data[key];
       
 11798         } else { // mass-setter: data({key1: val1, key2: val2})
       
 11799           extend(data, key);
       
 11800         }
       
 11801       }
       
 11802     }
       
 11803   }
       
 11804 }
       
 11805 
       
 11806 function jqLiteHasClass(element, selector) {
       
 11807   if (!element.getAttribute) return false;
       
 11808   return ((" " + (element.getAttribute('class') || '') + " ").replace(/[\n\t]/g, " ").
       
 11809       indexOf( " " + selector + " " ) > -1);
       
 11810 }
       
 11811 
       
 11812 function jqLiteRemoveClass(element, cssClasses) {
       
 11813   if (cssClasses && element.setAttribute) {
       
 11814     forEach(cssClasses.split(' '), function(cssClass) {
       
 11815       element.setAttribute('class', trim(
       
 11816           (" " + (element.getAttribute('class') || '') + " ")
       
 11817           .replace(/[\n\t]/g, " ")
       
 11818           .replace(" " + trim(cssClass) + " ", " "))
       
 11819       );
       
 11820     });
       
 11821   }
       
 11822 }
       
 11823 
       
 11824 function jqLiteAddClass(element, cssClasses) {
       
 11825   if (cssClasses && element.setAttribute) {
       
 11826     var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ')
       
 11827                             .replace(/[\n\t]/g, " ");
       
 11828 
       
 11829     forEach(cssClasses.split(' '), function(cssClass) {
       
 11830       cssClass = trim(cssClass);
       
 11831       if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) {
       
 11832         existingClasses += cssClass + ' ';
       
 11833       }
       
 11834     });
       
 11835 
       
 11836     element.setAttribute('class', trim(existingClasses));
       
 11837   }
       
 11838 }
       
 11839 
       
 11840 
       
 11841 function jqLiteAddNodes(root, elements) {
       
 11842   // THIS CODE IS VERY HOT. Don't make changes without benchmarking.
       
 11843 
       
 11844   if (elements) {
       
 11845 
       
 11846     // if a Node (the most common case)
       
 11847     if (elements.nodeType) {
       
 11848       root[root.length++] = elements;
       
 11849     } else {
       
 11850       var length = elements.length;
       
 11851 
       
 11852       // if an Array or NodeList and not a Window
       
 11853       if (typeof length === 'number' && elements.window !== elements) {
       
 11854         if (length) {
       
 11855           for (var i = 0; i < length; i++) {
       
 11856             root[root.length++] = elements[i];
       
 11857           }
       
 11858         }
       
 11859       } else {
       
 11860         root[root.length++] = elements;
       
 11861       }
       
 11862     }
       
 11863   }
       
 11864 }
       
 11865 
       
 11866 
       
 11867 function jqLiteController(element, name) {
       
 11868   return jqLiteInheritedData(element, '$' + (name || 'ngController' ) + 'Controller');
       
 11869 }
       
 11870 
       
 11871 function jqLiteInheritedData(element, name, value) {
       
 11872   // if element is the document object work with the html element instead
       
 11873   // this makes $(document).scope() possible
       
 11874   if(element.nodeType == NODE_TYPE_DOCUMENT) {
       
 11875     element = element.documentElement;
       
 11876   }
       
 11877   var names = isArray(name) ? name : [name];
       
 11878 
       
 11879   while (element) {
       
 11880     for (var i = 0, ii = names.length; i < ii; i++) {
       
 11881       if ((value = jqLite.data(element, names[i])) !== undefined) return value;
       
 11882     }
       
 11883 
       
 11884     // If dealing with a document fragment node with a host element, and no parent, use the host
       
 11885     // element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM
       
 11886     // to lookup parent controllers.
       
 11887     element = element.parentNode || (element.nodeType === NODE_TYPE_DOCUMENT_FRAGMENT && element.host);
       
 11888   }
       
 11889 }
       
 11890 
       
 11891 function jqLiteEmpty(element) {
       
 11892   jqLiteDealoc(element, true);
       
 11893   while (element.firstChild) {
       
 11894     element.removeChild(element.firstChild);
       
 11895   }
       
 11896 }
       
 11897 
       
 11898 function jqLiteRemove(element, keepData) {
       
 11899   if (!keepData) jqLiteDealoc(element);
       
 11900   var parent = element.parentNode;
       
 11901   if (parent) parent.removeChild(element);
       
 11902 }
       
 11903 
       
 11904 //////////////////////////////////////////
       
 11905 // Functions which are declared directly.
       
 11906 //////////////////////////////////////////
       
 11907 var JQLitePrototype = JQLite.prototype = {
       
 11908   ready: function(fn) {
       
 11909     var fired = false;
       
 11910 
       
 11911     function trigger() {
       
 11912       if (fired) return;
       
 11913       fired = true;
       
 11914       fn();
       
 11915     }
       
 11916 
       
 11917     // check if document is already loaded
       
 11918     if (document.readyState === 'complete'){
       
 11919       setTimeout(trigger);
       
 11920     } else {
       
 11921       this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9
       
 11922       // we can not use jqLite since we are not done loading and jQuery could be loaded later.
       
 11923       // jshint -W064
       
 11924       JQLite(window).on('load', trigger); // fallback to window.onload for others
       
 11925       // jshint +W064
       
 11926       this.on('DOMContentLoaded', trigger);
       
 11927     }
       
 11928   },
       
 11929   toString: function() {
       
 11930     var value = [];
       
 11931     forEach(this, function(e){ value.push('' + e);});
       
 11932     return '[' + value.join(', ') + ']';
       
 11933   },
       
 11934 
       
 11935   eq: function(index) {
       
 11936       return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]);
       
 11937   },
       
 11938 
       
 11939   length: 0,
       
 11940   push: push,
       
 11941   sort: [].sort,
       
 11942   splice: [].splice
       
 11943 };
       
 11944 
       
 11945 //////////////////////////////////////////
       
 11946 // Functions iterating getter/setters.
       
 11947 // these functions return self on setter and
       
 11948 // value on get.
       
 11949 //////////////////////////////////////////
       
 11950 var BOOLEAN_ATTR = {};
       
 11951 forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function(value) {
       
 11952   BOOLEAN_ATTR[lowercase(value)] = value;
       
 11953 });
       
 11954 var BOOLEAN_ELEMENTS = {};
       
 11955 forEach('input,select,option,textarea,button,form,details'.split(','), function(value) {
       
 11956   BOOLEAN_ELEMENTS[value] = true;
       
 11957 });
       
 11958 var ALIASED_ATTR = {
       
 11959   'ngMinlength' : 'minlength',
       
 11960   'ngMaxlength' : 'maxlength',
       
 11961   'ngMin' : 'min',
       
 11962   'ngMax' : 'max',
       
 11963   'ngPattern' : 'pattern'
       
 11964 };
       
 11965 
       
 11966 function getBooleanAttrName(element, name) {
       
 11967   // check dom last since we will most likely fail on name
       
 11968   var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];
       
 11969 
       
 11970   // booleanAttr is here twice to minimize DOM access
       
 11971   return booleanAttr && BOOLEAN_ELEMENTS[nodeName_(element)] && booleanAttr;
       
 11972 }
       
 11973 
       
 11974 function getAliasedAttrName(element, name) {
       
 11975   var nodeName = element.nodeName;
       
 11976   return (nodeName === 'INPUT' || nodeName === 'TEXTAREA') && ALIASED_ATTR[name];
       
 11977 }
       
 11978 
       
 11979 forEach({
       
 11980   data: jqLiteData,
       
 11981   removeData: jqLiteRemoveData
       
 11982 }, function(fn, name) {
       
 11983   JQLite[name] = fn;
       
 11984 });
       
 11985 
       
 11986 forEach({
       
 11987   data: jqLiteData,
       
 11988   inheritedData: jqLiteInheritedData,
       
 11989 
       
 11990   scope: function(element) {
       
 11991     // Can't use jqLiteData here directly so we stay compatible with jQuery!
       
 11992     return jqLite.data(element, '$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
       
 11993   },
       
 11994 
       
 11995   isolateScope: function(element) {
       
 11996     // Can't use jqLiteData here directly so we stay compatible with jQuery!
       
 11997     return jqLite.data(element, '$isolateScope') || jqLite.data(element, '$isolateScopeNoTemplate');
       
 11998   },
       
 11999 
       
 12000   controller: jqLiteController,
       
 12001 
       
 12002   injector: function(element) {
       
 12003     return jqLiteInheritedData(element, '$injector');
       
 12004   },
       
 12005 
       
 12006   removeAttr: function(element, name) {
       
 12007     element.removeAttribute(name);
       
 12008   },
       
 12009 
       
 12010   hasClass: jqLiteHasClass,
       
 12011 
       
 12012   css: function(element, name, value) {
       
 12013     name = camelCase(name);
       
 12014 
       
 12015     if (isDefined(value)) {
       
 12016       element.style[name] = value;
       
 12017     } else {
       
 12018       return element.style[name];
       
 12019     }
       
 12020   },
       
 12021 
       
 12022   attr: function(element, name, value){
       
 12023     var lowercasedName = lowercase(name);
       
 12024     if (BOOLEAN_ATTR[lowercasedName]) {
       
 12025       if (isDefined(value)) {
       
 12026         if (!!value) {
       
 12027           element[name] = true;
       
 12028           element.setAttribute(name, lowercasedName);
       
 12029         } else {
       
 12030           element[name] = false;
       
 12031           element.removeAttribute(lowercasedName);
       
 12032         }
       
 12033       } else {
       
 12034         return (element[name] ||
       
 12035                  (element.attributes.getNamedItem(name)|| noop).specified)
       
 12036                ? lowercasedName
       
 12037                : undefined;
       
 12038       }
       
 12039     } else if (isDefined(value)) {
       
 12040       element.setAttribute(name, value);
       
 12041     } else if (element.getAttribute) {
       
 12042       // the extra argument "2" is to get the right thing for a.href in IE, see jQuery code
       
 12043       // some elements (e.g. Document) don't have get attribute, so return undefined
       
 12044       var ret = element.getAttribute(name, 2);
       
 12045       // normalize non-existing attributes to undefined (as jQuery)
       
 12046       return ret === null ? undefined : ret;
       
 12047     }
       
 12048   },
       
 12049 
       
 12050   prop: function(element, name, value) {
       
 12051     if (isDefined(value)) {
       
 12052       element[name] = value;
       
 12053     } else {
       
 12054       return element[name];
       
 12055     }
       
 12056   },
       
 12057 
       
 12058   text: (function() {
       
 12059     getText.$dv = '';
       
 12060     return getText;
       
 12061 
       
 12062     function getText(element, value) {
       
 12063       if (isUndefined(value)) {
       
 12064         var nodeType = element.nodeType;
       
 12065         return (nodeType === NODE_TYPE_ELEMENT || nodeType === NODE_TYPE_TEXT) ? element.textContent : '';
       
 12066       }
       
 12067       element.textContent = value;
       
 12068     }
       
 12069   })(),
       
 12070 
       
 12071   val: function(element, value) {
       
 12072     if (isUndefined(value)) {
       
 12073       if (element.multiple && nodeName_(element) === 'select') {
       
 12074         var result = [];
       
 12075         forEach(element.options, function (option) {
       
 12076           if (option.selected) {
       
 12077             result.push(option.value || option.text);
       
 12078           }
       
 12079         });
       
 12080         return result.length === 0 ? null : result;
       
 12081       }
       
 12082       return element.value;
       
 12083     }
       
 12084     element.value = value;
       
 12085   },
       
 12086 
       
 12087   html: function(element, value) {
       
 12088     if (isUndefined(value)) {
       
 12089       return element.innerHTML;
       
 12090     }
       
 12091     jqLiteDealoc(element, true);
       
 12092     element.innerHTML = value;
       
 12093   },
       
 12094 
       
 12095   empty: jqLiteEmpty
       
 12096 }, function(fn, name){
       
 12097   /**
       
 12098    * Properties: writes return selection, reads return first value
       
 12099    */
       
 12100   JQLite.prototype[name] = function(arg1, arg2) {
       
 12101     var i, key;
       
 12102     var nodeCount = this.length;
       
 12103 
       
 12104     // jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
       
 12105     // in a way that survives minification.
       
 12106     // jqLiteEmpty takes no arguments but is a setter.
       
 12107     if (fn !== jqLiteEmpty &&
       
 12108         (((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2) === undefined)) {
       
 12109       if (isObject(arg1)) {
       
 12110 
       
 12111         // we are a write, but the object properties are the key/values
       
 12112         for (i = 0; i < nodeCount; i++) {
       
 12113           if (fn === jqLiteData) {
       
 12114             // data() takes the whole object in jQuery
       
 12115             fn(this[i], arg1);
       
 12116           } else {
       
 12117             for (key in arg1) {
       
 12118               fn(this[i], key, arg1[key]);
       
 12119             }
       
 12120           }
       
 12121         }
       
 12122         // return self for chaining
       
 12123         return this;
       
 12124       } else {
       
 12125         // we are a read, so read the first child.
       
 12126         // TODO: do we still need this?
       
 12127         var value = fn.$dv;
       
 12128         // Only if we have $dv do we iterate over all, otherwise it is just the first element.
       
 12129         var jj = (value === undefined) ? Math.min(nodeCount, 1) : nodeCount;
       
 12130         for (var j = 0; j < jj; j++) {
       
 12131           var nodeValue = fn(this[j], arg1, arg2);
       
 12132           value = value ? value + nodeValue : nodeValue;
       
 12133         }
       
 12134         return value;
       
 12135       }
       
 12136     } else {
       
 12137       // we are a write, so apply to all children
       
 12138       for (i = 0; i < nodeCount; i++) {
       
 12139         fn(this[i], arg1, arg2);
       
 12140       }
       
 12141       // return self for chaining
       
 12142       return this;
       
 12143     }
       
 12144   };
       
 12145 });
       
 12146 
       
 12147 function createEventHandler(element, events) {
       
 12148   var eventHandler = function (event, type) {
       
 12149     // jQuery specific api
       
 12150     event.isDefaultPrevented = function() {
       
 12151       return event.defaultPrevented;
       
 12152     };
       
 12153 
       
 12154     var eventFns = events[type || event.type];
       
 12155     var eventFnsLength = eventFns ? eventFns.length : 0;
       
 12156 
       
 12157     if (!eventFnsLength) return;
       
 12158 
       
 12159     if (isUndefined(event.immediatePropagationStopped)) {
       
 12160       var originalStopImmediatePropagation = event.stopImmediatePropagation;
       
 12161       event.stopImmediatePropagation = function() {
       
 12162         event.immediatePropagationStopped = true;
       
 12163 
       
 12164         if (event.stopPropagation) {
       
 12165           event.stopPropagation();
       
 12166         }
       
 12167 
       
 12168         if (originalStopImmediatePropagation) {
       
 12169           originalStopImmediatePropagation.call(event);
       
 12170         }
       
 12171       };
       
 12172     }
       
 12173 
       
 12174     event.isImmediatePropagationStopped = function() {
       
 12175       return event.immediatePropagationStopped === true;
       
 12176     };
       
 12177 
       
 12178     // Copy event handlers in case event handlers array is modified during execution.
       
 12179     if ((eventFnsLength > 1)) {
       
 12180       eventFns = shallowCopy(eventFns);
       
 12181     }
       
 12182 
       
 12183     for (var i = 0; i < eventFnsLength; i++) {
       
 12184       if (!event.isImmediatePropagationStopped()) {
       
 12185         eventFns[i].call(element, event);
       
 12186       }
       
 12187     }
       
 12188   };
       
 12189 
       
 12190   // TODO: this is a hack for angularMocks/clearDataCache that makes it possible to deregister all
       
 12191   //       events on `element`
       
 12192   eventHandler.elem = element;
       
 12193   return eventHandler;
       
 12194 }
       
 12195 
       
 12196 //////////////////////////////////////////
       
 12197 // Functions iterating traversal.
       
 12198 // These functions chain results into a single
       
 12199 // selector.
       
 12200 //////////////////////////////////////////
       
 12201 forEach({
       
 12202   removeData: jqLiteRemoveData,
       
 12203 
       
 12204   on: function jqLiteOn(element, type, fn, unsupported){
       
 12205     if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters');
       
 12206 
       
 12207     // Do not add event handlers to non-elements because they will not be cleaned up.
       
 12208     if (!jqLiteAcceptsData(element)) {
       
 12209       return;
       
 12210     }
       
 12211 
       
 12212     var expandoStore = jqLiteExpandoStore(element, true);
       
 12213     var events = expandoStore.events;
       
 12214     var handle = expandoStore.handle;
       
 12215 
       
 12216     if (!handle) {
       
 12217       handle = expandoStore.handle = createEventHandler(element, events);
       
 12218     }
       
 12219 
       
 12220     // http://jsperf.com/string-indexof-vs-split
       
 12221     var types = type.indexOf(' ') >= 0 ? type.split(' ') : [type];
       
 12222     var i = types.length;
       
 12223 
       
 12224     while (i--) {
       
 12225       type = types[i];
       
 12226       var eventFns = events[type];
       
 12227 
       
 12228       if (!eventFns) {
       
 12229         events[type] = [];
       
 12230 
       
 12231         if (type === 'mouseenter' || type === 'mouseleave') {
       
 12232           // Refer to jQuery's implementation of mouseenter & mouseleave
       
 12233           // Read about mouseenter and mouseleave:
       
 12234           // http://www.quirksmode.org/js/events_mouse.html#link8
       
 12235 
       
 12236           jqLiteOn(element, MOUSE_EVENT_MAP[type], function(event) {
       
 12237             var target = this, related = event.relatedTarget;
       
 12238             // For mousenter/leave call the handler if related is outside the target.
       
 12239             // NB: No relatedTarget if the mouse left/entered the browser window
       
 12240             if ( !related || (related !== target && !target.contains(related)) ){
       
 12241               handle(event, type);
       
 12242             }
       
 12243           });
       
 12244 
       
 12245         } else {
       
 12246           if (type !== '$destroy') {
       
 12247             addEventListenerFn(element, type, handle);
       
 12248           }
       
 12249         }
       
 12250         eventFns = events[type];
       
 12251       }
       
 12252       eventFns.push(fn);
       
 12253     }
       
 12254   },
       
 12255 
       
 12256   off: jqLiteOff,
       
 12257 
       
 12258   one: function(element, type, fn) {
       
 12259     element = jqLite(element);
       
 12260 
       
 12261     //add the listener twice so that when it is called
       
 12262     //you can remove the original function and still be
       
 12263     //able to call element.off(ev, fn) normally
       
 12264     element.on(type, function onFn() {
       
 12265       element.off(type, fn);
       
 12266       element.off(type, onFn);
       
 12267     });
       
 12268     element.on(type, fn);
       
 12269   },
       
 12270 
       
 12271   replaceWith: function(element, replaceNode) {
       
 12272     var index, parent = element.parentNode;
       
 12273     jqLiteDealoc(element);
       
 12274     forEach(new JQLite(replaceNode), function(node){
       
 12275       if (index) {
       
 12276         parent.insertBefore(node, index.nextSibling);
       
 12277       } else {
       
 12278         parent.replaceChild(node, element);
       
 12279       }
       
 12280       index = node;
       
 12281     });
       
 12282   },
       
 12283 
       
 12284   children: function(element) {
       
 12285     var children = [];
       
 12286     forEach(element.childNodes, function(element){
       
 12287       if (element.nodeType === NODE_TYPE_ELEMENT)
       
 12288         children.push(element);
       
 12289     });
       
 12290     return children;
       
 12291   },
       
 12292 
       
 12293   contents: function(element) {
       
 12294     return element.contentDocument || element.childNodes || [];
       
 12295   },
       
 12296 
       
 12297   append: function(element, node) {
       
 12298     var nodeType = element.nodeType;
       
 12299     if (nodeType !== NODE_TYPE_ELEMENT && nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT) return;
       
 12300 
       
 12301     node = new JQLite(node);
       
 12302 
       
 12303     for (var i = 0, ii = node.length; i < ii; i++) {
       
 12304       var child = node[i];
       
 12305       element.appendChild(child);
       
 12306     }
       
 12307   },
       
 12308 
       
 12309   prepend: function(element, node) {
       
 12310     if (element.nodeType === NODE_TYPE_ELEMENT) {
       
 12311       var index = element.firstChild;
       
 12312       forEach(new JQLite(node), function(child){
       
 12313         element.insertBefore(child, index);
       
 12314       });
       
 12315     }
       
 12316   },
       
 12317 
       
 12318   wrap: function(element, wrapNode) {
       
 12319     wrapNode = jqLite(wrapNode).eq(0).clone()[0];
       
 12320     var parent = element.parentNode;
       
 12321     if (parent) {
       
 12322       parent.replaceChild(wrapNode, element);
       
 12323     }
       
 12324     wrapNode.appendChild(element);
       
 12325   },
       
 12326 
       
 12327   remove: jqLiteRemove,
       
 12328 
       
 12329   detach: function(element) {
       
 12330     jqLiteRemove(element, true);
       
 12331   },
       
 12332 
       
 12333   after: function(element, newElement) {
       
 12334     var index = element, parent = element.parentNode;
       
 12335     newElement = new JQLite(newElement);
       
 12336 
       
 12337     for (var i = 0, ii = newElement.length; i < ii; i++) {
       
 12338       var node = newElement[i];
       
 12339       parent.insertBefore(node, index.nextSibling);
       
 12340       index = node;
       
 12341     }
       
 12342   },
       
 12343 
       
 12344   addClass: jqLiteAddClass,
       
 12345   removeClass: jqLiteRemoveClass,
       
 12346 
       
 12347   toggleClass: function(element, selector, condition) {
       
 12348     if (selector) {
       
 12349       forEach(selector.split(' '), function(className){
       
 12350         var classCondition = condition;
       
 12351         if (isUndefined(classCondition)) {
       
 12352           classCondition = !jqLiteHasClass(element, className);
       
 12353         }
       
 12354         (classCondition ? jqLiteAddClass : jqLiteRemoveClass)(element, className);
       
 12355       });
       
 12356     }
       
 12357   },
       
 12358 
       
 12359   parent: function(element) {
       
 12360     var parent = element.parentNode;
       
 12361     return parent && parent.nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT ? parent : null;
       
 12362   },
       
 12363 
       
 12364   next: function(element) {
       
 12365     return element.nextElementSibling;
       
 12366   },
       
 12367 
       
 12368   find: function(element, selector) {
       
 12369     if (element.getElementsByTagName) {
       
 12370       return element.getElementsByTagName(selector);
       
 12371     } else {
       
 12372       return [];
       
 12373     }
       
 12374   },
       
 12375 
       
 12376   clone: jqLiteClone,
       
 12377 
       
 12378   triggerHandler: function(element, event, extraParameters) {
       
 12379 
       
 12380     var dummyEvent, eventFnsCopy, handlerArgs;
       
 12381     var eventName = event.type || event;
       
 12382     var expandoStore = jqLiteExpandoStore(element);
       
 12383     var events = expandoStore && expandoStore.events;
       
 12384     var eventFns = events && events[eventName];
       
 12385 
       
 12386     if (eventFns) {
       
 12387       // Create a dummy event to pass to the handlers
       
 12388       dummyEvent = {
       
 12389         preventDefault: function() { this.defaultPrevented = true; },
       
 12390         isDefaultPrevented: function() { return this.defaultPrevented === true; },
       
 12391         stopImmediatePropagation: function() { this.immediatePropagationStopped = true; },
       
 12392         isImmediatePropagationStopped: function() { return this.immediatePropagationStopped === true; },
       
 12393         stopPropagation: noop,
       
 12394         type: eventName,
       
 12395         target: element
       
 12396       };
       
 12397 
       
 12398       // If a custom event was provided then extend our dummy event with it
       
 12399       if (event.type) {
       
 12400         dummyEvent = extend(dummyEvent, event);
       
 12401       }
       
 12402 
       
 12403       // Copy event handlers in case event handlers array is modified during execution.
       
 12404       eventFnsCopy = shallowCopy(eventFns);
       
 12405       handlerArgs = extraParameters ? [dummyEvent].concat(extraParameters) : [dummyEvent];
       
 12406 
       
 12407       forEach(eventFnsCopy, function(fn) {
       
 12408         if (!dummyEvent.isImmediatePropagationStopped()) {
       
 12409           fn.apply(element, handlerArgs);
       
 12410         }
       
 12411       });
       
 12412     }
       
 12413   }
       
 12414 }, function(fn, name){
       
 12415   /**
       
 12416    * chaining functions
       
 12417    */
       
 12418   JQLite.prototype[name] = function(arg1, arg2, arg3) {
       
 12419     var value;
       
 12420 
       
 12421     for(var i = 0, ii = this.length; i < ii; i++) {
       
 12422       if (isUndefined(value)) {
       
 12423         value = fn(this[i], arg1, arg2, arg3);
       
 12424         if (isDefined(value)) {
       
 12425           // any function which returns a value needs to be wrapped
       
 12426           value = jqLite(value);
       
 12427         }
       
 12428       } else {
       
 12429         jqLiteAddNodes(value, fn(this[i], arg1, arg2, arg3));
       
 12430       }
       
 12431     }
       
 12432     return isDefined(value) ? value : this;
       
 12433   };
       
 12434 
       
 12435   // bind legacy bind/unbind to on/off
       
 12436   JQLite.prototype.bind = JQLite.prototype.on;
       
 12437   JQLite.prototype.unbind = JQLite.prototype.off;
       
 12438 });
       
 12439 
       
 12440 /**
       
 12441  * Computes a hash of an 'obj'.
       
 12442  * Hash of a:
       
 12443  *  string is string
       
 12444  *  number is number as string
       
 12445  *  object is either result of calling $$hashKey function on the object or uniquely generated id,
       
 12446  *         that is also assigned to the $$hashKey property of the object.
       
 12447  *
       
 12448  * @param obj
       
 12449  * @returns {string} hash string such that the same input will have the same hash string.
       
 12450  *         The resulting string key is in 'type:hashKey' format.
       
 12451  */
       
 12452 function hashKey(obj, nextUidFn) {
       
 12453   var key = obj && obj.$$hashKey;
       
 12454 
       
 12455   if (key) {
       
 12456     if (typeof key === 'function') {
       
 12457       key = obj.$$hashKey();
       
 12458     }
       
 12459     return key;
       
 12460   }
       
 12461 
       
 12462   var objType = typeof obj;
       
 12463   if (objType == 'function' || (objType == 'object' && obj !== null)) {
       
 12464     key = obj.$$hashKey = objType + ':' + (nextUidFn || nextUid)();
       
 12465   } else {
       
 12466     key = objType + ':' + obj;
       
 12467   }
       
 12468 
       
 12469   return key;
       
 12470 }
       
 12471 
       
 12472 /**
       
 12473  * HashMap which can use objects as keys
       
 12474  */
       
 12475 function HashMap(array, isolatedUid) {
       
 12476   if (isolatedUid) {
       
 12477     var uid = 0;
       
 12478     this.nextUid = function() {
       
 12479       return ++uid;
       
 12480     };
       
 12481   }
       
 12482   forEach(array, this.put, this);
       
 12483 }
       
 12484 HashMap.prototype = {
       
 12485   /**
       
 12486    * Store key value pair
       
 12487    * @param key key to store can be any type
       
 12488    * @param value value to store can be any type
       
 12489    */
       
 12490   put: function(key, value) {
       
 12491     this[hashKey(key, this.nextUid)] = value;
       
 12492   },
       
 12493 
       
 12494   /**
       
 12495    * @param key
       
 12496    * @returns {Object} the value for the key
       
 12497    */
       
 12498   get: function(key) {
       
 12499     return this[hashKey(key, this.nextUid)];
       
 12500   },
       
 12501 
       
 12502   /**
       
 12503    * Remove the key/value pair
       
 12504    * @param key
       
 12505    */
       
 12506   remove: function(key) {
       
 12507     var value = this[key = hashKey(key, this.nextUid)];
       
 12508     delete this[key];
       
 12509     return value;
       
 12510   }
       
 12511 };
       
 12512 
       
 12513 /**
       
 12514  * @ngdoc function
       
 12515  * @module ng
       
 12516  * @name angular.injector
       
 12517  * @kind function
       
 12518  *
       
 12519  * @description
       
 12520  * Creates an injector object that can be used for retrieving services as well as for
       
 12521  * dependency injection (see {@link guide/di dependency injection}).
       
 12522  *
       
 12523 
       
 12524  * @param {Array.<string|Function>} modules A list of module functions or their aliases. See
       
 12525  *        {@link angular.module}. The `ng` module must be explicitly added.
       
 12526  * @returns {function()} Injector object. See {@link auto.$injector $injector}.
       
 12527  *
       
 12528  * @example
       
 12529  * Typical usage
       
 12530  * ```js
       
 12531  *   // create an injector
       
 12532  *   var $injector = angular.injector(['ng']);
       
 12533  *
       
 12534  *   // use the injector to kick off your application
       
 12535  *   // use the type inference to auto inject arguments, or use implicit injection
       
 12536  *   $injector.invoke(function($rootScope, $compile, $document) {
       
 12537  *     $compile($document)($rootScope);
       
 12538  *     $rootScope.$digest();
       
 12539  *   });
       
 12540  * ```
       
 12541  *
       
 12542  * Sometimes you want to get access to the injector of a currently running Angular app
       
 12543  * from outside Angular. Perhaps, you want to inject and compile some markup after the
       
 12544  * application has been bootstrapped. You can do this using the extra `injector()` added
       
 12545  * to JQuery/jqLite elements. See {@link angular.element}.
       
 12546  *
       
 12547  * *This is fairly rare but could be the case if a third party library is injecting the
       
 12548  * markup.*
       
 12549  *
       
 12550  * In the following example a new block of HTML containing a `ng-controller`
       
 12551  * directive is added to the end of the document body by JQuery. We then compile and link
       
 12552  * it into the current AngularJS scope.
       
 12553  *
       
 12554  * ```js
       
 12555  * var $div = $('<div ng-controller="MyCtrl">{{content.label}}</div>');
       
 12556  * $(document.body).append($div);
       
 12557  *
       
 12558  * angular.element(document).injector().invoke(function($compile) {
       
 12559  *   var scope = angular.element($div).scope();
       
 12560  *   $compile($div)(scope);
       
 12561  * });
       
 12562  * ```
       
 12563  */
       
 12564 
       
 12565 
       
 12566 /**
       
 12567  * @ngdoc module
       
 12568  * @name auto
       
 12569  * @description
       
 12570  *
       
 12571  * Implicit module which gets automatically added to each {@link auto.$injector $injector}.
       
 12572  */
       
 12573 
       
 12574 var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
       
 12575 var FN_ARG_SPLIT = /,/;
       
 12576 var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
       
 12577 var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
       
 12578 var $injectorMinErr = minErr('$injector');
       
 12579 
       
 12580 function anonFn(fn) {
       
 12581   // For anonymous functions, showing at the very least the function signature can help in
       
 12582   // debugging.
       
 12583   var fnText = fn.toString().replace(STRIP_COMMENTS, ''),
       
 12584       args = fnText.match(FN_ARGS);
       
 12585   if (args) {
       
 12586     return 'function(' + (args[1] || '').replace(/[\s\r\n]+/, ' ') + ')';
       
 12587   }
       
 12588   return 'fn';
       
 12589 }
       
 12590 
       
 12591 function annotate(fn, strictDi, name) {
       
 12592   var $inject,
       
 12593       fnText,
       
 12594       argDecl,
       
 12595       last;
       
 12596 
       
 12597   if (typeof fn === 'function') {
       
 12598     if (!($inject = fn.$inject)) {
       
 12599       $inject = [];
       
 12600       if (fn.length) {
       
 12601         if (strictDi) {
       
 12602           if (!isString(name) || !name) {
       
 12603             name = fn.name || anonFn(fn);
       
 12604           }
       
 12605           throw $injectorMinErr('strictdi',
       
 12606             '{0} is not using explicit annotation and cannot be invoked in strict mode', name);
       
 12607         }
       
 12608         fnText = fn.toString().replace(STRIP_COMMENTS, '');
       
 12609         argDecl = fnText.match(FN_ARGS);
       
 12610         forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg) {
       
 12611           arg.replace(FN_ARG, function(all, underscore, name) {
       
 12612             $inject.push(name);
       
 12613           });
       
 12614         });
       
 12615       }
       
 12616       fn.$inject = $inject;
       
 12617     }
       
 12618   } else if (isArray(fn)) {
       
 12619     last = fn.length - 1;
       
 12620     assertArgFn(fn[last], 'fn');
       
 12621     $inject = fn.slice(0, last);
       
 12622   } else {
       
 12623     assertArgFn(fn, 'fn', true);
       
 12624   }
       
 12625   return $inject;
       
 12626 }
       
 12627 
       
 12628 ///////////////////////////////////////
       
 12629 
       
 12630 /**
       
 12631  * @ngdoc service
       
 12632  * @name $injector
       
 12633  *
       
 12634  * @description
       
 12635  *
       
 12636  * `$injector` is used to retrieve object instances as defined by
       
 12637  * {@link auto.$provide provider}, instantiate types, invoke methods,
       
 12638  * and load modules.
       
 12639  *
       
 12640  * The following always holds true:
       
 12641  *
       
 12642  * ```js
       
 12643  *   var $injector = angular.injector();
       
 12644  *   expect($injector.get('$injector')).toBe($injector);
       
 12645  *   expect($injector.invoke(function($injector) {
       
 12646  *     return $injector;
       
 12647  *   })).toBe($injector);
       
 12648  * ```
       
 12649  *
       
 12650  * # Injection Function Annotation
       
 12651  *
       
 12652  * JavaScript does not have annotations, and annotations are needed for dependency injection. The
       
 12653  * following are all valid ways of annotating function with injection arguments and are equivalent.
       
 12654  *
       
 12655  * ```js
       
 12656  *   // inferred (only works if code not minified/obfuscated)
       
 12657  *   $injector.invoke(function(serviceA){});
       
 12658  *
       
 12659  *   // annotated
       
 12660  *   function explicit(serviceA) {};
       
 12661  *   explicit.$inject = ['serviceA'];
       
 12662  *   $injector.invoke(explicit);
       
 12663  *
       
 12664  *   // inline
       
 12665  *   $injector.invoke(['serviceA', function(serviceA){}]);
       
 12666  * ```
       
 12667  *
       
 12668  * ## Inference
       
 12669  *
       
 12670  * In JavaScript calling `toString()` on a function returns the function definition. The definition
       
 12671  * can then be parsed and the function arguments can be extracted. *NOTE:* This does not work with
       
 12672  * minification, and obfuscation tools since these tools change the argument names.
       
 12673  *
       
 12674  * ## `$inject` Annotation
       
 12675  * By adding an `$inject` property onto a function the injection parameters can be specified.
       
 12676  *
       
 12677  * ## Inline
       
 12678  * As an array of injection names, where the last item in the array is the function to call.
       
 12679  */
       
 12680 
       
 12681 /**
       
 12682  * @ngdoc method
       
 12683  * @name $injector#get
       
 12684  *
       
 12685  * @description
       
 12686  * Return an instance of the service.
       
 12687  *
       
 12688  * @param {string} name The name of the instance to retrieve.
       
 12689  * @return {*} The instance.
       
 12690  */
       
 12691 
       
 12692 /**
       
 12693  * @ngdoc method
       
 12694  * @name $injector#invoke
       
 12695  *
       
 12696  * @description
       
 12697  * Invoke the method and supply the method arguments from the `$injector`.
       
 12698  *
       
 12699  * @param {!Function} fn The function to invoke. Function parameters are injected according to the
       
 12700  *   {@link guide/di $inject Annotation} rules.
       
 12701  * @param {Object=} self The `this` for the invoked method.
       
 12702  * @param {Object=} locals Optional object. If preset then any argument names are read from this
       
 12703  *                         object first, before the `$injector` is consulted.
       
 12704  * @returns {*} the value returned by the invoked `fn` function.
       
 12705  */
       
 12706 
       
 12707 /**
       
 12708  * @ngdoc method
       
 12709  * @name $injector#has
       
 12710  *
       
 12711  * @description
       
 12712  * Allows the user to query if the particular service exists.
       
 12713  *
       
 12714  * @param {string} name Name of the service to query.
       
 12715  * @returns {boolean} `true` if injector has given service.
       
 12716  */
       
 12717 
       
 12718 /**
       
 12719  * @ngdoc method
       
 12720  * @name $injector#instantiate
       
 12721  * @description
       
 12722  * Create a new instance of JS type. The method takes a constructor function, invokes the new
       
 12723  * operator, and supplies all of the arguments to the constructor function as specified by the
       
 12724  * constructor annotation.
       
 12725  *
       
 12726  * @param {Function} Type Annotated constructor function.
       
 12727  * @param {Object=} locals Optional object. If preset then any argument names are read from this
       
 12728  * object first, before the `$injector` is consulted.
       
 12729  * @returns {Object} new instance of `Type`.
       
 12730  */
       
 12731 
       
 12732 /**
       
 12733  * @ngdoc method
       
 12734  * @name $injector#annotate
       
 12735  *
       
 12736  * @description
       
 12737  * Returns an array of service names which the function is requesting for injection. This API is
       
 12738  * used by the injector to determine which services need to be injected into the function when the
       
 12739  * function is invoked. There are three ways in which the function can be annotated with the needed
       
 12740  * dependencies.
       
 12741  *
       
 12742  * # Argument names
       
 12743  *
       
 12744  * The simplest form is to extract the dependencies from the arguments of the function. This is done
       
 12745  * by converting the function into a string using `toString()` method and extracting the argument
       
 12746  * names.
       
 12747  * ```js
       
 12748  *   // Given
       
 12749  *   function MyController($scope, $route) {
       
 12750  *     // ...
       
 12751  *   }
       
 12752  *
       
 12753  *   // Then
       
 12754  *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
       
 12755  * ```
       
 12756  *
       
 12757  * This method does not work with code minification / obfuscation. For this reason the following
       
 12758  * annotation strategies are supported.
       
 12759  *
       
 12760  * # The `$inject` property
       
 12761  *
       
 12762  * If a function has an `$inject` property and its value is an array of strings, then the strings
       
 12763  * represent names of services to be injected into the function.
       
 12764  * ```js
       
 12765  *   // Given
       
 12766  *   var MyController = function(obfuscatedScope, obfuscatedRoute) {
       
 12767  *     // ...
       
 12768  *   }
       
 12769  *   // Define function dependencies
       
 12770  *   MyController['$inject'] = ['$scope', '$route'];
       
 12771  *
       
 12772  *   // Then
       
 12773  *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
       
 12774  * ```
       
 12775  *
       
 12776  * # The array notation
       
 12777  *
       
 12778  * It is often desirable to inline Injected functions and that's when setting the `$inject` property
       
 12779  * is very inconvenient. In these situations using the array notation to specify the dependencies in
       
 12780  * a way that survives minification is a better choice:
       
 12781  *
       
 12782  * ```js
       
 12783  *   // We wish to write this (not minification / obfuscation safe)
       
 12784  *   injector.invoke(function($compile, $rootScope) {
       
 12785  *     // ...
       
 12786  *   });
       
 12787  *
       
 12788  *   // We are forced to write break inlining
       
 12789  *   var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) {
       
 12790  *     // ...
       
 12791  *   };
       
 12792  *   tmpFn.$inject = ['$compile', '$rootScope'];
       
 12793  *   injector.invoke(tmpFn);
       
 12794  *
       
 12795  *   // To better support inline function the inline annotation is supported
       
 12796  *   injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {
       
 12797  *     // ...
       
 12798  *   }]);
       
 12799  *
       
 12800  *   // Therefore
       
 12801  *   expect(injector.annotate(
       
 12802  *      ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}])
       
 12803  *    ).toEqual(['$compile', '$rootScope']);
       
 12804  * ```
       
 12805  *
       
 12806  * @param {Function|Array.<string|Function>} fn Function for which dependent service names need to
       
 12807  * be retrieved as described above.
       
 12808  *
       
 12809  * @returns {Array.<string>} The names of the services which the function requires.
       
 12810  */
       
 12811 
       
 12812 
       
 12813 
       
 12814 
       
 12815 /**
       
 12816  * @ngdoc service
       
 12817  * @name $provide
       
 12818  *
       
 12819  * @description
       
 12820  *
       
 12821  * The {@link auto.$provide $provide} service has a number of methods for registering components
       
 12822  * with the {@link auto.$injector $injector}. Many of these functions are also exposed on
       
 12823  * {@link angular.Module}.
       
 12824  *
       
 12825  * An Angular **service** is a singleton object created by a **service factory**.  These **service
       
 12826  * factories** are functions which, in turn, are created by a **service provider**.
       
 12827  * The **service providers** are constructor functions. When instantiated they must contain a
       
 12828  * property called `$get`, which holds the **service factory** function.
       
 12829  *
       
 12830  * When you request a service, the {@link auto.$injector $injector} is responsible for finding the
       
 12831  * correct **service provider**, instantiating it and then calling its `$get` **service factory**
       
 12832  * function to get the instance of the **service**.
       
 12833  *
       
 12834  * Often services have no configuration options and there is no need to add methods to the service
       
 12835  * provider.  The provider will be no more than a constructor function with a `$get` property. For
       
 12836  * these cases the {@link auto.$provide $provide} service has additional helper methods to register
       
 12837  * services without specifying a provider.
       
 12838  *
       
 12839  * * {@link auto.$provide#provider provider(provider)} - registers a **service provider** with the
       
 12840  *     {@link auto.$injector $injector}
       
 12841  * * {@link auto.$provide#constant constant(obj)} - registers a value/object that can be accessed by
       
 12842  *     providers and services.
       
 12843  * * {@link auto.$provide#value value(obj)} - registers a value/object that can only be accessed by
       
 12844  *     services, not providers.
       
 12845  * * {@link auto.$provide#factory factory(fn)} - registers a service **factory function**, `fn`,
       
 12846  *     that will be wrapped in a **service provider** object, whose `$get` property will contain the
       
 12847  *     given factory function.
       
 12848  * * {@link auto.$provide#service service(class)} - registers a **constructor function**, `class`
       
 12849  *     that will be wrapped in a **service provider** object, whose `$get` property will instantiate
       
 12850  *      a new object using the given constructor function.
       
 12851  *
       
 12852  * See the individual methods for more information and examples.
       
 12853  */
       
 12854 
       
 12855 /**
       
 12856  * @ngdoc method
       
 12857  * @name $provide#provider
       
 12858  * @description
       
 12859  *
       
 12860  * Register a **provider function** with the {@link auto.$injector $injector}. Provider functions
       
 12861  * are constructor functions, whose instances are responsible for "providing" a factory for a
       
 12862  * service.
       
 12863  *
       
 12864  * Service provider names start with the name of the service they provide followed by `Provider`.
       
 12865  * For example, the {@link ng.$log $log} service has a provider called
       
 12866  * {@link ng.$logProvider $logProvider}.
       
 12867  *
       
 12868  * Service provider objects can have additional methods which allow configuration of the provider
       
 12869  * and its service. Importantly, you can configure what kind of service is created by the `$get`
       
 12870  * method, or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a
       
 12871  * method {@link ng.$logProvider#debugEnabled debugEnabled}
       
 12872  * which lets you specify whether the {@link ng.$log $log} service will log debug messages to the
       
 12873  * console or not.
       
 12874  *
       
 12875  * @param {string} name The name of the instance. NOTE: the provider will be available under `name +
       
 12876                         'Provider'` key.
       
 12877  * @param {(Object|function())} provider If the provider is:
       
 12878  *
       
 12879  *   - `Object`: then it should have a `$get` method. The `$get` method will be invoked using
       
 12880  *     {@link auto.$injector#invoke $injector.invoke()} when an instance needs to be created.
       
 12881  *   - `Constructor`: a new instance of the provider will be created using
       
 12882  *     {@link auto.$injector#instantiate $injector.instantiate()}, then treated as `object`.
       
 12883  *
       
 12884  * @returns {Object} registered provider instance
       
 12885 
       
 12886  * @example
       
 12887  *
       
 12888  * The following example shows how to create a simple event tracking service and register it using
       
 12889  * {@link auto.$provide#provider $provide.provider()}.
       
 12890  *
       
 12891  * ```js
       
 12892  *  // Define the eventTracker provider
       
 12893  *  function EventTrackerProvider() {
       
 12894  *    var trackingUrl = '/track';
       
 12895  *
       
 12896  *    // A provider method for configuring where the tracked events should been saved
       
 12897  *    this.setTrackingUrl = function(url) {
       
 12898  *      trackingUrl = url;
       
 12899  *    };
       
 12900  *
       
 12901  *    // The service factory function
       
 12902  *    this.$get = ['$http', function($http) {
       
 12903  *      var trackedEvents = {};
       
 12904  *      return {
       
 12905  *        // Call this to track an event
       
 12906  *        event: function(event) {
       
 12907  *          var count = trackedEvents[event] || 0;
       
 12908  *          count += 1;
       
 12909  *          trackedEvents[event] = count;
       
 12910  *          return count;
       
 12911  *        },
       
 12912  *        // Call this to save the tracked events to the trackingUrl
       
 12913  *        save: function() {
       
 12914  *          $http.post(trackingUrl, trackedEvents);
       
 12915  *        }
       
 12916  *      };
       
 12917  *    }];
       
 12918  *  }
       
 12919  *
       
 12920  *  describe('eventTracker', function() {
       
 12921  *    var postSpy;
       
 12922  *
       
 12923  *    beforeEach(module(function($provide) {
       
 12924  *      // Register the eventTracker provider
       
 12925  *      $provide.provider('eventTracker', EventTrackerProvider);
       
 12926  *    }));
       
 12927  *
       
 12928  *    beforeEach(module(function(eventTrackerProvider) {
       
 12929  *      // Configure eventTracker provider
       
 12930  *      eventTrackerProvider.setTrackingUrl('/custom-track');
       
 12931  *    }));
       
 12932  *
       
 12933  *    it('tracks events', inject(function(eventTracker) {
       
 12934  *      expect(eventTracker.event('login')).toEqual(1);
       
 12935  *      expect(eventTracker.event('login')).toEqual(2);
       
 12936  *    }));
       
 12937  *
       
 12938  *    it('saves to the tracking url', inject(function(eventTracker, $http) {
       
 12939  *      postSpy = spyOn($http, 'post');
       
 12940  *      eventTracker.event('login');
       
 12941  *      eventTracker.save();
       
 12942  *      expect(postSpy).toHaveBeenCalled();
       
 12943  *      expect(postSpy.mostRecentCall.args[0]).not.toEqual('/track');
       
 12944  *      expect(postSpy.mostRecentCall.args[0]).toEqual('/custom-track');
       
 12945  *      expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 });
       
 12946  *    }));
       
 12947  *  });
       
 12948  * ```
       
 12949  */
       
 12950 
       
 12951 /**
       
 12952  * @ngdoc method
       
 12953  * @name $provide#factory
       
 12954  * @description
       
 12955  *
       
 12956  * Register a **service factory**, which will be called to return the service instance.
       
 12957  * This is short for registering a service where its provider consists of only a `$get` property,
       
 12958  * which is the given service factory function.
       
 12959  * You should use {@link auto.$provide#factory $provide.factory(getFn)} if you do not need to
       
 12960  * configure your service in a provider.
       
 12961  *
       
 12962  * @param {string} name The name of the instance.
       
 12963  * @param {function()} $getFn The $getFn for the instance creation. Internally this is a short hand
       
 12964  *                            for `$provide.provider(name, {$get: $getFn})`.
       
 12965  * @returns {Object} registered provider instance
       
 12966  *
       
 12967  * @example
       
 12968  * Here is an example of registering a service
       
 12969  * ```js
       
 12970  *   $provide.factory('ping', ['$http', function($http) {
       
 12971  *     return function ping() {
       
 12972  *       return $http.send('/ping');
       
 12973  *     };
       
 12974  *   }]);
       
 12975  * ```
       
 12976  * You would then inject and use this service like this:
       
 12977  * ```js
       
 12978  *   someModule.controller('Ctrl', ['ping', function(ping) {
       
 12979  *     ping();
       
 12980  *   }]);
       
 12981  * ```
       
 12982  */
       
 12983 
       
 12984 
       
 12985 /**
       
 12986  * @ngdoc method
       
 12987  * @name $provide#service
       
 12988  * @description
       
 12989  *
       
 12990  * Register a **service constructor**, which will be invoked with `new` to create the service
       
 12991  * instance.
       
 12992  * This is short for registering a service where its provider's `$get` property is the service
       
 12993  * constructor function that will be used to instantiate the service instance.
       
 12994  *
       
 12995  * You should use {@link auto.$provide#service $provide.service(class)} if you define your service
       
 12996  * as a type/class.
       
 12997  *
       
 12998  * @param {string} name The name of the instance.
       
 12999  * @param {Function} constructor A class (constructor function) that will be instantiated.
       
 13000  * @returns {Object} registered provider instance
       
 13001  *
       
 13002  * @example
       
 13003  * Here is an example of registering a service using
       
 13004  * {@link auto.$provide#service $provide.service(class)}.
       
 13005  * ```js
       
 13006  *   var Ping = function($http) {
       
 13007  *     this.$http = $http;
       
 13008  *   };
       
 13009  *
       
 13010  *   Ping.$inject = ['$http'];
       
 13011  *
       
 13012  *   Ping.prototype.send = function() {
       
 13013  *     return this.$http.get('/ping');
       
 13014  *   };
       
 13015  *   $provide.service('ping', Ping);
       
 13016  * ```
       
 13017  * You would then inject and use this service like this:
       
 13018  * ```js
       
 13019  *   someModule.controller('Ctrl', ['ping', function(ping) {
       
 13020  *     ping.send();
       
 13021  *   }]);
       
 13022  * ```
       
 13023  */
       
 13024 
       
 13025 
       
 13026 /**
       
 13027  * @ngdoc method
       
 13028  * @name $provide#value
       
 13029  * @description
       
 13030  *
       
 13031  * Register a **value service** with the {@link auto.$injector $injector}, such as a string, a
       
 13032  * number, an array, an object or a function.  This is short for registering a service where its
       
 13033  * provider's `$get` property is a factory function that takes no arguments and returns the **value
       
 13034  * service**.
       
 13035  *
       
 13036  * Value services are similar to constant services, except that they cannot be injected into a
       
 13037  * module configuration function (see {@link angular.Module#config}) but they can be overridden by
       
 13038  * an Angular
       
 13039  * {@link auto.$provide#decorator decorator}.
       
 13040  *
       
 13041  * @param {string} name The name of the instance.
       
 13042  * @param {*} value The value.
       
 13043  * @returns {Object} registered provider instance
       
 13044  *
       
 13045  * @example
       
 13046  * Here are some examples of creating value services.
       
 13047  * ```js
       
 13048  *   $provide.value('ADMIN_USER', 'admin');
       
 13049  *
       
 13050  *   $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 });
       
 13051  *
       
 13052  *   $provide.value('halfOf', function(value) {
       
 13053  *     return value / 2;
       
 13054  *   });
       
 13055  * ```
       
 13056  */
       
 13057 
       
 13058 
       
 13059 /**
       
 13060  * @ngdoc method
       
 13061  * @name $provide#constant
       
 13062  * @description
       
 13063  *
       
 13064  * Register a **constant service**, such as a string, a number, an array, an object or a function,
       
 13065  * with the {@link auto.$injector $injector}. Unlike {@link auto.$provide#value value} it can be
       
 13066  * injected into a module configuration function (see {@link angular.Module#config}) and it cannot
       
 13067  * be overridden by an Angular {@link auto.$provide#decorator decorator}.
       
 13068  *
       
 13069  * @param {string} name The name of the constant.
       
 13070  * @param {*} value The constant value.
       
 13071  * @returns {Object} registered instance
       
 13072  *
       
 13073  * @example
       
 13074  * Here a some examples of creating constants:
       
 13075  * ```js
       
 13076  *   $provide.constant('SHARD_HEIGHT', 306);
       
 13077  *
       
 13078  *   $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']);
       
 13079  *
       
 13080  *   $provide.constant('double', function(value) {
       
 13081  *     return value * 2;
       
 13082  *   });
       
 13083  * ```
       
 13084  */
       
 13085 
       
 13086 
       
 13087 /**
       
 13088  * @ngdoc method
       
 13089  * @name $provide#decorator
       
 13090  * @description
       
 13091  *
       
 13092  * Register a **service decorator** with the {@link auto.$injector $injector}. A service decorator
       
 13093  * intercepts the creation of a service, allowing it to override or modify the behaviour of the
       
 13094  * service. The object returned by the decorator may be the original service, or a new service
       
 13095  * object which replaces or wraps and delegates to the original service.
       
 13096  *
       
 13097  * @param {string} name The name of the service to decorate.
       
 13098  * @param {function()} decorator This function will be invoked when the service needs to be
       
 13099  *    instantiated and should return the decorated service instance. The function is called using
       
 13100  *    the {@link auto.$injector#invoke injector.invoke} method and is therefore fully injectable.
       
 13101  *    Local injection arguments:
       
 13102  *
       
 13103  *    * `$delegate` - The original service instance, which can be monkey patched, configured,
       
 13104  *      decorated or delegated to.
       
 13105  *
       
 13106  * @example
       
 13107  * Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting
       
 13108  * calls to {@link ng.$log#error $log.warn()}.
       
 13109  * ```js
       
 13110  *   $provide.decorator('$log', ['$delegate', function($delegate) {
       
 13111  *     $delegate.warn = $delegate.error;
       
 13112  *     return $delegate;
       
 13113  *   }]);
       
 13114  * ```
       
 13115  */
       
 13116 
       
 13117 
       
 13118 function createInjector(modulesToLoad, strictDi) {
       
 13119   strictDi = (strictDi === true);
       
 13120   var INSTANTIATING = {},
       
 13121       providerSuffix = 'Provider',
       
 13122       path = [],
       
 13123       loadedModules = new HashMap([], true),
       
 13124       providerCache = {
       
 13125         $provide: {
       
 13126             provider: supportObject(provider),
       
 13127             factory: supportObject(factory),
       
 13128             service: supportObject(service),
       
 13129             value: supportObject(value),
       
 13130             constant: supportObject(constant),
       
 13131             decorator: decorator
       
 13132           }
       
 13133       },
       
 13134       providerInjector = (providerCache.$injector =
       
 13135           createInternalInjector(providerCache, function() {
       
 13136             throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
       
 13137           })),
       
 13138       instanceCache = {},
       
 13139       instanceInjector = (instanceCache.$injector =
       
 13140           createInternalInjector(instanceCache, function(servicename) {
       
 13141             var provider = providerInjector.get(servicename + providerSuffix);
       
 13142             return instanceInjector.invoke(provider.$get, provider, undefined, servicename);
       
 13143           }));
       
 13144 
       
 13145 
       
 13146   forEach(loadModules(modulesToLoad), function(fn) { instanceInjector.invoke(fn || noop); });
       
 13147 
       
 13148   return instanceInjector;
       
 13149 
       
 13150   ////////////////////////////////////
       
 13151   // $provider
       
 13152   ////////////////////////////////////
       
 13153 
       
 13154   function supportObject(delegate) {
       
 13155     return function(key, value) {
       
 13156       if (isObject(key)) {
       
 13157         forEach(key, reverseParams(delegate));
       
 13158       } else {
       
 13159         return delegate(key, value);
       
 13160       }
       
 13161     };
       
 13162   }
       
 13163 
       
 13164   function provider(name, provider_) {
       
 13165     assertNotHasOwnProperty(name, 'service');
       
 13166     if (isFunction(provider_) || isArray(provider_)) {
       
 13167       provider_ = providerInjector.instantiate(provider_);
       
 13168     }
       
 13169     if (!provider_.$get) {
       
 13170       throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name);
       
 13171     }
       
 13172     return providerCache[name + providerSuffix] = provider_;
       
 13173   }
       
 13174 
       
 13175   function enforceReturnValue(name, factory) {
       
 13176     return function enforcedReturnValue() {
       
 13177       var result = instanceInjector.invoke(factory);
       
 13178       if (isUndefined(result)) {
       
 13179         throw $injectorMinErr('undef', "Provider '{0}' must return a value from $get factory method.", name);
       
 13180       }
       
 13181       return result;
       
 13182     };
       
 13183   }
       
 13184 
       
 13185   function factory(name, factoryFn, enforce) {
       
 13186     return provider(name, {
       
 13187       $get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
       
 13188     });
       
 13189   }
       
 13190 
       
 13191   function service(name, constructor) {
       
 13192     return factory(name, ['$injector', function($injector) {
       
 13193       return $injector.instantiate(constructor);
       
 13194     }]);
       
 13195   }
       
 13196 
       
 13197   function value(name, val) { return factory(name, valueFn(val), false); }
       
 13198 
       
 13199   function constant(name, value) {
       
 13200     assertNotHasOwnProperty(name, 'constant');
       
 13201     providerCache[name] = value;
       
 13202     instanceCache[name] = value;
       
 13203   }
       
 13204 
       
 13205   function decorator(serviceName, decorFn) {
       
 13206     var origProvider = providerInjector.get(serviceName + providerSuffix),
       
 13207         orig$get = origProvider.$get;
       
 13208 
       
 13209     origProvider.$get = function() {
       
 13210       var origInstance = instanceInjector.invoke(orig$get, origProvider);
       
 13211       return instanceInjector.invoke(decorFn, null, {$delegate: origInstance});
       
 13212     };
       
 13213   }
       
 13214 
       
 13215   ////////////////////////////////////
       
 13216   // Module Loading
       
 13217   ////////////////////////////////////
       
 13218   function loadModules(modulesToLoad){
       
 13219     var runBlocks = [], moduleFn;
       
 13220     forEach(modulesToLoad, function(module) {
       
 13221       if (loadedModules.get(module)) return;
       
 13222       loadedModules.put(module, true);
       
 13223 
       
 13224       function runInvokeQueue(queue) {
       
 13225         var i, ii;
       
 13226         for(i = 0, ii = queue.length; i < ii; i++) {
       
 13227           var invokeArgs = queue[i],
       
 13228               provider = providerInjector.get(invokeArgs[0]);
       
 13229 
       
 13230           provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
       
 13231         }
       
 13232       }
       
 13233 
       
 13234       try {
       
 13235         if (isString(module)) {
       
 13236           moduleFn = angularModule(module);
       
 13237           runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
       
 13238           runInvokeQueue(moduleFn._invokeQueue);
       
 13239           runInvokeQueue(moduleFn._configBlocks);
       
 13240         } else if (isFunction(module)) {
       
 13241             runBlocks.push(providerInjector.invoke(module));
       
 13242         } else if (isArray(module)) {
       
 13243             runBlocks.push(providerInjector.invoke(module));
       
 13244         } else {
       
 13245           assertArgFn(module, 'module');
       
 13246         }
       
 13247       } catch (e) {
       
 13248         if (isArray(module)) {
       
 13249           module = module[module.length - 1];
       
 13250         }
       
 13251         if (e.message && e.stack && e.stack.indexOf(e.message) == -1) {
       
 13252           // Safari & FF's stack traces don't contain error.message content
       
 13253           // unlike those of Chrome and IE
       
 13254           // So if stack doesn't contain message, we create a new string that contains both.
       
 13255           // Since error.stack is read-only in Safari, I'm overriding e and not e.stack here.
       
 13256           /* jshint -W022 */
       
 13257           e = e.message + '\n' + e.stack;
       
 13258         }
       
 13259         throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}",
       
 13260                   module, e.stack || e.message || e);
       
 13261       }
       
 13262     });
       
 13263     return runBlocks;
       
 13264   }
       
 13265 
       
 13266   ////////////////////////////////////
       
 13267   // internal Injector
       
 13268   ////////////////////////////////////
       
 13269 
       
 13270   function createInternalInjector(cache, factory) {
       
 13271 
       
 13272     function getService(serviceName) {
       
 13273       if (cache.hasOwnProperty(serviceName)) {
       
 13274         if (cache[serviceName] === INSTANTIATING) {
       
 13275           throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
       
 13276                     serviceName + ' <- ' + path.join(' <- '));
       
 13277         }
       
 13278         return cache[serviceName];
       
 13279       } else {
       
 13280         try {
       
 13281           path.unshift(serviceName);
       
 13282           cache[serviceName] = INSTANTIATING;
       
 13283           return cache[serviceName] = factory(serviceName);
       
 13284         } catch (err) {
       
 13285           if (cache[serviceName] === INSTANTIATING) {
       
 13286             delete cache[serviceName];
       
 13287           }
       
 13288           throw err;
       
 13289         } finally {
       
 13290           path.shift();
       
 13291         }
       
 13292       }
       
 13293     }
       
 13294 
       
 13295     function invoke(fn, self, locals, serviceName) {
       
 13296       if (typeof locals === 'string') {
       
 13297         serviceName = locals;
       
 13298         locals = null;
       
 13299       }
       
 13300 
       
 13301       var args = [],
       
 13302           $inject = annotate(fn, strictDi, serviceName),
       
 13303           length, i,
       
 13304           key;
       
 13305 
       
 13306       for(i = 0, length = $inject.length; i < length; i++) {
       
 13307         key = $inject[i];
       
 13308         if (typeof key !== 'string') {
       
 13309           throw $injectorMinErr('itkn',
       
 13310                   'Incorrect injection token! Expected service name as string, got {0}', key);
       
 13311         }
       
 13312         args.push(
       
 13313           locals && locals.hasOwnProperty(key)
       
 13314           ? locals[key]
       
 13315           : getService(key)
       
 13316         );
       
 13317       }
       
 13318       if (isArray(fn)) {
       
 13319         fn = fn[length];
       
 13320       }
       
 13321 
       
 13322       // http://jsperf.com/angularjs-invoke-apply-vs-switch
       
 13323       // #5388
       
 13324       return fn.apply(self, args);
       
 13325     }
       
 13326 
       
 13327     function instantiate(Type, locals, serviceName) {
       
 13328       var Constructor = function() {},
       
 13329           instance, returnedValue;
       
 13330 
       
 13331       // Check if Type is annotated and use just the given function at n-1 as parameter
       
 13332       // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
       
 13333       Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Type).prototype;
       
 13334       instance = new Constructor();
       
 13335       returnedValue = invoke(Type, instance, locals, serviceName);
       
 13336 
       
 13337       return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
       
 13338     }
       
 13339 
       
 13340     return {
       
 13341       invoke: invoke,
       
 13342       instantiate: instantiate,
       
 13343       get: getService,
       
 13344       annotate: annotate,
       
 13345       has: function(name) {
       
 13346         return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
       
 13347       }
       
 13348     };
       
 13349   }
       
 13350 }
       
 13351 
       
 13352 createInjector.$$annotate = annotate;
       
 13353 
       
 13354 /**
       
 13355  * @ngdoc service
       
 13356  * @name $anchorScroll
       
 13357  * @kind function
       
 13358  * @requires $window
       
 13359  * @requires $location
       
 13360  * @requires $rootScope
       
 13361  *
       
 13362  * @description
       
 13363  * When called, it checks current value of `$location.hash()` and scrolls to the related element,
       
 13364  * according to rules specified in
       
 13365  * [Html5 spec](http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document).
       
 13366  *
       
 13367  * It also watches the `$location.hash()` and scrolls whenever it changes to match any anchor.
       
 13368  * This can be disabled by calling `$anchorScrollProvider.disableAutoScrolling()`.
       
 13369  *
       
 13370  * @example
       
 13371    <example module="anchorScrollExample">
       
 13372      <file name="index.html">
       
 13373        <div id="scrollArea" ng-controller="ScrollController">
       
 13374          <a ng-click="gotoBottom()">Go to bottom</a>
       
 13375          <a id="bottom"></a> You're at the bottom!
       
 13376        </div>
       
 13377      </file>
       
 13378      <file name="script.js">
       
 13379        angular.module('anchorScrollExample', [])
       
 13380          .controller('ScrollController', ['$scope', '$location', '$anchorScroll',
       
 13381            function ($scope, $location, $anchorScroll) {
       
 13382              $scope.gotoBottom = function() {
       
 13383                // set the location.hash to the id of
       
 13384                // the element you wish to scroll to.
       
 13385                $location.hash('bottom');
       
 13386 
       
 13387                // call $anchorScroll()
       
 13388                $anchorScroll();
       
 13389              };
       
 13390            }]);
       
 13391      </file>
       
 13392      <file name="style.css">
       
 13393        #scrollArea {
       
 13394          height: 350px;
       
 13395          overflow: auto;
       
 13396        }
       
 13397 
       
 13398        #bottom {
       
 13399          display: block;
       
 13400          margin-top: 2000px;
       
 13401        }
       
 13402      </file>
       
 13403    </example>
       
 13404  */
       
 13405 function $AnchorScrollProvider() {
       
 13406 
       
 13407   var autoScrollingEnabled = true;
       
 13408 
       
 13409   this.disableAutoScrolling = function() {
       
 13410     autoScrollingEnabled = false;
       
 13411   };
       
 13412 
       
 13413   this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) {
       
 13414     var document = $window.document;
       
 13415 
       
 13416     // helper function to get first anchor from a NodeList
       
 13417     // can't use filter.filter, as it accepts only instances of Array
       
 13418     // and IE can't convert NodeList to an array using [].slice
       
 13419     // TODO(vojta): use filter if we change it to accept lists as well
       
 13420     function getFirstAnchor(list) {
       
 13421       var result = null;
       
 13422       forEach(list, function(element) {
       
 13423         if (!result && nodeName_(element) === 'a') result = element;
       
 13424       });
       
 13425       return result;
       
 13426     }
       
 13427 
       
 13428     function scroll() {
       
 13429       var hash = $location.hash(), elm;
       
 13430 
       
 13431       // empty hash, scroll to the top of the page
       
 13432       if (!hash) $window.scrollTo(0, 0);
       
 13433 
       
 13434       // element with given id
       
 13435       else if ((elm = document.getElementById(hash))) elm.scrollIntoView();
       
 13436 
       
 13437       // first anchor with given name :-D
       
 13438       else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) elm.scrollIntoView();
       
 13439 
       
 13440       // no element and hash == 'top', scroll to the top of the page
       
 13441       else if (hash === 'top') $window.scrollTo(0, 0);
       
 13442     }
       
 13443 
       
 13444     // does not scroll when user clicks on anchor link that is currently on
       
 13445     // (no url change, no $location.hash() change), browser native does scroll
       
 13446     if (autoScrollingEnabled) {
       
 13447       $rootScope.$watch(function autoScrollWatch() {return $location.hash();},
       
 13448         function autoScrollWatchAction(newVal, oldVal) {
       
 13449           // skip the initial scroll if $location.hash is empty
       
 13450           if (newVal === oldVal && newVal === '') return;
       
 13451 
       
 13452           $rootScope.$evalAsync(scroll);
       
 13453         });
       
 13454     }
       
 13455 
       
 13456     return scroll;
       
 13457   }];
       
 13458 }
       
 13459 
       
 13460 var $animateMinErr = minErr('$animate');
       
 13461 
       
 13462 /**
       
 13463  * @ngdoc provider
       
 13464  * @name $animateProvider
       
 13465  *
       
 13466  * @description
       
 13467  * Default implementation of $animate that doesn't perform any animations, instead just
       
 13468  * synchronously performs DOM
       
 13469  * updates and calls done() callbacks.
       
 13470  *
       
 13471  * In order to enable animations the ngAnimate module has to be loaded.
       
 13472  *
       
 13473  * To see the functional implementation check out src/ngAnimate/animate.js
       
 13474  */
       
 13475 var $AnimateProvider = ['$provide', function($provide) {
       
 13476 
       
 13477 
       
 13478   this.$$selectors = {};
       
 13479 
       
 13480 
       
 13481   /**
       
 13482    * @ngdoc method
       
 13483    * @name $animateProvider#register
       
 13484    *
       
 13485    * @description
       
 13486    * Registers a new injectable animation factory function. The factory function produces the
       
 13487    * animation object which contains callback functions for each event that is expected to be
       
 13488    * animated.
       
 13489    *
       
 13490    *   * `eventFn`: `function(Element, doneFunction)` The element to animate, the `doneFunction`
       
 13491    *   must be called once the element animation is complete. If a function is returned then the
       
 13492    *   animation service will use this function to cancel the animation whenever a cancel event is
       
 13493    *   triggered.
       
 13494    *
       
 13495    *
       
 13496    * ```js
       
 13497    *   return {
       
 13498      *     eventFn : function(element, done) {
       
 13499      *       //code to run the animation
       
 13500      *       //once complete, then run done()
       
 13501      *       return function cancellationFunction() {
       
 13502      *         //code to cancel the animation
       
 13503      *       }
       
 13504      *     }
       
 13505      *   }
       
 13506    * ```
       
 13507    *
       
 13508    * @param {string} name The name of the animation.
       
 13509    * @param {Function} factory The factory function that will be executed to return the animation
       
 13510    *                           object.
       
 13511    */
       
 13512   this.register = function(name, factory) {
       
 13513     var key = name + '-animation';
       
 13514     if (name && name.charAt(0) != '.') throw $animateMinErr('notcsel',
       
 13515         "Expecting class selector starting with '.' got '{0}'.", name);
       
 13516     this.$$selectors[name.substr(1)] = key;
       
 13517     $provide.factory(key, factory);
       
 13518   };
       
 13519 
       
 13520   /**
       
 13521    * @ngdoc method
       
 13522    * @name $animateProvider#classNameFilter
       
 13523    *
       
 13524    * @description
       
 13525    * Sets and/or returns the CSS class regular expression that is checked when performing
       
 13526    * an animation. Upon bootstrap the classNameFilter value is not set at all and will
       
 13527    * therefore enable $animate to attempt to perform an animation on any element.
       
 13528    * When setting the classNameFilter value, animations will only be performed on elements
       
 13529    * that successfully match the filter expression. This in turn can boost performance
       
 13530    * for low-powered devices as well as applications containing a lot of structural operations.
       
 13531    * @param {RegExp=} expression The className expression which will be checked against all animations
       
 13532    * @return {RegExp} The current CSS className expression value. If null then there is no expression value
       
 13533    */
       
 13534   this.classNameFilter = function(expression) {
       
 13535     if(arguments.length === 1) {
       
 13536       this.$$classNameFilter = (expression instanceof RegExp) ? expression : null;
       
 13537     }
       
 13538     return this.$$classNameFilter;
       
 13539   };
       
 13540 
       
 13541   this.$get = ['$$q', '$$asyncCallback', '$rootScope', function($$q, $$asyncCallback, $rootScope) {
       
 13542 
       
 13543     var currentDefer;
       
 13544 
       
 13545     function runAnimationPostDigest(fn) {
       
 13546       var cancelFn, defer = $$q.defer();
       
 13547       defer.promise.$$cancelFn = function ngAnimateMaybeCancel() {
       
 13548         cancelFn && cancelFn();
       
 13549       };
       
 13550 
       
 13551       $rootScope.$$postDigest(function ngAnimatePostDigest() {
       
 13552         cancelFn = fn(function ngAnimateNotifyComplete() {
       
 13553           defer.resolve();
       
 13554         });
       
 13555       });
       
 13556 
       
 13557       return defer.promise;
       
 13558     }
       
 13559 
       
 13560     function resolveElementClasses(element, cache) {
       
 13561       var toAdd = [], toRemove = [];
       
 13562 
       
 13563       var hasClasses = createMap();
       
 13564       forEach((element.attr('class') || '').split(/\s+/), function(className) {
       
 13565         hasClasses[className] = true;
       
 13566       });
       
 13567 
       
 13568       forEach(cache.classes, function(status, className) {
       
 13569         var hasClass = hasClasses[className];
       
 13570 
       
 13571         // If the most recent class manipulation (via $animate) was to remove the class, and the
       
 13572         // element currently has the class, the class is scheduled for removal. Otherwise, if
       
 13573         // the most recent class manipulation (via $animate) was to add the class, and the
       
 13574         // element does not currently have the class, the class is scheduled to be added.
       
 13575         if (status === false && hasClass) {
       
 13576           toRemove.push(className);
       
 13577         } else if (status === true && !hasClass) {
       
 13578           toAdd.push(className);
       
 13579         }
       
 13580       });
       
 13581 
       
 13582       return (toAdd.length + toRemove.length) > 0 && [toAdd.length && toAdd, toRemove.length && toRemove];
       
 13583     }
       
 13584 
       
 13585     function cachedClassManipulation(cache, classes, op) {
       
 13586       for (var i=0, ii = classes.length; i < ii; ++i) {
       
 13587         var className = classes[i];
       
 13588         cache[className] = op;
       
 13589       }
       
 13590     }
       
 13591 
       
 13592     function asyncPromise() {
       
 13593       // only serve one instance of a promise in order to save CPU cycles
       
 13594       if (!currentDefer) {
       
 13595         currentDefer = $$q.defer();
       
 13596         $$asyncCallback(function() {
       
 13597           currentDefer.resolve();
       
 13598           currentDefer = null;
       
 13599         });
       
 13600       }
       
 13601       return currentDefer.promise;
       
 13602     }
       
 13603 
       
 13604     /**
       
 13605      *
       
 13606      * @ngdoc service
       
 13607      * @name $animate
       
 13608      * @description The $animate service provides rudimentary DOM manipulation functions to
       
 13609      * insert, remove and move elements within the DOM, as well as adding and removing classes.
       
 13610      * This service is the core service used by the ngAnimate $animator service which provides
       
 13611      * high-level animation hooks for CSS and JavaScript.
       
 13612      *
       
 13613      * $animate is available in the AngularJS core, however, the ngAnimate module must be included
       
 13614      * to enable full out animation support. Otherwise, $animate will only perform simple DOM
       
 13615      * manipulation operations.
       
 13616      *
       
 13617      * To learn more about enabling animation support, click here to visit the {@link ngAnimate
       
 13618      * ngAnimate module page} as well as the {@link ngAnimate.$animate ngAnimate $animate service
       
 13619      * page}.
       
 13620      */
       
 13621     return {
       
 13622 
       
 13623       /**
       
 13624        *
       
 13625        * @ngdoc method
       
 13626        * @name $animate#enter
       
 13627        * @kind function
       
 13628        * @description Inserts the element into the DOM either after the `after` element or
       
 13629        * as the first child within the `parent` element. When the function is called a promise
       
 13630        * is returned that will be resolved at a later time.
       
 13631        * @param {DOMElement} element the element which will be inserted into the DOM
       
 13632        * @param {DOMElement} parent the parent element which will append the element as
       
 13633        *   a child (if the after element is not present)
       
 13634        * @param {DOMElement} after the sibling element which will append the element
       
 13635        *   after itself
       
 13636        * @return {Promise} the animation callback promise
       
 13637        */
       
 13638       enter : function(element, parent, after) {
       
 13639         after ? after.after(element)
       
 13640               : parent.prepend(element);
       
 13641         return asyncPromise();
       
 13642       },
       
 13643 
       
 13644       /**
       
 13645        *
       
 13646        * @ngdoc method
       
 13647        * @name $animate#leave
       
 13648        * @kind function
       
 13649        * @description Removes the element from the DOM. When the function is called a promise
       
 13650        * is returned that will be resolved at a later time.
       
 13651        * @param {DOMElement} element the element which will be removed from the DOM
       
 13652        * @return {Promise} the animation callback promise
       
 13653        */
       
 13654       leave : function(element) {
       
 13655         element.remove();
       
 13656         return asyncPromise();
       
 13657       },
       
 13658 
       
 13659       /**
       
 13660        *
       
 13661        * @ngdoc method
       
 13662        * @name $animate#move
       
 13663        * @kind function
       
 13664        * @description Moves the position of the provided element within the DOM to be placed
       
 13665        * either after the `after` element or inside of the `parent` element. When the function
       
 13666        * is called a promise is returned that will be resolved at a later time.
       
 13667        *
       
 13668        * @param {DOMElement} element the element which will be moved around within the
       
 13669        *   DOM
       
 13670        * @param {DOMElement} parent the parent element where the element will be
       
 13671        *   inserted into (if the after element is not present)
       
 13672        * @param {DOMElement} after the sibling element where the element will be
       
 13673        *   positioned next to
       
 13674        * @return {Promise} the animation callback promise
       
 13675        */
       
 13676       move : function(element, parent, after) {
       
 13677         // Do not remove element before insert. Removing will cause data associated with the
       
 13678         // element to be dropped. Insert will implicitly do the remove.
       
 13679         return this.enter(element, parent, after);
       
 13680       },
       
 13681 
       
 13682       /**
       
 13683        *
       
 13684        * @ngdoc method
       
 13685        * @name $animate#addClass
       
 13686        * @kind function
       
 13687        * @description Adds the provided className CSS class value to the provided element.
       
 13688        * When the function is called a promise is returned that will be resolved at a later time.
       
 13689        * @param {DOMElement} element the element which will have the className value
       
 13690        *   added to it
       
 13691        * @param {string} className the CSS class which will be added to the element
       
 13692        * @return {Promise} the animation callback promise
       
 13693        */
       
 13694       addClass : function(element, className) {
       
 13695         return this.setClass(element, className, []);
       
 13696       },
       
 13697 
       
 13698       $$addClassImmediately : function addClassImmediately(element, className) {
       
 13699         element = jqLite(element);
       
 13700         className = !isString(className)
       
 13701                         ? (isArray(className) ? className.join(' ') : '')
       
 13702                         : className;
       
 13703         forEach(element, function (element) {
       
 13704           jqLiteAddClass(element, className);
       
 13705         });
       
 13706       },
       
 13707 
       
 13708       /**
       
 13709        *
       
 13710        * @ngdoc method
       
 13711        * @name $animate#removeClass
       
 13712        * @kind function
       
 13713        * @description Removes the provided className CSS class value from the provided element.
       
 13714        * When the function is called a promise is returned that will be resolved at a later time.
       
 13715        * @param {DOMElement} element the element which will have the className value
       
 13716        *   removed from it
       
 13717        * @param {string} className the CSS class which will be removed from the element
       
 13718        * @return {Promise} the animation callback promise
       
 13719        */
       
 13720       removeClass : function(element, className) {
       
 13721         return this.setClass(element, [], className);
       
 13722       },
       
 13723 
       
 13724       $$removeClassImmediately : function removeClassImmediately(element, className) {
       
 13725         element = jqLite(element);
       
 13726         className = !isString(className)
       
 13727                         ? (isArray(className) ? className.join(' ') : '')
       
 13728                         : className;
       
 13729         forEach(element, function (element) {
       
 13730           jqLiteRemoveClass(element, className);
       
 13731         });
       
 13732         return asyncPromise();
       
 13733       },
       
 13734 
       
 13735       /**
       
 13736        *
       
 13737        * @ngdoc method
       
 13738        * @name $animate#setClass
       
 13739        * @kind function
       
 13740        * @description Adds and/or removes the given CSS classes to and from the element.
       
 13741        * When the function is called a promise is returned that will be resolved at a later time.
       
 13742        * @param {DOMElement} element the element which will have its CSS classes changed
       
 13743        *   removed from it
       
 13744        * @param {string} add the CSS classes which will be added to the element
       
 13745        * @param {string} remove the CSS class which will be removed from the element
       
 13746        * @return {Promise} the animation callback promise
       
 13747        */
       
 13748       setClass : function(element, add, remove, runSynchronously) {
       
 13749         var self = this;
       
 13750         var STORAGE_KEY = '$$animateClasses';
       
 13751         var createdCache = false;
       
 13752         element = jqLite(element);
       
 13753 
       
 13754         if (runSynchronously) {
       
 13755           // TODO(@caitp/@matsko): Remove undocumented `runSynchronously` parameter, and always
       
 13756           // perform DOM manipulation asynchronously or in postDigest.
       
 13757           self.$$addClassImmediately(element, add);
       
 13758           self.$$removeClassImmediately(element, remove);
       
 13759           return asyncPromise();
       
 13760         }
       
 13761 
       
 13762         var cache = element.data(STORAGE_KEY);
       
 13763         if (!cache) {
       
 13764           cache = {
       
 13765             classes: {}
       
 13766           };
       
 13767           createdCache = true;
       
 13768         }
       
 13769 
       
 13770         var classes = cache.classes;
       
 13771 
       
 13772         add = isArray(add) ? add : add.split(' ');
       
 13773         remove = isArray(remove) ? remove : remove.split(' ');
       
 13774         cachedClassManipulation(classes, add, true);
       
 13775         cachedClassManipulation(classes, remove, false);
       
 13776 
       
 13777         if (createdCache) {
       
 13778           cache.promise = runAnimationPostDigest(function(done) {
       
 13779             var cache = element.data(STORAGE_KEY);
       
 13780             element.removeData(STORAGE_KEY);
       
 13781 
       
 13782             var classes = cache && resolveElementClasses(element, cache);
       
 13783 
       
 13784             if (classes) {
       
 13785               if (classes[0]) self.$$addClassImmediately(element, classes[0]);
       
 13786               if (classes[1]) self.$$removeClassImmediately(element, classes[1]);
       
 13787             }
       
 13788 
       
 13789             done();
       
 13790           });
       
 13791           element.data(STORAGE_KEY, cache);
       
 13792         }
       
 13793 
       
 13794         return cache.promise;
       
 13795       },
       
 13796 
       
 13797       enabled : noop,
       
 13798       cancel : noop
       
 13799     };
       
 13800   }];
       
 13801 }];
       
 13802 
       
 13803 function $$AsyncCallbackProvider(){
       
 13804   this.$get = ['$$rAF', '$timeout', function($$rAF, $timeout) {
       
 13805     return $$rAF.supported
       
 13806       ? function(fn) { return $$rAF(fn); }
       
 13807       : function(fn) {
       
 13808         return $timeout(fn, 0, false);
       
 13809       };
       
 13810   }];
       
 13811 }
       
 13812 
       
 13813 /* global stripHash: true */
       
 13814 
       
 13815 /**
       
 13816  * ! This is a private undocumented service !
       
 13817  *
       
 13818  * @name $browser
       
 13819  * @requires $log
       
 13820  * @description
       
 13821  * This object has two goals:
       
 13822  *
       
 13823  * - hide all the global state in the browser caused by the window object
       
 13824  * - abstract away all the browser specific features and inconsistencies
       
 13825  *
       
 13826  * For tests we provide {@link ngMock.$browser mock implementation} of the `$browser`
       
 13827  * service, which can be used for convenient testing of the application without the interaction with
       
 13828  * the real browser apis.
       
 13829  */
       
 13830 /**
       
 13831  * @param {object} window The global window object.
       
 13832  * @param {object} document jQuery wrapped document.
       
 13833  * @param {function()} XHR XMLHttpRequest constructor.
       
 13834  * @param {object} $log console.log or an object with the same interface.
       
 13835  * @param {object} $sniffer $sniffer service
       
 13836  */
       
 13837 function Browser(window, document, $log, $sniffer) {
       
 13838   var self = this,
       
 13839       rawDocument = document[0],
       
 13840       location = window.location,
       
 13841       history = window.history,
       
 13842       setTimeout = window.setTimeout,
       
 13843       clearTimeout = window.clearTimeout,
       
 13844       pendingDeferIds = {};
       
 13845 
       
 13846   self.isMock = false;
       
 13847 
       
 13848   var outstandingRequestCount = 0;
       
 13849   var outstandingRequestCallbacks = [];
       
 13850 
       
 13851   // TODO(vojta): remove this temporary api
       
 13852   self.$$completeOutstandingRequest = completeOutstandingRequest;
       
 13853   self.$$incOutstandingRequestCount = function() { outstandingRequestCount++; };
       
 13854 
       
 13855   /**
       
 13856    * Executes the `fn` function(supports currying) and decrements the `outstandingRequestCallbacks`
       
 13857    * counter. If the counter reaches 0, all the `outstandingRequestCallbacks` are executed.
       
 13858    */
       
 13859   function completeOutstandingRequest(fn) {
       
 13860     try {
       
 13861       fn.apply(null, sliceArgs(arguments, 1));
       
 13862     } finally {
       
 13863       outstandingRequestCount--;
       
 13864       if (outstandingRequestCount === 0) {
       
 13865         while(outstandingRequestCallbacks.length) {
       
 13866           try {
       
 13867             outstandingRequestCallbacks.pop()();
       
 13868           } catch (e) {
       
 13869             $log.error(e);
       
 13870           }
       
 13871         }
       
 13872       }
       
 13873     }
       
 13874   }
       
 13875 
       
 13876   /**
       
 13877    * @private
       
 13878    * Note: this method is used only by scenario runner
       
 13879    * TODO(vojta): prefix this method with $$ ?
       
 13880    * @param {function()} callback Function that will be called when no outstanding request
       
 13881    */
       
 13882   self.notifyWhenNoOutstandingRequests = function(callback) {
       
 13883     // force browser to execute all pollFns - this is needed so that cookies and other pollers fire
       
 13884     // at some deterministic time in respect to the test runner's actions. Leaving things up to the
       
 13885     // regular poller would result in flaky tests.
       
 13886     forEach(pollFns, function(pollFn){ pollFn(); });
       
 13887 
       
 13888     if (outstandingRequestCount === 0) {
       
 13889       callback();
       
 13890     } else {
       
 13891       outstandingRequestCallbacks.push(callback);
       
 13892     }
       
 13893   };
       
 13894 
       
 13895   //////////////////////////////////////////////////////////////
       
 13896   // Poll Watcher API
       
 13897   //////////////////////////////////////////////////////////////
       
 13898   var pollFns = [],
       
 13899       pollTimeout;
       
 13900 
       
 13901   /**
       
 13902    * @name $browser#addPollFn
       
 13903    *
       
 13904    * @param {function()} fn Poll function to add
       
 13905    *
       
 13906    * @description
       
 13907    * Adds a function to the list of functions that poller periodically executes,
       
 13908    * and starts polling if not started yet.
       
 13909    *
       
 13910    * @returns {function()} the added function
       
 13911    */
       
 13912   self.addPollFn = function(fn) {
       
 13913     if (isUndefined(pollTimeout)) startPoller(100, setTimeout);
       
 13914     pollFns.push(fn);
       
 13915     return fn;
       
 13916   };
       
 13917 
       
 13918   /**
       
 13919    * @param {number} interval How often should browser call poll functions (ms)
       
 13920    * @param {function()} setTimeout Reference to a real or fake `setTimeout` function.
       
 13921    *
       
 13922    * @description
       
 13923    * Configures the poller to run in the specified intervals, using the specified
       
 13924    * setTimeout fn and kicks it off.
       
 13925    */
       
 13926   function startPoller(interval, setTimeout) {
       
 13927     (function check() {
       
 13928       forEach(pollFns, function(pollFn){ pollFn(); });
       
 13929       pollTimeout = setTimeout(check, interval);
       
 13930     })();
       
 13931   }
       
 13932 
       
 13933   //////////////////////////////////////////////////////////////
       
 13934   // URL API
       
 13935   //////////////////////////////////////////////////////////////
       
 13936 
       
 13937   var lastBrowserUrl = location.href,
       
 13938       lastHistoryState = history.state,
       
 13939       baseElement = document.find('base'),
       
 13940       reloadLocation = null;
       
 13941 
       
 13942   /**
       
 13943    * @name $browser#url
       
 13944    *
       
 13945    * @description
       
 13946    * GETTER:
       
 13947    * Without any argument, this method just returns current value of location.href.
       
 13948    *
       
 13949    * SETTER:
       
 13950    * With at least one argument, this method sets url to new value.
       
 13951    * If html5 history api supported, pushState/replaceState is used, otherwise
       
 13952    * location.href/location.replace is used.
       
 13953    * Returns its own instance to allow chaining
       
 13954    *
       
 13955    * NOTE: this api is intended for use only by the $location service. Please use the
       
 13956    * {@link ng.$location $location service} to change url.
       
 13957    *
       
 13958    * @param {string} url New url (when used as setter)
       
 13959    * @param {boolean=} replace Should new url replace current history record?
       
 13960    * @param {object=} state object to use with pushState/replaceState
       
 13961    */
       
 13962   self.url = function(url, replace, state) {
       
 13963     // In modern browsers `history.state` is `null` by default; treating it separately
       
 13964     // from `undefined` would cause `$browser.url('/foo')` to change `history.state`
       
 13965     // to undefined via `pushState`. Instead, let's change `undefined` to `null` here.
       
 13966     if (isUndefined(state)) {
       
 13967       state = null;
       
 13968     }
       
 13969 
       
 13970     // Android Browser BFCache causes location, history reference to become stale.
       
 13971     if (location !== window.location) location = window.location;
       
 13972     if (history !== window.history) history = window.history;
       
 13973 
       
 13974     // setter
       
 13975     if (url) {
       
 13976       // Don't change anything if previous and current URLs and states match. This also prevents
       
 13977       // IE<10 from getting into redirect loop when in LocationHashbangInHtml5Url mode.
       
 13978       // See https://github.com/angular/angular.js/commit/ffb2701
       
 13979       if (lastBrowserUrl === url && (!$sniffer.history || history.state === state)) {
       
 13980         return;
       
 13981       }
       
 13982       var sameBase = lastBrowserUrl && stripHash(lastBrowserUrl) === stripHash(url);
       
 13983       lastBrowserUrl = url;
       
 13984       // Don't use history API if only the hash changed
       
 13985       // due to a bug in IE10/IE11 which leads
       
 13986       // to not firing a `hashchange` nor `popstate` event
       
 13987       // in some cases (see #9143).
       
 13988       if ($sniffer.history && (!sameBase || history.state !== state)) {
       
 13989         history[replace ? 'replaceState' : 'pushState'](state, '', url);
       
 13990         lastHistoryState = history.state;
       
 13991       } else {
       
 13992         if (!sameBase) {
       
 13993           reloadLocation = url;
       
 13994         }
       
 13995         if (replace) {
       
 13996           location.replace(url);
       
 13997         } else {
       
 13998           location.href = url;
       
 13999         }
       
 14000       }
       
 14001       return self;
       
 14002     // getter
       
 14003     } else {
       
 14004       // - reloadLocation is needed as browsers don't allow to read out
       
 14005       //   the new location.href if a reload happened.
       
 14006       // - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172
       
 14007       return reloadLocation || location.href.replace(/%27/g,"'");
       
 14008     }
       
 14009   };
       
 14010 
       
 14011   /**
       
 14012    * @name $browser#state
       
 14013    *
       
 14014    * @description
       
 14015    * This method is a getter.
       
 14016    *
       
 14017    * Return history.state or null if history.state is undefined.
       
 14018    *
       
 14019    * @returns {object} state
       
 14020    */
       
 14021   self.state = function() {
       
 14022     return isUndefined(history.state) ? null : history.state;
       
 14023   };
       
 14024 
       
 14025   var urlChangeListeners = [],
       
 14026       urlChangeInit = false;
       
 14027 
       
 14028   function fireUrlChange() {
       
 14029     if (lastBrowserUrl === self.url() && lastHistoryState === history.state) {
       
 14030       return;
       
 14031     }
       
 14032 
       
 14033     lastBrowserUrl = self.url();
       
 14034     forEach(urlChangeListeners, function(listener) {
       
 14035       listener(self.url(), history.state);
       
 14036     });
       
 14037   }
       
 14038 
       
 14039   /**
       
 14040    * @name $browser#onUrlChange
       
 14041    *
       
 14042    * @description
       
 14043    * Register callback function that will be called, when url changes.
       
 14044    *
       
 14045    * It's only called when the url is changed from outside of angular:
       
 14046    * - user types different url into address bar
       
 14047    * - user clicks on history (forward/back) button
       
 14048    * - user clicks on a link
       
 14049    *
       
 14050    * It's not called when url is changed by $browser.url() method
       
 14051    *
       
 14052    * The listener gets called with new url as parameter.
       
 14053    *
       
 14054    * NOTE: this api is intended for use only by the $location service. Please use the
       
 14055    * {@link ng.$location $location service} to monitor url changes in angular apps.
       
 14056    *
       
 14057    * @param {function(string)} listener Listener function to be called when url changes.
       
 14058    * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous.
       
 14059    */
       
 14060   self.onUrlChange = function(callback) {
       
 14061     // TODO(vojta): refactor to use node's syntax for events
       
 14062     if (!urlChangeInit) {
       
 14063       // We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera)
       
 14064       // don't fire popstate when user change the address bar and don't fire hashchange when url
       
 14065       // changed by push/replaceState
       
 14066 
       
 14067       // html5 history api - popstate event
       
 14068       if ($sniffer.history) jqLite(window).on('popstate', fireUrlChange);
       
 14069       // hashchange event
       
 14070       jqLite(window).on('hashchange', fireUrlChange);
       
 14071 
       
 14072       urlChangeInit = true;
       
 14073     }
       
 14074 
       
 14075     urlChangeListeners.push(callback);
       
 14076     return callback;
       
 14077   };
       
 14078 
       
 14079   /**
       
 14080    * Checks whether the url has changed outside of Angular.
       
 14081    * Needs to be exported to be able to check for changes that have been done in sync,
       
 14082    * as hashchange/popstate events fire in async.
       
 14083    */
       
 14084   self.$$checkUrlChange = fireUrlChange;
       
 14085 
       
 14086   //////////////////////////////////////////////////////////////
       
 14087   // Misc API
       
 14088   //////////////////////////////////////////////////////////////
       
 14089 
       
 14090   /**
       
 14091    * @name $browser#baseHref
       
 14092    *
       
 14093    * @description
       
 14094    * Returns current <base href>
       
 14095    * (always relative - without domain)
       
 14096    *
       
 14097    * @returns {string} The current base href
       
 14098    */
       
 14099   self.baseHref = function() {
       
 14100     var href = baseElement.attr('href');
       
 14101     return href ? href.replace(/^(https?\:)?\/\/[^\/]*/, '') : '';
       
 14102   };
       
 14103 
       
 14104   //////////////////////////////////////////////////////////////
       
 14105   // Cookies API
       
 14106   //////////////////////////////////////////////////////////////
       
 14107   var lastCookies = {};
       
 14108   var lastCookieString = '';
       
 14109   var cookiePath = self.baseHref();
       
 14110 
       
 14111   /**
       
 14112    * @name $browser#cookies
       
 14113    *
       
 14114    * @param {string=} name Cookie name
       
 14115    * @param {string=} value Cookie value
       
 14116    *
       
 14117    * @description
       
 14118    * The cookies method provides a 'private' low level access to browser cookies.
       
 14119    * It is not meant to be used directly, use the $cookie service instead.
       
 14120    *
       
 14121    * The return values vary depending on the arguments that the method was called with as follows:
       
 14122    *
       
 14123    * - cookies() -> hash of all cookies, this is NOT a copy of the internal state, so do not modify
       
 14124    *   it
       
 14125    * - cookies(name, value) -> set name to value, if value is undefined delete the cookie
       
 14126    * - cookies(name) -> the same as (name, undefined) == DELETES (no one calls it right now that
       
 14127    *   way)
       
 14128    *
       
 14129    * @returns {Object} Hash of all cookies (if called without any parameter)
       
 14130    */
       
 14131   self.cookies = function(name, value) {
       
 14132     var cookieLength, cookieArray, cookie, i, index;
       
 14133 
       
 14134     if (name) {
       
 14135       if (value === undefined) {
       
 14136         rawDocument.cookie = encodeURIComponent(name) + "=;path=" + cookiePath +
       
 14137                                 ";expires=Thu, 01 Jan 1970 00:00:00 GMT";
       
 14138       } else {
       
 14139         if (isString(value)) {
       
 14140           cookieLength = (rawDocument.cookie = encodeURIComponent(name) + '=' + encodeURIComponent(value) +
       
 14141                                 ';path=' + cookiePath).length + 1;
       
 14142 
       
 14143           // per http://www.ietf.org/rfc/rfc2109.txt browser must allow at minimum:
       
 14144           // - 300 cookies
       
 14145           // - 20 cookies per unique domain
       
 14146           // - 4096 bytes per cookie
       
 14147           if (cookieLength > 4096) {
       
 14148             $log.warn("Cookie '"+ name +
       
 14149               "' possibly not set or overflowed because it was too large ("+
       
 14150               cookieLength + " > 4096 bytes)!");
       
 14151           }
       
 14152         }
       
 14153       }
       
 14154     } else {
       
 14155       if (rawDocument.cookie !== lastCookieString) {
       
 14156         lastCookieString = rawDocument.cookie;
       
 14157         cookieArray = lastCookieString.split("; ");
       
 14158         lastCookies = {};
       
 14159 
       
 14160         for (i = 0; i < cookieArray.length; i++) {
       
 14161           cookie = cookieArray[i];
       
 14162           index = cookie.indexOf('=');
       
 14163           if (index > 0) { //ignore nameless cookies
       
 14164             name = decodeURIComponent(cookie.substring(0, index));
       
 14165             // the first value that is seen for a cookie is the most
       
 14166             // specific one.  values for the same cookie name that
       
 14167             // follow are for less specific paths.
       
 14168             if (lastCookies[name] === undefined) {
       
 14169               lastCookies[name] = decodeURIComponent(cookie.substring(index + 1));
       
 14170             }
       
 14171           }
       
 14172         }
       
 14173       }
       
 14174       return lastCookies;
       
 14175     }
       
 14176   };
       
 14177 
       
 14178 
       
 14179   /**
       
 14180    * @name $browser#defer
       
 14181    * @param {function()} fn A function, who's execution should be deferred.
       
 14182    * @param {number=} [delay=0] of milliseconds to defer the function execution.
       
 14183    * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`.
       
 14184    *
       
 14185    * @description
       
 14186    * Executes a fn asynchronously via `setTimeout(fn, delay)`.
       
 14187    *
       
 14188    * Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using
       
 14189    * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed
       
 14190    * via `$browser.defer.flush()`.
       
 14191    *
       
 14192    */
       
 14193   self.defer = function(fn, delay) {
       
 14194     var timeoutId;
       
 14195     outstandingRequestCount++;
       
 14196     timeoutId = setTimeout(function() {
       
 14197       delete pendingDeferIds[timeoutId];
       
 14198       completeOutstandingRequest(fn);
       
 14199     }, delay || 0);
       
 14200     pendingDeferIds[timeoutId] = true;
       
 14201     return timeoutId;
       
 14202   };
       
 14203 
       
 14204 
       
 14205   /**
       
 14206    * @name $browser#defer.cancel
       
 14207    *
       
 14208    * @description
       
 14209    * Cancels a deferred task identified with `deferId`.
       
 14210    *
       
 14211    * @param {*} deferId Token returned by the `$browser.defer` function.
       
 14212    * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
       
 14213    *                    canceled.
       
 14214    */
       
 14215   self.defer.cancel = function(deferId) {
       
 14216     if (pendingDeferIds[deferId]) {
       
 14217       delete pendingDeferIds[deferId];
       
 14218       clearTimeout(deferId);
       
 14219       completeOutstandingRequest(noop);
       
 14220       return true;
       
 14221     }
       
 14222     return false;
       
 14223   };
       
 14224 
       
 14225 }
       
 14226 
       
 14227 function $BrowserProvider(){
       
 14228   this.$get = ['$window', '$log', '$sniffer', '$document',
       
 14229       function( $window,   $log,   $sniffer,   $document){
       
 14230         return new Browser($window, $document, $log, $sniffer);
       
 14231       }];
       
 14232 }
       
 14233 
       
 14234 /**
       
 14235  * @ngdoc service
       
 14236  * @name $cacheFactory
       
 14237  *
       
 14238  * @description
       
 14239  * Factory that constructs {@link $cacheFactory.Cache Cache} objects and gives access to
       
 14240  * them.
       
 14241  *
       
 14242  * ```js
       
 14243  *
       
 14244  *  var cache = $cacheFactory('cacheId');
       
 14245  *  expect($cacheFactory.get('cacheId')).toBe(cache);
       
 14246  *  expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined();
       
 14247  *
       
 14248  *  cache.put("key", "value");
       
 14249  *  cache.put("another key", "another value");
       
 14250  *
       
 14251  *  // We've specified no options on creation
       
 14252  *  expect(cache.info()).toEqual({id: 'cacheId', size: 2});
       
 14253  *
       
 14254  * ```
       
 14255  *
       
 14256  *
       
 14257  * @param {string} cacheId Name or id of the newly created cache.
       
 14258  * @param {object=} options Options object that specifies the cache behavior. Properties:
       
 14259  *
       
 14260  *   - `{number=}` `capacity` — turns the cache into LRU cache.
       
 14261  *
       
 14262  * @returns {object} Newly created cache object with the following set of methods:
       
 14263  *
       
 14264  * - `{object}` `info()` — Returns id, size, and options of cache.
       
 14265  * - `{{*}}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache and returns
       
 14266  *   it.
       
 14267  * - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss.
       
 14268  * - `{void}` `remove({string} key)` — Removes a key-value pair from the cache.
       
 14269  * - `{void}` `removeAll()` — Removes all cached values.
       
 14270  * - `{void}` `destroy()` — Removes references to this cache from $cacheFactory.
       
 14271  *
       
 14272  * @example
       
 14273    <example module="cacheExampleApp">
       
 14274      <file name="index.html">
       
 14275        <div ng-controller="CacheController">
       
 14276          <input ng-model="newCacheKey" placeholder="Key">
       
 14277          <input ng-model="newCacheValue" placeholder="Value">
       
 14278          <button ng-click="put(newCacheKey, newCacheValue)">Cache</button>
       
 14279 
       
 14280          <p ng-if="keys.length">Cached Values</p>
       
 14281          <div ng-repeat="key in keys">
       
 14282            <span ng-bind="key"></span>
       
 14283            <span>: </span>
       
 14284            <b ng-bind="cache.get(key)"></b>
       
 14285          </div>
       
 14286 
       
 14287          <p>Cache Info</p>
       
 14288          <div ng-repeat="(key, value) in cache.info()">
       
 14289            <span ng-bind="key"></span>
       
 14290            <span>: </span>
       
 14291            <b ng-bind="value"></b>
       
 14292          </div>
       
 14293        </div>
       
 14294      </file>
       
 14295      <file name="script.js">
       
 14296        angular.module('cacheExampleApp', []).
       
 14297          controller('CacheController', ['$scope', '$cacheFactory', function($scope, $cacheFactory) {
       
 14298            $scope.keys = [];
       
 14299            $scope.cache = $cacheFactory('cacheId');
       
 14300            $scope.put = function(key, value) {
       
 14301              if ($scope.cache.get(key) === undefined) {
       
 14302                $scope.keys.push(key);
       
 14303              }
       
 14304              $scope.cache.put(key, value === undefined ? null : value);
       
 14305            };
       
 14306          }]);
       
 14307      </file>
       
 14308      <file name="style.css">
       
 14309        p {
       
 14310          margin: 10px 0 3px;
       
 14311        }
       
 14312      </file>
       
 14313    </example>
       
 14314  */
       
 14315 function $CacheFactoryProvider() {
       
 14316 
       
 14317   this.$get = function() {
       
 14318     var caches = {};
       
 14319 
       
 14320     function cacheFactory(cacheId, options) {
       
 14321       if (cacheId in caches) {
       
 14322         throw minErr('$cacheFactory')('iid', "CacheId '{0}' is already taken!", cacheId);
       
 14323       }
       
 14324 
       
 14325       var size = 0,
       
 14326           stats = extend({}, options, {id: cacheId}),
       
 14327           data = {},
       
 14328           capacity = (options && options.capacity) || Number.MAX_VALUE,
       
 14329           lruHash = {},
       
 14330           freshEnd = null,
       
 14331           staleEnd = null;
       
 14332 
       
 14333       /**
       
 14334        * @ngdoc type
       
 14335        * @name $cacheFactory.Cache
       
 14336        *
       
 14337        * @description
       
 14338        * A cache object used to store and retrieve data, primarily used by
       
 14339        * {@link $http $http} and the {@link ng.directive:script script} directive to cache
       
 14340        * templates and other data.
       
 14341        *
       
 14342        * ```js
       
 14343        *  angular.module('superCache')
       
 14344        *    .factory('superCache', ['$cacheFactory', function($cacheFactory) {
       
 14345        *      return $cacheFactory('super-cache');
       
 14346        *    }]);
       
 14347        * ```
       
 14348        *
       
 14349        * Example test:
       
 14350        *
       
 14351        * ```js
       
 14352        *  it('should behave like a cache', inject(function(superCache) {
       
 14353        *    superCache.put('key', 'value');
       
 14354        *    superCache.put('another key', 'another value');
       
 14355        *
       
 14356        *    expect(superCache.info()).toEqual({
       
 14357        *      id: 'super-cache',
       
 14358        *      size: 2
       
 14359        *    });
       
 14360        *
       
 14361        *    superCache.remove('another key');
       
 14362        *    expect(superCache.get('another key')).toBeUndefined();
       
 14363        *
       
 14364        *    superCache.removeAll();
       
 14365        *    expect(superCache.info()).toEqual({
       
 14366        *      id: 'super-cache',
       
 14367        *      size: 0
       
 14368        *    });
       
 14369        *  }));
       
 14370        * ```
       
 14371        */
       
 14372       return caches[cacheId] = {
       
 14373 
       
 14374         /**
       
 14375          * @ngdoc method
       
 14376          * @name $cacheFactory.Cache#put
       
 14377          * @kind function
       
 14378          *
       
 14379          * @description
       
 14380          * Inserts a named entry into the {@link $cacheFactory.Cache Cache} object to be
       
 14381          * retrieved later, and incrementing the size of the cache if the key was not already
       
 14382          * present in the cache. If behaving like an LRU cache, it will also remove stale
       
 14383          * entries from the set.
       
 14384          *
       
 14385          * It will not insert undefined values into the cache.
       
 14386          *
       
 14387          * @param {string} key the key under which the cached data is stored.
       
 14388          * @param {*} value the value to store alongside the key. If it is undefined, the key
       
 14389          *    will not be stored.
       
 14390          * @returns {*} the value stored.
       
 14391          */
       
 14392         put: function(key, value) {
       
 14393           if (capacity < Number.MAX_VALUE) {
       
 14394             var lruEntry = lruHash[key] || (lruHash[key] = {key: key});
       
 14395 
       
 14396             refresh(lruEntry);
       
 14397           }
       
 14398 
       
 14399           if (isUndefined(value)) return;
       
 14400           if (!(key in data)) size++;
       
 14401           data[key] = value;
       
 14402 
       
 14403           if (size > capacity) {
       
 14404             this.remove(staleEnd.key);
       
 14405           }
       
 14406 
       
 14407           return value;
       
 14408         },
       
 14409 
       
 14410         /**
       
 14411          * @ngdoc method
       
 14412          * @name $cacheFactory.Cache#get
       
 14413          * @kind function
       
 14414          *
       
 14415          * @description
       
 14416          * Retrieves named data stored in the {@link $cacheFactory.Cache Cache} object.
       
 14417          *
       
 14418          * @param {string} key the key of the data to be retrieved
       
 14419          * @returns {*} the value stored.
       
 14420          */
       
 14421         get: function(key) {
       
 14422           if (capacity < Number.MAX_VALUE) {
       
 14423             var lruEntry = lruHash[key];
       
 14424 
       
 14425             if (!lruEntry) return;
       
 14426 
       
 14427             refresh(lruEntry);
       
 14428           }
       
 14429 
       
 14430           return data[key];
       
 14431         },
       
 14432 
       
 14433 
       
 14434         /**
       
 14435          * @ngdoc method
       
 14436          * @name $cacheFactory.Cache#remove
       
 14437          * @kind function
       
 14438          *
       
 14439          * @description
       
 14440          * Removes an entry from the {@link $cacheFactory.Cache Cache} object.
       
 14441          *
       
 14442          * @param {string} key the key of the entry to be removed
       
 14443          */
       
 14444         remove: function(key) {
       
 14445           if (capacity < Number.MAX_VALUE) {
       
 14446             var lruEntry = lruHash[key];
       
 14447 
       
 14448             if (!lruEntry) return;
       
 14449 
       
 14450             if (lruEntry == freshEnd) freshEnd = lruEntry.p;
       
 14451             if (lruEntry == staleEnd) staleEnd = lruEntry.n;
       
 14452             link(lruEntry.n,lruEntry.p);
       
 14453 
       
 14454             delete lruHash[key];
       
 14455           }
       
 14456 
       
 14457           delete data[key];
       
 14458           size--;
       
 14459         },
       
 14460 
       
 14461 
       
 14462         /**
       
 14463          * @ngdoc method
       
 14464          * @name $cacheFactory.Cache#removeAll
       
 14465          * @kind function
       
 14466          *
       
 14467          * @description
       
 14468          * Clears the cache object of any entries.
       
 14469          */
       
 14470         removeAll: function() {
       
 14471           data = {};
       
 14472           size = 0;
       
 14473           lruHash = {};
       
 14474           freshEnd = staleEnd = null;
       
 14475         },
       
 14476 
       
 14477 
       
 14478         /**
       
 14479          * @ngdoc method
       
 14480          * @name $cacheFactory.Cache#destroy
       
 14481          * @kind function
       
 14482          *
       
 14483          * @description
       
 14484          * Destroys the {@link $cacheFactory.Cache Cache} object entirely,
       
 14485          * removing it from the {@link $cacheFactory $cacheFactory} set.
       
 14486          */
       
 14487         destroy: function() {
       
 14488           data = null;
       
 14489           stats = null;
       
 14490           lruHash = null;
       
 14491           delete caches[cacheId];
       
 14492         },
       
 14493 
       
 14494 
       
 14495         /**
       
 14496          * @ngdoc method
       
 14497          * @name $cacheFactory.Cache#info
       
 14498          * @kind function
       
 14499          *
       
 14500          * @description
       
 14501          * Retrieve information regarding a particular {@link $cacheFactory.Cache Cache}.
       
 14502          *
       
 14503          * @returns {object} an object with the following properties:
       
 14504          *   <ul>
       
 14505          *     <li>**id**: the id of the cache instance</li>
       
 14506          *     <li>**size**: the number of entries kept in the cache instance</li>
       
 14507          *     <li>**...**: any additional properties from the options object when creating the
       
 14508          *       cache.</li>
       
 14509          *   </ul>
       
 14510          */
       
 14511         info: function() {
       
 14512           return extend({}, stats, {size: size});
       
 14513         }
       
 14514       };
       
 14515 
       
 14516 
       
 14517       /**
       
 14518        * makes the `entry` the freshEnd of the LRU linked list
       
 14519        */
       
 14520       function refresh(entry) {
       
 14521         if (entry != freshEnd) {
       
 14522           if (!staleEnd) {
       
 14523             staleEnd = entry;
       
 14524           } else if (staleEnd == entry) {
       
 14525             staleEnd = entry.n;
       
 14526           }
       
 14527 
       
 14528           link(entry.n, entry.p);
       
 14529           link(entry, freshEnd);
       
 14530           freshEnd = entry;
       
 14531           freshEnd.n = null;
       
 14532         }
       
 14533       }
       
 14534 
       
 14535 
       
 14536       /**
       
 14537        * bidirectionally links two entries of the LRU linked list
       
 14538        */
       
 14539       function link(nextEntry, prevEntry) {
       
 14540         if (nextEntry != prevEntry) {
       
 14541           if (nextEntry) nextEntry.p = prevEntry; //p stands for previous, 'prev' didn't minify
       
 14542           if (prevEntry) prevEntry.n = nextEntry; //n stands for next, 'next' didn't minify
       
 14543         }
       
 14544       }
       
 14545     }
       
 14546 
       
 14547 
       
 14548   /**
       
 14549    * @ngdoc method
       
 14550    * @name $cacheFactory#info
       
 14551    *
       
 14552    * @description
       
 14553    * Get information about all the caches that have been created
       
 14554    *
       
 14555    * @returns {Object} - key-value map of `cacheId` to the result of calling `cache#info`
       
 14556    */
       
 14557     cacheFactory.info = function() {
       
 14558       var info = {};
       
 14559       forEach(caches, function(cache, cacheId) {
       
 14560         info[cacheId] = cache.info();
       
 14561       });
       
 14562       return info;
       
 14563     };
       
 14564 
       
 14565 
       
 14566   /**
       
 14567    * @ngdoc method
       
 14568    * @name $cacheFactory#get
       
 14569    *
       
 14570    * @description
       
 14571    * Get access to a cache object by the `cacheId` used when it was created.
       
 14572    *
       
 14573    * @param {string} cacheId Name or id of a cache to access.
       
 14574    * @returns {object} Cache object identified by the cacheId or undefined if no such cache.
       
 14575    */
       
 14576     cacheFactory.get = function(cacheId) {
       
 14577       return caches[cacheId];
       
 14578     };
       
 14579 
       
 14580 
       
 14581     return cacheFactory;
       
 14582   };
       
 14583 }
       
 14584 
       
 14585 /**
       
 14586  * @ngdoc service
       
 14587  * @name $templateCache
       
 14588  *
       
 14589  * @description
       
 14590  * The first time a template is used, it is loaded in the template cache for quick retrieval. You
       
 14591  * can load templates directly into the cache in a `script` tag, or by consuming the
       
 14592  * `$templateCache` service directly.
       
 14593  *
       
 14594  * Adding via the `script` tag:
       
 14595  *
       
 14596  * ```html
       
 14597  *   <script type="text/ng-template" id="templateId.html">
       
 14598  *     <p>This is the content of the template</p>
       
 14599  *   </script>
       
 14600  * ```
       
 14601  *
       
 14602  * **Note:** the `script` tag containing the template does not need to be included in the `head` of
       
 14603  * the document, but it must be below the `ng-app` definition.
       
 14604  *
       
 14605  * Adding via the $templateCache service:
       
 14606  *
       
 14607  * ```js
       
 14608  * var myApp = angular.module('myApp', []);
       
 14609  * myApp.run(function($templateCache) {
       
 14610  *   $templateCache.put('templateId.html', 'This is the content of the template');
       
 14611  * });
       
 14612  * ```
       
 14613  *
       
 14614  * To retrieve the template later, simply use it in your HTML:
       
 14615  * ```html
       
 14616  * <div ng-include=" 'templateId.html' "></div>
       
 14617  * ```
       
 14618  *
       
 14619  * or get it via Javascript:
       
 14620  * ```js
       
 14621  * $templateCache.get('templateId.html')
       
 14622  * ```
       
 14623  *
       
 14624  * See {@link ng.$cacheFactory $cacheFactory}.
       
 14625  *
       
 14626  */
       
 14627 function $TemplateCacheProvider() {
       
 14628   this.$get = ['$cacheFactory', function($cacheFactory) {
       
 14629     return $cacheFactory('templates');
       
 14630   }];
       
 14631 }
       
 14632 
       
 14633 /* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE!
       
 14634  *
       
 14635  * DOM-related variables:
       
 14636  *
       
 14637  * - "node" - DOM Node
       
 14638  * - "element" - DOM Element or Node
       
 14639  * - "$node" or "$element" - jqLite-wrapped node or element
       
 14640  *
       
 14641  *
       
 14642  * Compiler related stuff:
       
 14643  *
       
 14644  * - "linkFn" - linking fn of a single directive
       
 14645  * - "nodeLinkFn" - function that aggregates all linking fns for a particular node
       
 14646  * - "childLinkFn" -  function that aggregates all linking fns for child nodes of a particular node
       
 14647  * - "compositeLinkFn" - function that aggregates all linking fns for a compilation root (nodeList)
       
 14648  */
       
 14649 
       
 14650 
       
 14651 /**
       
 14652  * @ngdoc service
       
 14653  * @name $compile
       
 14654  * @kind function
       
 14655  *
       
 14656  * @description
       
 14657  * Compiles an HTML string or DOM into a template and produces a template function, which
       
 14658  * can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together.
       
 14659  *
       
 14660  * The compilation is a process of walking the DOM tree and matching DOM elements to
       
 14661  * {@link ng.$compileProvider#directive directives}.
       
 14662  *
       
 14663  * <div class="alert alert-warning">
       
 14664  * **Note:** This document is an in-depth reference of all directive options.
       
 14665  * For a gentle introduction to directives with examples of common use cases,
       
 14666  * see the {@link guide/directive directive guide}.
       
 14667  * </div>
       
 14668  *
       
 14669  * ## Comprehensive Directive API
       
 14670  *
       
 14671  * There are many different options for a directive.
       
 14672  *
       
 14673  * The difference resides in the return value of the factory function.
       
 14674  * You can either return a "Directive Definition Object" (see below) that defines the directive properties,
       
 14675  * or just the `postLink` function (all other properties will have the default values).
       
 14676  *
       
 14677  * <div class="alert alert-success">
       
 14678  * **Best Practice:** It's recommended to use the "directive definition object" form.
       
 14679  * </div>
       
 14680  *
       
 14681  * Here's an example directive declared with a Directive Definition Object:
       
 14682  *
       
 14683  * ```js
       
 14684  *   var myModule = angular.module(...);
       
 14685  *
       
 14686  *   myModule.directive('directiveName', function factory(injectables) {
       
 14687  *     var directiveDefinitionObject = {
       
 14688  *       priority: 0,
       
 14689  *       template: '<div></div>', // or // function(tElement, tAttrs) { ... },
       
 14690  *       // or
       
 14691  *       // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... },
       
 14692  *       transclude: false,
       
 14693  *       restrict: 'A',
       
 14694  *       scope: false,
       
 14695  *       controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
       
 14696  *       controllerAs: 'stringAlias',
       
 14697  *       require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'],
       
 14698  *       compile: function compile(tElement, tAttrs, transclude) {
       
 14699  *         return {
       
 14700  *           pre: function preLink(scope, iElement, iAttrs, controller) { ... },
       
 14701  *           post: function postLink(scope, iElement, iAttrs, controller) { ... }
       
 14702  *         }
       
 14703  *         // or
       
 14704  *         // return function postLink( ... ) { ... }
       
 14705  *       },
       
 14706  *       // or
       
 14707  *       // link: {
       
 14708  *       //  pre: function preLink(scope, iElement, iAttrs, controller) { ... },
       
 14709  *       //  post: function postLink(scope, iElement, iAttrs, controller) { ... }
       
 14710  *       // }
       
 14711  *       // or
       
 14712  *       // link: function postLink( ... ) { ... }
       
 14713  *     };
       
 14714  *     return directiveDefinitionObject;
       
 14715  *   });
       
 14716  * ```
       
 14717  *
       
 14718  * <div class="alert alert-warning">
       
 14719  * **Note:** Any unspecified options will use the default value. You can see the default values below.
       
 14720  * </div>
       
 14721  *
       
 14722  * Therefore the above can be simplified as:
       
 14723  *
       
 14724  * ```js
       
 14725  *   var myModule = angular.module(...);
       
 14726  *
       
 14727  *   myModule.directive('directiveName', function factory(injectables) {
       
 14728  *     var directiveDefinitionObject = {
       
 14729  *       link: function postLink(scope, iElement, iAttrs) { ... }
       
 14730  *     };
       
 14731  *     return directiveDefinitionObject;
       
 14732  *     // or
       
 14733  *     // return function postLink(scope, iElement, iAttrs) { ... }
       
 14734  *   });
       
 14735  * ```
       
 14736  *
       
 14737  *
       
 14738  *
       
 14739  * ### Directive Definition Object
       
 14740  *
       
 14741  * The directive definition object provides instructions to the {@link ng.$compile
       
 14742  * compiler}. The attributes are:
       
 14743  *
       
 14744  * #### `multiElement`
       
 14745  * When this property is set to true, the HTML compiler will collect DOM nodes between
       
 14746  * nodes with the attributes `directive-name-start` and `directive-name-end`, and group them
       
 14747  * together as the directive elements. It is recomended that this feature be used on directives
       
 14748  * which are not strictly behavioural (such as {@link api/ng.directive:ngClick ngClick}), and which
       
 14749  * do not manipulate or replace child nodes (such as {@link api/ng.directive:ngInclude ngInclude}).
       
 14750  *
       
 14751  * #### `priority`
       
 14752  * When there are multiple directives defined on a single DOM element, sometimes it
       
 14753  * is necessary to specify the order in which the directives are applied. The `priority` is used
       
 14754  * to sort the directives before their `compile` functions get called. Priority is defined as a
       
 14755  * number. Directives with greater numerical `priority` are compiled first. Pre-link functions
       
 14756  * are also run in priority order, but post-link functions are run in reverse order. The order
       
 14757  * of directives with the same priority is undefined. The default priority is `0`.
       
 14758  *
       
 14759  * #### `terminal`
       
 14760  * If set to true then the current `priority` will be the last set of directives
       
 14761  * which will execute (any directives at the current priority will still execute
       
 14762  * as the order of execution on same `priority` is undefined).
       
 14763  *
       
 14764  * #### `scope`
       
 14765  * **If set to `true`,** then a new scope will be created for this directive. If multiple directives on the
       
 14766  * same element request a new scope, only one new scope is created. The new scope rule does not
       
 14767  * apply for the root of the template since the root of the template always gets a new scope.
       
 14768  *
       
 14769  * **If set to `{}` (object hash),** then a new "isolate" scope is created. The 'isolate' scope differs from
       
 14770  * normal scope in that it does not prototypically inherit from the parent scope. This is useful
       
 14771  * when creating reusable components, which should not accidentally read or modify data in the
       
 14772  * parent scope.
       
 14773  *
       
 14774  * The 'isolate' scope takes an object hash which defines a set of local scope properties
       
 14775  * derived from the parent scope. These local properties are useful for aliasing values for
       
 14776  * templates. Locals definition is a hash of local scope property to its source:
       
 14777  *
       
 14778  * * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is
       
 14779  *   always a string since DOM attributes are strings. If no `attr` name is specified  then the
       
 14780  *   attribute name is assumed to be the same as the local name.
       
 14781  *   Given `<widget my-attr="hello {{name}}">` and widget definition
       
 14782  *   of `scope: { localName:'@myAttr' }`, then widget scope property `localName` will reflect
       
 14783  *   the interpolated value of `hello {{name}}`. As the `name` attribute changes so will the
       
 14784  *   `localName` property on the widget scope. The `name` is read from the parent scope (not
       
 14785  *   component scope).
       
 14786  *
       
 14787  * * `=` or `=attr` - set up bi-directional binding between a local scope property and the
       
 14788  *   parent scope property of name defined via the value of the `attr` attribute. If no `attr`
       
 14789  *   name is specified then the attribute name is assumed to be the same as the local name.
       
 14790  *   Given `<widget my-attr="parentModel">` and widget definition of
       
 14791  *   `scope: { localModel:'=myAttr' }`, then widget scope property `localModel` will reflect the
       
 14792  *   value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected
       
 14793  *   in `localModel` and any changes in `localModel` will reflect in `parentModel`. If the parent
       
 14794  *   scope property doesn't exist, it will throw a NON_ASSIGNABLE_MODEL_EXPRESSION exception. You
       
 14795  *   can avoid this behavior using `=?` or `=?attr` in order to flag the property as optional.
       
 14796  *
       
 14797  * * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope.
       
 14798  *   If no `attr` name is specified then the attribute name is assumed to be the same as the
       
 14799  *   local name. Given `<widget my-attr="count = count + value">` and widget definition of
       
 14800  *   `scope: { localFn:'&myAttr' }`, then isolate scope property `localFn` will point to
       
 14801  *   a function wrapper for the `count = count + value` expression. Often it's desirable to
       
 14802  *   pass data from the isolated scope via an expression to the parent scope, this can be
       
 14803  *   done by passing a map of local variable names and values into the expression wrapper fn.
       
 14804  *   For example, if the expression is `increment(amount)` then we can specify the amount value
       
 14805  *   by calling the `localFn` as `localFn({amount: 22})`.
       
 14806  *
       
 14807  *
       
 14808  * #### `bindToController`
       
 14809  * When an isolate scope is used for a component (see above), and `controllerAs` is used, `bindToController` will
       
 14810  * allow a component to have its properties bound to the controller, rather than to scope. When the controller
       
 14811  * is instantiated, the initial values of the isolate scope bindings are already available.
       
 14812  *
       
 14813  * #### `controller`
       
 14814  * Controller constructor function. The controller is instantiated before the
       
 14815  * pre-linking phase and it is shared with other directives (see
       
 14816  * `require` attribute). This allows the directives to communicate with each other and augment
       
 14817  * each other's behavior. The controller is injectable (and supports bracket notation) with the following locals:
       
 14818  *
       
 14819  * * `$scope` - Current scope associated with the element
       
 14820  * * `$element` - Current element
       
 14821  * * `$attrs` - Current attributes object for the element
       
 14822  * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope:
       
 14823  *   `function([scope], cloneLinkingFn, futureParentElement)`.
       
 14824  *    * `scope`: optional argument to override the scope.
       
 14825  *    * `cloneLinkingFn`: optional argument to create clones of the original transcluded content.
       
 14826  *    * `futureParentElement`:
       
 14827  *        * defines the parent to which the `cloneLinkingFn` will add the cloned elements.
       
 14828  *        * default: `$element.parent()` resp. `$element` for `transclude:'element'` resp. `transclude:true`.
       
 14829  *        * only needed for transcludes that are allowed to contain non html elements (e.g. SVG elements)
       
 14830  *          and when the `cloneLinkinFn` is passed,
       
 14831  *          as those elements need to created and cloned in a special way when they are defined outside their
       
 14832  *          usual containers (e.g. like `<svg>`).
       
 14833  *        * See also the `directive.templateNamespace` property.
       
 14834  *
       
 14835  *
       
 14836  * #### `require`
       
 14837  * Require another directive and inject its controller as the fourth argument to the linking function. The
       
 14838  * `require` takes a string name (or array of strings) of the directive(s) to pass in. If an array is used, the
       
 14839  * injected argument will be an array in corresponding order. If no such directive can be
       
 14840  * found, or if the directive does not have a controller, then an error is raised. The name can be prefixed with:
       
 14841  *
       
 14842  * * (no prefix) - Locate the required controller on the current element. Throw an error if not found.
       
 14843  * * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found.
       
 14844  * * `^` - Locate the required controller by searching the element and its parents. Throw an error if not found.
       
 14845  * * `^^` - Locate the required controller by searching the element's parents. Throw an error if not found.
       
 14846  * * `?^` - Attempt to locate the required controller by searching the element and its parents or pass
       
 14847  *   `null` to the `link` fn if not found.
       
 14848  * * `?^^` - Attempt to locate the required controller by searching the element's parents, or pass
       
 14849  *   `null` to the `link` fn if not found.
       
 14850  *
       
 14851  *
       
 14852  * #### `controllerAs`
       
 14853  * Controller alias at the directive scope. An alias for the controller so it
       
 14854  * can be referenced at the directive template. The directive needs to define a scope for this
       
 14855  * configuration to be used. Useful in the case when directive is used as component.
       
 14856  *
       
 14857  *
       
 14858  * #### `restrict`
       
 14859  * String of subset of `EACM` which restricts the directive to a specific directive
       
 14860  * declaration style. If omitted, the defaults (elements and attributes) are used.
       
 14861  *
       
 14862  * * `E` - Element name (default): `<my-directive></my-directive>`
       
 14863  * * `A` - Attribute (default): `<div my-directive="exp"></div>`
       
 14864  * * `C` - Class: `<div class="my-directive: exp;"></div>`
       
 14865  * * `M` - Comment: `<!-- directive: my-directive exp -->`
       
 14866  *
       
 14867  *
       
 14868  * #### `templateNamespace`
       
 14869  * String representing the document type used by the markup in the template.
       
 14870  * AngularJS needs this information as those elements need to be created and cloned
       
 14871  * in a special way when they are defined outside their usual containers like `<svg>` and `<math>`.
       
 14872  *
       
 14873  * * `html` - All root nodes in the template are HTML. Root nodes may also be
       
 14874  *   top-level elements such as `<svg>` or `<math>`.
       
 14875  * * `svg` - The root nodes in the template are SVG elements (excluding `<math>`).
       
 14876  * * `math` - The root nodes in the template are MathML elements (excluding `<svg>`).
       
 14877  *
       
 14878  * If no `templateNamespace` is specified, then the namespace is considered to be `html`.
       
 14879  *
       
 14880  * #### `template`
       
 14881  * HTML markup that may:
       
 14882  * * Replace the contents of the directive's element (default).
       
 14883  * * Replace the directive's element itself (if `replace` is true - DEPRECATED).
       
 14884  * * Wrap the contents of the directive's element (if `transclude` is true).
       
 14885  *
       
 14886  * Value may be:
       
 14887  *
       
 14888  * * A string. For example `<div red-on-hover>{{delete_str}}</div>`.
       
 14889  * * A function which takes two arguments `tElement` and `tAttrs` (described in the `compile`
       
 14890  *   function api below) and returns a string value.
       
 14891  *
       
 14892  *
       
 14893  * #### `templateUrl`
       
 14894  * This is similar to `template` but the template is loaded from the specified URL, asynchronously.
       
 14895  *
       
 14896  * Because template loading is asynchronous the compiler will suspend compilation of directives on that element
       
 14897  * for later when the template has been resolved.  In the meantime it will continue to compile and link
       
 14898  * sibling and parent elements as though this element had not contained any directives.
       
 14899  *
       
 14900  * The compiler does not suspend the entire compilation to wait for templates to be loaded because this
       
 14901  * would result in the whole app "stalling" until all templates are loaded asynchronously - even in the
       
 14902  * case when only one deeply nested directive has `templateUrl`.
       
 14903  *
       
 14904  * Template loading is asynchronous even if the template has been preloaded into the {@link $templateCache}
       
 14905  *
       
 14906  * You can specify `templateUrl` as a string representing the URL or as a function which takes two
       
 14907  * arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns
       
 14908  * a string value representing the url.  In either case, the template URL is passed through {@link
       
 14909  * api/ng.$sce#getTrustedResourceUrl $sce.getTrustedResourceUrl}.
       
 14910  *
       
 14911  *
       
 14912  * #### `replace` ([*DEPRECATED*!], will be removed in next major release - i.e. v2.0)
       
 14913  * specify what the template should replace. Defaults to `false`.
       
 14914  *
       
 14915  * * `true` - the template will replace the directive's element.
       
 14916  * * `false` - the template will replace the contents of the directive's element.
       
 14917  *
       
 14918  * The replacement process migrates all of the attributes / classes from the old element to the new
       
 14919  * one. See the {@link guide/directive#creating-custom-directives_creating-directives_template-expanding-directive
       
 14920  * Directives Guide} for an example.
       
 14921  *
       
 14922  * There are very few scenarios where element replacement is required for the application function,
       
 14923  * the main one being reusable custom components that are used within SVG contexts
       
 14924  * (because SVG doesn't work with custom elements in the DOM tree).
       
 14925  *
       
 14926  * #### `transclude`
       
 14927  * Extract the contents of the element where the directive appears and make it available to the directive.
       
 14928  * The contents are compiled and provided to the directive as a **transclusion function**. See the
       
 14929  * {@link $compile#transclusion Transclusion} section below.
       
 14930  *
       
 14931  * There are two kinds of transclusion depending upon whether you want to transclude just the contents of the
       
 14932  * directive's element or the entire element:
       
 14933  *
       
 14934  * * `true` - transclude the content (i.e. the child nodes) of the directive's element.
       
 14935  * * `'element'` - transclude the whole of the directive's element including any directives on this
       
 14936  *   element that defined at a lower priority than this directive. When used, the `template`
       
 14937  *   property is ignored.
       
 14938  *
       
 14939  *
       
 14940  * #### `compile`
       
 14941  *
       
 14942  * ```js
       
 14943  *   function compile(tElement, tAttrs, transclude) { ... }
       
 14944  * ```
       
 14945  *
       
 14946  * The compile function deals with transforming the template DOM. Since most directives do not do
       
 14947  * template transformation, it is not used often. The compile function takes the following arguments:
       
 14948  *
       
 14949  *   * `tElement` - template element - The element where the directive has been declared. It is
       
 14950  *     safe to do template transformation on the element and child elements only.
       
 14951  *
       
 14952  *   * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared
       
 14953  *     between all directive compile functions.
       
 14954  *
       
 14955  *   * `transclude` -  [*DEPRECATED*!] A transclude linking function: `function(scope, cloneLinkingFn)`
       
 14956  *
       
 14957  * <div class="alert alert-warning">
       
 14958  * **Note:** The template instance and the link instance may be different objects if the template has
       
 14959  * been cloned. For this reason it is **not** safe to do anything other than DOM transformations that
       
 14960  * apply to all cloned DOM nodes within the compile function. Specifically, DOM listener registration
       
 14961  * should be done in a linking function rather than in a compile function.
       
 14962  * </div>
       
 14963 
       
 14964  * <div class="alert alert-warning">
       
 14965  * **Note:** The compile function cannot handle directives that recursively use themselves in their
       
 14966  * own templates or compile functions. Compiling these directives results in an infinite loop and a
       
 14967  * stack overflow errors.
       
 14968  *
       
 14969  * This can be avoided by manually using $compile in the postLink function to imperatively compile
       
 14970  * a directive's template instead of relying on automatic template compilation via `template` or
       
 14971  * `templateUrl` declaration or manual compilation inside the compile function.
       
 14972  * </div>
       
 14973  *
       
 14974  * <div class="alert alert-error">
       
 14975  * **Note:** The `transclude` function that is passed to the compile function is deprecated, as it
       
 14976  *   e.g. does not know about the right outer scope. Please use the transclude function that is passed
       
 14977  *   to the link function instead.
       
 14978  * </div>
       
 14979 
       
 14980  * A compile function can have a return value which can be either a function or an object.
       
 14981  *
       
 14982  * * returning a (post-link) function - is equivalent to registering the linking function via the
       
 14983  *   `link` property of the config object when the compile function is empty.
       
 14984  *
       
 14985  * * returning an object with function(s) registered via `pre` and `post` properties - allows you to
       
 14986  *   control when a linking function should be called during the linking phase. See info about
       
 14987  *   pre-linking and post-linking functions below.
       
 14988  *
       
 14989  *
       
 14990  * #### `link`
       
 14991  * This property is used only if the `compile` property is not defined.
       
 14992  *
       
 14993  * ```js
       
 14994  *   function link(scope, iElement, iAttrs, controller, transcludeFn) { ... }
       
 14995  * ```
       
 14996  *
       
 14997  * The link function is responsible for registering DOM listeners as well as updating the DOM. It is
       
 14998  * executed after the template has been cloned. This is where most of the directive logic will be
       
 14999  * put.
       
 15000  *
       
 15001  *   * `scope` - {@link ng.$rootScope.Scope Scope} - The scope to be used by the
       
 15002  *     directive for registering {@link ng.$rootScope.Scope#$watch watches}.
       
 15003  *
       
 15004  *   * `iElement` - instance element - The element where the directive is to be used. It is safe to
       
 15005  *     manipulate the children of the element only in `postLink` function since the children have
       
 15006  *     already been linked.
       
 15007  *
       
 15008  *   * `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared
       
 15009  *     between all directive linking functions.
       
 15010  *
       
 15011  *   * `controller` - a controller instance - A controller instance if at least one directive on the
       
 15012  *     element defines a controller. The controller is shared among all the directives, which allows
       
 15013  *     the directives to use the controllers as a communication channel.
       
 15014  *
       
 15015  *   * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope.
       
 15016  *     This is the same as the `$transclude`
       
 15017  *     parameter of directive controllers, see there for details.
       
 15018  *     `function([scope], cloneLinkingFn, futureParentElement)`.
       
 15019  *
       
 15020  * #### Pre-linking function
       
 15021  *
       
 15022  * Executed before the child elements are linked. Not safe to do DOM transformation since the
       
 15023  * compiler linking function will fail to locate the correct elements for linking.
       
 15024  *
       
 15025  * #### Post-linking function
       
 15026  *
       
 15027  * Executed after the child elements are linked.
       
 15028  *
       
 15029  * Note that child elements that contain `templateUrl` directives will not have been compiled
       
 15030  * and linked since they are waiting for their template to load asynchronously and their own
       
 15031  * compilation and linking has been suspended until that occurs.
       
 15032  *
       
 15033  * It is safe to do DOM transformation in the post-linking function on elements that are not waiting
       
 15034  * for their async templates to be resolved.
       
 15035  *
       
 15036  *
       
 15037  * ### Transclusion
       
 15038  *
       
 15039  * Transclusion is the process of extracting a collection of DOM element from one part of the DOM and
       
 15040  * copying them to another part of the DOM, while maintaining their connection to the original AngularJS
       
 15041  * scope from where they were taken.
       
 15042  *
       
 15043  * Transclusion is used (often with {@link ngTransclude}) to insert the
       
 15044  * original contents of a directive's element into a specified place in the template of the directive.
       
 15045  * The benefit of transclusion, over simply moving the DOM elements manually, is that the transcluded
       
 15046  * content has access to the properties on the scope from which it was taken, even if the directive
       
 15047  * has isolated scope.
       
 15048  * See the {@link guide/directive#creating-a-directive-that-wraps-other-elements Directives Guide}.
       
 15049  *
       
 15050  * This makes it possible for the widget to have private state for its template, while the transcluded
       
 15051  * content has access to its originating scope.
       
 15052  *
       
 15053  * <div class="alert alert-warning">
       
 15054  * **Note:** When testing an element transclude directive you must not place the directive at the root of the
       
 15055  * DOM fragment that is being compiled. See {@link guide/unit-testing#testing-transclusion-directives
       
 15056  * Testing Transclusion Directives}.
       
 15057  * </div>
       
 15058  *
       
 15059  * #### Transclusion Functions
       
 15060  *
       
 15061  * When a directive requests transclusion, the compiler extracts its contents and provides a **transclusion
       
 15062  * function** to the directive's `link` function and `controller`. This transclusion function is a special
       
 15063  * **linking function** that will return the compiled contents linked to a new transclusion scope.
       
 15064  *
       
 15065  * <div class="alert alert-info">
       
 15066  * If you are just using {@link ngTransclude} then you don't need to worry about this function, since
       
 15067  * ngTransclude will deal with it for us.
       
 15068  * </div>
       
 15069  *
       
 15070  * If you want to manually control the insertion and removal of the transcluded content in your directive
       
 15071  * then you must use this transclude function. When you call a transclude function it returns a a jqLite/JQuery
       
 15072  * object that contains the compiled DOM, which is linked to the correct transclusion scope.
       
 15073  *
       
 15074  * When you call a transclusion function you can pass in a **clone attach function**. This function is accepts
       
 15075  * two parameters, `function(clone, scope) { ... }`, where the `clone` is a fresh compiled copy of your transcluded
       
 15076  * content and the `scope` is the newly created transclusion scope, to which the clone is bound.
       
 15077  *
       
 15078  * <div class="alert alert-info">
       
 15079  * **Best Practice**: Always provide a `cloneFn` (clone attach function) when you call a translude function
       
 15080  * since you then get a fresh clone of the original DOM and also have access to the new transclusion scope.
       
 15081  * </div>
       
 15082  *
       
 15083  * It is normal practice to attach your transcluded content (`clone`) to the DOM inside your **clone
       
 15084  * attach function**:
       
 15085  *
       
 15086  * ```js
       
 15087  * var transcludedContent, transclusionScope;
       
 15088  *
       
 15089  * $transclude(function(clone, scope) {
       
 15090  *   element.append(clone);
       
 15091  *   transcludedContent = clone;
       
 15092  *   transclusionScope = scope;
       
 15093  * });
       
 15094  * ```
       
 15095  *
       
 15096  * Later, if you want to remove the transcluded content from your DOM then you should also destroy the
       
 15097  * associated transclusion scope:
       
 15098  *
       
 15099  * ```js
       
 15100  * transcludedContent.remove();
       
 15101  * transclusionScope.$destroy();
       
 15102  * ```
       
 15103  *
       
 15104  * <div class="alert alert-info">
       
 15105  * **Best Practice**: if you intend to add and remove transcluded content manually in your directive
       
 15106  * (by calling the transclude function to get the DOM and and calling `element.remove()` to remove it),
       
 15107  * then you are also responsible for calling `$destroy` on the transclusion scope.
       
 15108  * </div>
       
 15109  *
       
 15110  * The built-in DOM manipulation directives, such as {@link ngIf}, {@link ngSwitch} and {@link ngRepeat}
       
 15111  * automatically destroy their transluded clones as necessary so you do not need to worry about this if
       
 15112  * you are simply using {@link ngTransclude} to inject the transclusion into your directive.
       
 15113  *
       
 15114  *
       
 15115  * #### Transclusion Scopes
       
 15116  *
       
 15117  * When you call a transclude function it returns a DOM fragment that is pre-bound to a **transclusion
       
 15118  * scope**. This scope is special, in that it is a child of the directive's scope (and so gets destroyed
       
 15119  * when the directive's scope gets destroyed) but it inherits the properties of the scope from which it
       
 15120  * was taken.
       
 15121  *
       
 15122  * For example consider a directive that uses transclusion and isolated scope. The DOM hierarchy might look
       
 15123  * like this:
       
 15124  *
       
 15125  * ```html
       
 15126  * <div ng-app>
       
 15127  *   <div isolate>
       
 15128  *     <div transclusion>
       
 15129  *     </div>
       
 15130  *   </div>
       
 15131  * </div>
       
 15132  * ```
       
 15133  *
       
 15134  * The `$parent` scope hierarchy will look like this:
       
 15135  *
       
 15136  * ```
       
 15137  * - $rootScope
       
 15138  *   - isolate
       
 15139  *     - transclusion
       
 15140  * ```
       
 15141  *
       
 15142  * but the scopes will inherit prototypically from different scopes to their `$parent`.
       
 15143  *
       
 15144  * ```
       
 15145  * - $rootScope
       
 15146  *   - transclusion
       
 15147  * - isolate
       
 15148  * ```
       
 15149  *
       
 15150  *
       
 15151  * ### Attributes
       
 15152  *
       
 15153  * The {@link ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the
       
 15154  * `link()` or `compile()` functions. It has a variety of uses.
       
 15155  *
       
 15156  * accessing *Normalized attribute names:*
       
 15157  * Directives like 'ngBind' can be expressed in many ways: 'ng:bind', `data-ng-bind`, or 'x-ng-bind'.
       
 15158  * the attributes object allows for normalized access to
       
 15159  *   the attributes.
       
 15160  *
       
 15161  * * *Directive inter-communication:* All directives share the same instance of the attributes
       
 15162  *   object which allows the directives to use the attributes object as inter directive
       
 15163  *   communication.
       
 15164  *
       
 15165  * * *Supports interpolation:* Interpolation attributes are assigned to the attribute object
       
 15166  *   allowing other directives to read the interpolated value.
       
 15167  *
       
 15168  * * *Observing interpolated attributes:* Use `$observe` to observe the value changes of attributes
       
 15169  *   that contain interpolation (e.g. `src="{{bar}}"`). Not only is this very efficient but it's also
       
 15170  *   the only way to easily get the actual value because during the linking phase the interpolation
       
 15171  *   hasn't been evaluated yet and so the value is at this time set to `undefined`.
       
 15172  *
       
 15173  * ```js
       
 15174  * function linkingFn(scope, elm, attrs, ctrl) {
       
 15175  *   // get the attribute value
       
 15176  *   console.log(attrs.ngModel);
       
 15177  *
       
 15178  *   // change the attribute
       
 15179  *   attrs.$set('ngModel', 'new value');
       
 15180  *
       
 15181  *   // observe changes to interpolated attribute
       
 15182  *   attrs.$observe('ngModel', function(value) {
       
 15183  *     console.log('ngModel has changed value to ' + value);
       
 15184  *   });
       
 15185  * }
       
 15186  * ```
       
 15187  *
       
 15188  * ## Example
       
 15189  *
       
 15190  * <div class="alert alert-warning">
       
 15191  * **Note**: Typically directives are registered with `module.directive`. The example below is
       
 15192  * to illustrate how `$compile` works.
       
 15193  * </div>
       
 15194  *
       
 15195  <example module="compileExample">
       
 15196    <file name="index.html">
       
 15197     <script>
       
 15198       angular.module('compileExample', [], function($compileProvider) {
       
 15199         // configure new 'compile' directive by passing a directive
       
 15200         // factory function. The factory function injects the '$compile'
       
 15201         $compileProvider.directive('compile', function($compile) {
       
 15202           // directive factory creates a link function
       
 15203           return function(scope, element, attrs) {
       
 15204             scope.$watch(
       
 15205               function(scope) {
       
 15206                  // watch the 'compile' expression for changes
       
 15207                 return scope.$eval(attrs.compile);
       
 15208               },
       
 15209               function(value) {
       
 15210                 // when the 'compile' expression changes
       
 15211                 // assign it into the current DOM
       
 15212                 element.html(value);
       
 15213 
       
 15214                 // compile the new DOM and link it to the current
       
 15215                 // scope.
       
 15216                 // NOTE: we only compile .childNodes so that
       
 15217                 // we don't get into infinite loop compiling ourselves
       
 15218                 $compile(element.contents())(scope);
       
 15219               }
       
 15220             );
       
 15221           };
       
 15222         });
       
 15223       })
       
 15224       .controller('GreeterController', ['$scope', function($scope) {
       
 15225         $scope.name = 'Angular';
       
 15226         $scope.html = 'Hello {{name}}';
       
 15227       }]);
       
 15228     </script>
       
 15229     <div ng-controller="GreeterController">
       
 15230       <input ng-model="name"> <br>
       
 15231       <textarea ng-model="html"></textarea> <br>
       
 15232       <div compile="html"></div>
       
 15233     </div>
       
 15234    </file>
       
 15235    <file name="protractor.js" type="protractor">
       
 15236      it('should auto compile', function() {
       
 15237        var textarea = $('textarea');
       
 15238        var output = $('div[compile]');
       
 15239        // The initial state reads 'Hello Angular'.
       
 15240        expect(output.getText()).toBe('Hello Angular');
       
 15241        textarea.clear();
       
 15242        textarea.sendKeys('{{name}}!');
       
 15243        expect(output.getText()).toBe('Angular!');
       
 15244      });
       
 15245    </file>
       
 15246  </example>
       
 15247 
       
 15248  *
       
 15249  *
       
 15250  * @param {string|DOMElement} element Element or HTML string to compile into a template function.
       
 15251  * @param {function(angular.Scope, cloneAttachFn=)} transclude function available to directives.
       
 15252  * @param {number} maxPriority only apply directives lower than given priority (Only effects the
       
 15253  *                 root element(s), not their children)
       
 15254  * @returns {function(scope, cloneAttachFn=)} a link function which is used to bind template
       
 15255  * (a DOM element/tree) to a scope. Where:
       
 15256  *
       
 15257  *  * `scope` - A {@link ng.$rootScope.Scope Scope} to bind to.
       
 15258  *  * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the
       
 15259  *  `template` and call the `cloneAttachFn` function allowing the caller to attach the
       
 15260  *  cloned elements to the DOM document at the appropriate place. The `cloneAttachFn` is
       
 15261  *  called as: <br> `cloneAttachFn(clonedElement, scope)` where:
       
 15262  *
       
 15263  *      * `clonedElement` - is a clone of the original `element` passed into the compiler.
       
 15264  *      * `scope` - is the current scope with which the linking function is working with.
       
 15265  *
       
 15266  * Calling the linking function returns the element of the template. It is either the original
       
 15267  * element passed in, or the clone of the element if the `cloneAttachFn` is provided.
       
 15268  *
       
 15269  * After linking the view is not updated until after a call to $digest which typically is done by
       
 15270  * Angular automatically.
       
 15271  *
       
 15272  * If you need access to the bound view, there are two ways to do it:
       
 15273  *
       
 15274  * - If you are not asking the linking function to clone the template, create the DOM element(s)
       
 15275  *   before you send them to the compiler and keep this reference around.
       
 15276  *   ```js
       
 15277  *     var element = $compile('<p>{{total}}</p>')(scope);
       
 15278  *   ```
       
 15279  *
       
 15280  * - if on the other hand, you need the element to be cloned, the view reference from the original
       
 15281  *   example would not point to the clone, but rather to the original template that was cloned. In
       
 15282  *   this case, you can access the clone via the cloneAttachFn:
       
 15283  *   ```js
       
 15284  *     var templateElement = angular.element('<p>{{total}}</p>'),
       
 15285  *         scope = ....;
       
 15286  *
       
 15287  *     var clonedElement = $compile(templateElement)(scope, function(clonedElement, scope) {
       
 15288  *       //attach the clone to DOM document at the right place
       
 15289  *     });
       
 15290  *
       
 15291  *     //now we have reference to the cloned DOM via `clonedElement`
       
 15292  *   ```
       
 15293  *
       
 15294  *
       
 15295  * For information on how the compiler works, see the
       
 15296  * {@link guide/compiler Angular HTML Compiler} section of the Developer Guide.
       
 15297  */
       
 15298 
       
 15299 var $compileMinErr = minErr('$compile');
       
 15300 
       
 15301 /**
       
 15302  * @ngdoc provider
       
 15303  * @name $compileProvider
       
 15304  *
       
 15305  * @description
       
 15306  */
       
 15307 $CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider'];
       
 15308 function $CompileProvider($provide, $$sanitizeUriProvider) {
       
 15309   var hasDirectives = {},
       
 15310       Suffix = 'Directive',
       
 15311       COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w_\-]+)\s+(.*)$/,
       
 15312       CLASS_DIRECTIVE_REGEXP = /(([\d\w_\-]+)(?:\:([^;]+))?;?)/,
       
 15313       ALL_OR_NOTHING_ATTRS = makeMap('ngSrc,ngSrcset,src,srcset'),
       
 15314       REQUIRE_PREFIX_REGEXP = /^(?:(\^\^?)?(\?)?(\^\^?)?)?/;
       
 15315 
       
 15316   // Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
       
 15317   // The assumption is that future DOM event attribute names will begin with
       
 15318   // 'on' and be composed of only English letters.
       
 15319   var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/;
       
 15320 
       
 15321   function parseIsolateBindings(scope, directiveName) {
       
 15322     var LOCAL_REGEXP = /^\s*([@=&])(\??)\s*(\w*)\s*$/;
       
 15323 
       
 15324     var bindings = {};
       
 15325 
       
 15326     forEach(scope, function(definition, scopeName) {
       
 15327       var match = definition.match(LOCAL_REGEXP);
       
 15328 
       
 15329       if (!match) {
       
 15330         throw $compileMinErr('iscp',
       
 15331             "Invalid isolate scope definition for directive '{0}'." +
       
 15332             " Definition: {... {1}: '{2}' ...}",
       
 15333             directiveName, scopeName, definition);
       
 15334       }
       
 15335 
       
 15336       bindings[scopeName] = {
       
 15337         attrName: match[3] || scopeName,
       
 15338         mode: match[1],
       
 15339         optional: match[2] === '?'
       
 15340       };
       
 15341     });
       
 15342 
       
 15343     return bindings;
       
 15344   }
       
 15345 
       
 15346   /**
       
 15347    * @ngdoc method
       
 15348    * @name $compileProvider#directive
       
 15349    * @kind function
       
 15350    *
       
 15351    * @description
       
 15352    * Register a new directive with the compiler.
       
 15353    *
       
 15354    * @param {string|Object} name Name of the directive in camel-case (i.e. <code>ngBind</code> which
       
 15355    *    will match as <code>ng-bind</code>), or an object map of directives where the keys are the
       
 15356    *    names and the values are the factories.
       
 15357    * @param {Function|Array} directiveFactory An injectable directive factory function. See
       
 15358    *    {@link guide/directive} for more info.
       
 15359    * @returns {ng.$compileProvider} Self for chaining.
       
 15360    */
       
 15361    this.directive = function registerDirective(name, directiveFactory) {
       
 15362     assertNotHasOwnProperty(name, 'directive');
       
 15363     if (isString(name)) {
       
 15364       assertArg(directiveFactory, 'directiveFactory');
       
 15365       if (!hasDirectives.hasOwnProperty(name)) {
       
 15366         hasDirectives[name] = [];
       
 15367         $provide.factory(name + Suffix, ['$injector', '$exceptionHandler',
       
 15368           function($injector, $exceptionHandler) {
       
 15369             var directives = [];
       
 15370             forEach(hasDirectives[name], function(directiveFactory, index) {
       
 15371               try {
       
 15372                 var directive = $injector.invoke(directiveFactory);
       
 15373                 if (isFunction(directive)) {
       
 15374                   directive = { compile: valueFn(directive) };
       
 15375                 } else if (!directive.compile && directive.link) {
       
 15376                   directive.compile = valueFn(directive.link);
       
 15377                 }
       
 15378                 directive.priority = directive.priority || 0;
       
 15379                 directive.index = index;
       
 15380                 directive.name = directive.name || name;
       
 15381                 directive.require = directive.require || (directive.controller && directive.name);
       
 15382                 directive.restrict = directive.restrict || 'EA';
       
 15383                 if (isObject(directive.scope)) {
       
 15384                   directive.$$isolateBindings = parseIsolateBindings(directive.scope, directive.name);
       
 15385                 }
       
 15386                 directives.push(directive);
       
 15387               } catch (e) {
       
 15388                 $exceptionHandler(e);
       
 15389               }
       
 15390             });
       
 15391             return directives;
       
 15392           }]);
       
 15393       }
       
 15394       hasDirectives[name].push(directiveFactory);
       
 15395     } else {
       
 15396       forEach(name, reverseParams(registerDirective));
       
 15397     }
       
 15398     return this;
       
 15399   };
       
 15400 
       
 15401 
       
 15402   /**
       
 15403    * @ngdoc method
       
 15404    * @name $compileProvider#aHrefSanitizationWhitelist
       
 15405    * @kind function
       
 15406    *
       
 15407    * @description
       
 15408    * Retrieves or overrides the default regular expression that is used for whitelisting of safe
       
 15409    * urls during a[href] sanitization.
       
 15410    *
       
 15411    * The sanitization is a security measure aimed at prevent XSS attacks via html links.
       
 15412    *
       
 15413    * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
       
 15414    * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
       
 15415    * regular expression. If a match is found, the original url is written into the dom. Otherwise,
       
 15416    * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
       
 15417    *
       
 15418    * @param {RegExp=} regexp New regexp to whitelist urls with.
       
 15419    * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
       
 15420    *    chaining otherwise.
       
 15421    */
       
 15422   this.aHrefSanitizationWhitelist = function(regexp) {
       
 15423     if (isDefined(regexp)) {
       
 15424       $$sanitizeUriProvider.aHrefSanitizationWhitelist(regexp);
       
 15425       return this;
       
 15426     } else {
       
 15427       return $$sanitizeUriProvider.aHrefSanitizationWhitelist();
       
 15428     }
       
 15429   };
       
 15430 
       
 15431 
       
 15432   /**
       
 15433    * @ngdoc method
       
 15434    * @name $compileProvider#imgSrcSanitizationWhitelist
       
 15435    * @kind function
       
 15436    *
       
 15437    * @description
       
 15438    * Retrieves or overrides the default regular expression that is used for whitelisting of safe
       
 15439    * urls during img[src] sanitization.
       
 15440    *
       
 15441    * The sanitization is a security measure aimed at prevent XSS attacks via html links.
       
 15442    *
       
 15443    * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
       
 15444    * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
       
 15445    * regular expression. If a match is found, the original url is written into the dom. Otherwise,
       
 15446    * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
       
 15447    *
       
 15448    * @param {RegExp=} regexp New regexp to whitelist urls with.
       
 15449    * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
       
 15450    *    chaining otherwise.
       
 15451    */
       
 15452   this.imgSrcSanitizationWhitelist = function(regexp) {
       
 15453     if (isDefined(regexp)) {
       
 15454       $$sanitizeUriProvider.imgSrcSanitizationWhitelist(regexp);
       
 15455       return this;
       
 15456     } else {
       
 15457       return $$sanitizeUriProvider.imgSrcSanitizationWhitelist();
       
 15458     }
       
 15459   };
       
 15460 
       
 15461   /**
       
 15462    * @ngdoc method
       
 15463    * @name  $compileProvider#debugInfoEnabled
       
 15464    *
       
 15465    * @param {boolean=} enabled update the debugInfoEnabled state if provided, otherwise just return the
       
 15466    * current debugInfoEnabled state
       
 15467    * @returns {*} current value if used as getter or itself (chaining) if used as setter
       
 15468    *
       
 15469    * @kind function
       
 15470    *
       
 15471    * @description
       
 15472    * Call this method to enable/disable various debug runtime information in the compiler such as adding
       
 15473    * binding information and a reference to the current scope on to DOM elements.
       
 15474    * If enabled, the compiler will add the following to DOM elements that have been bound to the scope
       
 15475    * * `ng-binding` CSS class
       
 15476    * * `$binding` data property containing an array of the binding expressions
       
 15477    *
       
 15478    * You may want to use this in production for a significant performance boost. See
       
 15479    * {@link guide/production#disabling-debug-data Disabling Debug Data} for more.
       
 15480    *
       
 15481    * The default value is true.
       
 15482    */
       
 15483   var debugInfoEnabled = true;
       
 15484   this.debugInfoEnabled = function(enabled) {
       
 15485     if(isDefined(enabled)) {
       
 15486       debugInfoEnabled = enabled;
       
 15487       return this;
       
 15488     }
       
 15489     return debugInfoEnabled;
       
 15490   };
       
 15491 
       
 15492   this.$get = [
       
 15493             '$injector', '$interpolate', '$exceptionHandler', '$templateRequest', '$parse',
       
 15494             '$controller', '$rootScope', '$document', '$sce', '$animate', '$$sanitizeUri',
       
 15495     function($injector,   $interpolate,   $exceptionHandler,   $templateRequest,   $parse,
       
 15496              $controller,   $rootScope,   $document,   $sce,   $animate,   $$sanitizeUri) {
       
 15497 
       
 15498     var Attributes = function(element, attributesToCopy) {
       
 15499       if (attributesToCopy) {
       
 15500         var keys = Object.keys(attributesToCopy);
       
 15501         var i, l, key;
       
 15502 
       
 15503         for (i = 0, l = keys.length; i < l; i++) {
       
 15504           key = keys[i];
       
 15505           this[key] = attributesToCopy[key];
       
 15506         }
       
 15507       } else {
       
 15508         this.$attr = {};
       
 15509       }
       
 15510 
       
 15511       this.$$element = element;
       
 15512     };
       
 15513 
       
 15514     Attributes.prototype = {
       
 15515       $normalize: directiveNormalize,
       
 15516 
       
 15517 
       
 15518       /**
       
 15519        * @ngdoc method
       
 15520        * @name $compile.directive.Attributes#$addClass
       
 15521        * @kind function
       
 15522        *
       
 15523        * @description
       
 15524        * Adds the CSS class value specified by the classVal parameter to the element. If animations
       
 15525        * are enabled then an animation will be triggered for the class addition.
       
 15526        *
       
 15527        * @param {string} classVal The className value that will be added to the element
       
 15528        */
       
 15529       $addClass : function(classVal) {
       
 15530         if(classVal && classVal.length > 0) {
       
 15531           $animate.addClass(this.$$element, classVal);
       
 15532         }
       
 15533       },
       
 15534 
       
 15535       /**
       
 15536        * @ngdoc method
       
 15537        * @name $compile.directive.Attributes#$removeClass
       
 15538        * @kind function
       
 15539        *
       
 15540        * @description
       
 15541        * Removes the CSS class value specified by the classVal parameter from the element. If
       
 15542        * animations are enabled then an animation will be triggered for the class removal.
       
 15543        *
       
 15544        * @param {string} classVal The className value that will be removed from the element
       
 15545        */
       
 15546       $removeClass : function(classVal) {
       
 15547         if(classVal && classVal.length > 0) {
       
 15548           $animate.removeClass(this.$$element, classVal);
       
 15549         }
       
 15550       },
       
 15551 
       
 15552       /**
       
 15553        * @ngdoc method
       
 15554        * @name $compile.directive.Attributes#$updateClass
       
 15555        * @kind function
       
 15556        *
       
 15557        * @description
       
 15558        * Adds and removes the appropriate CSS class values to the element based on the difference
       
 15559        * between the new and old CSS class values (specified as newClasses and oldClasses).
       
 15560        *
       
 15561        * @param {string} newClasses The current CSS className value
       
 15562        * @param {string} oldClasses The former CSS className value
       
 15563        */
       
 15564       $updateClass : function(newClasses, oldClasses) {
       
 15565         var toAdd = tokenDifference(newClasses, oldClasses);
       
 15566         if (toAdd && toAdd.length) {
       
 15567           $animate.addClass(this.$$element, toAdd);
       
 15568         }
       
 15569 
       
 15570         var toRemove = tokenDifference(oldClasses, newClasses);
       
 15571         if (toRemove && toRemove.length) {
       
 15572           $animate.removeClass(this.$$element, toRemove);
       
 15573         }
       
 15574       },
       
 15575 
       
 15576       /**
       
 15577        * Set a normalized attribute on the element in a way such that all directives
       
 15578        * can share the attribute. This function properly handles boolean attributes.
       
 15579        * @param {string} key Normalized key. (ie ngAttribute)
       
 15580        * @param {string|boolean} value The value to set. If `null` attribute will be deleted.
       
 15581        * @param {boolean=} writeAttr If false, does not write the value to DOM element attribute.
       
 15582        *     Defaults to true.
       
 15583        * @param {string=} attrName Optional none normalized name. Defaults to key.
       
 15584        */
       
 15585       $set: function(key, value, writeAttr, attrName) {
       
 15586         // TODO: decide whether or not to throw an error if "class"
       
 15587         //is set through this function since it may cause $updateClass to
       
 15588         //become unstable.
       
 15589 
       
 15590         var node = this.$$element[0],
       
 15591             booleanKey = getBooleanAttrName(node, key),
       
 15592             aliasedKey = getAliasedAttrName(node, key),
       
 15593             observer = key,
       
 15594             normalizedVal,
       
 15595             nodeName;
       
 15596 
       
 15597         if (booleanKey) {
       
 15598           this.$$element.prop(key, value);
       
 15599           attrName = booleanKey;
       
 15600         } else if(aliasedKey) {
       
 15601           this[aliasedKey] = value;
       
 15602           observer = aliasedKey;
       
 15603         }
       
 15604 
       
 15605         this[key] = value;
       
 15606 
       
 15607         // translate normalized key to actual key
       
 15608         if (attrName) {
       
 15609           this.$attr[key] = attrName;
       
 15610         } else {
       
 15611           attrName = this.$attr[key];
       
 15612           if (!attrName) {
       
 15613             this.$attr[key] = attrName = snake_case(key, '-');
       
 15614           }
       
 15615         }
       
 15616 
       
 15617         nodeName = nodeName_(this.$$element);
       
 15618 
       
 15619         if ((nodeName === 'a' && key === 'href') ||
       
 15620             (nodeName === 'img' && key === 'src')) {
       
 15621           // sanitize a[href] and img[src] values
       
 15622           this[key] = value = $$sanitizeUri(value, key === 'src');
       
 15623         } else if (nodeName === 'img' && key === 'srcset') {
       
 15624           // sanitize img[srcset] values
       
 15625           var result = "";
       
 15626 
       
 15627           // first check if there are spaces because it's not the same pattern
       
 15628           var trimmedSrcset = trim(value);
       
 15629           //                (   999x   ,|   999w   ,|   ,|,   )
       
 15630           var srcPattern = /(\s+\d+x\s*,|\s+\d+w\s*,|\s+,|,\s+)/;
       
 15631           var pattern = /\s/.test(trimmedSrcset) ? srcPattern : /(,)/;
       
 15632 
       
 15633           // split srcset into tuple of uri and descriptor except for the last item
       
 15634           var rawUris = trimmedSrcset.split(pattern);
       
 15635 
       
 15636           // for each tuples
       
 15637           var nbrUrisWith2parts = Math.floor(rawUris.length / 2);
       
 15638           for (var i=0; i<nbrUrisWith2parts; i++) {
       
 15639             var innerIdx = i*2;
       
 15640             // sanitize the uri
       
 15641             result += $$sanitizeUri(trim( rawUris[innerIdx]), true);
       
 15642             // add the descriptor
       
 15643             result += ( " " + trim(rawUris[innerIdx+1]));
       
 15644           }
       
 15645 
       
 15646           // split the last item into uri and descriptor
       
 15647           var lastTuple = trim(rawUris[i*2]).split(/\s/);
       
 15648 
       
 15649           // sanitize the last uri
       
 15650           result += $$sanitizeUri(trim(lastTuple[0]), true);
       
 15651 
       
 15652           // and add the last descriptor if any
       
 15653           if( lastTuple.length === 2) {
       
 15654             result += (" " + trim(lastTuple[1]));
       
 15655           }
       
 15656           this[key] = value = result;
       
 15657         }
       
 15658 
       
 15659         if (writeAttr !== false) {
       
 15660           if (value === null || value === undefined) {
       
 15661             this.$$element.removeAttr(attrName);
       
 15662           } else {
       
 15663             this.$$element.attr(attrName, value);
       
 15664           }
       
 15665         }
       
 15666 
       
 15667         // fire observers
       
 15668         var $$observers = this.$$observers;
       
 15669         $$observers && forEach($$observers[observer], function(fn) {
       
 15670           try {
       
 15671             fn(value);
       
 15672           } catch (e) {
       
 15673             $exceptionHandler(e);
       
 15674           }
       
 15675         });
       
 15676       },
       
 15677 
       
 15678 
       
 15679       /**
       
 15680        * @ngdoc method
       
 15681        * @name $compile.directive.Attributes#$observe
       
 15682        * @kind function
       
 15683        *
       
 15684        * @description
       
 15685        * Observes an interpolated attribute.
       
 15686        *
       
 15687        * The observer function will be invoked once during the next `$digest` following
       
 15688        * compilation. The observer is then invoked whenever the interpolated value
       
 15689        * changes.
       
 15690        *
       
 15691        * @param {string} key Normalized key. (ie ngAttribute) .
       
 15692        * @param {function(interpolatedValue)} fn Function that will be called whenever
       
 15693                 the interpolated value of the attribute changes.
       
 15694        *        See {@link ng.$compile#attributes $compile} for more info.
       
 15695        * @returns {function()} Returns a deregistration function for this observer.
       
 15696        */
       
 15697       $observe: function(key, fn) {
       
 15698         var attrs = this,
       
 15699             $$observers = (attrs.$$observers || (attrs.$$observers = Object.create(null))),
       
 15700             listeners = ($$observers[key] || ($$observers[key] = []));
       
 15701 
       
 15702         listeners.push(fn);
       
 15703         $rootScope.$evalAsync(function() {
       
 15704           if (!listeners.$$inter) {
       
 15705             // no one registered attribute interpolation function, so lets call it manually
       
 15706             fn(attrs[key]);
       
 15707           }
       
 15708         });
       
 15709 
       
 15710         return function() {
       
 15711           arrayRemove(listeners, fn);
       
 15712         };
       
 15713       }
       
 15714     };
       
 15715 
       
 15716 
       
 15717     function safeAddClass($element, className) {
       
 15718       try {
       
 15719         $element.addClass(className);
       
 15720       } catch(e) {
       
 15721         // ignore, since it means that we are trying to set class on
       
 15722         // SVG element, where class name is read-only.
       
 15723       }
       
 15724     }
       
 15725 
       
 15726 
       
 15727     var startSymbol = $interpolate.startSymbol(),
       
 15728         endSymbol = $interpolate.endSymbol(),
       
 15729         denormalizeTemplate = (startSymbol == '{{' || endSymbol  == '}}')
       
 15730             ? identity
       
 15731             : function denormalizeTemplate(template) {
       
 15732               return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol);
       
 15733         },
       
 15734         NG_ATTR_BINDING = /^ngAttr[A-Z]/;
       
 15735 
       
 15736     compile.$$addBindingInfo = debugInfoEnabled ? function $$addBindingInfo($element, binding) {
       
 15737       var bindings = $element.data('$binding') || [];
       
 15738 
       
 15739       if (isArray(binding)) {
       
 15740         bindings = bindings.concat(binding);
       
 15741       } else {
       
 15742         bindings.push(binding);
       
 15743       }
       
 15744 
       
 15745       $element.data('$binding', bindings);
       
 15746     } : noop;
       
 15747 
       
 15748     compile.$$addBindingClass = debugInfoEnabled ? function $$addBindingClass($element) {
       
 15749       safeAddClass($element, 'ng-binding');
       
 15750     } : noop;
       
 15751 
       
 15752     compile.$$addScopeInfo = debugInfoEnabled ? function $$addScopeInfo($element, scope, isolated, noTemplate) {
       
 15753       var dataName = isolated ? (noTemplate ? '$isolateScopeNoTemplate' : '$isolateScope') : '$scope';
       
 15754       $element.data(dataName, scope);
       
 15755     } : noop;
       
 15756 
       
 15757     compile.$$addScopeClass = debugInfoEnabled ? function $$addScopeClass($element, isolated) {
       
 15758       safeAddClass($element, isolated ? 'ng-isolate-scope' : 'ng-scope');
       
 15759     } : noop;
       
 15760 
       
 15761     return compile;
       
 15762 
       
 15763     //================================
       
 15764 
       
 15765     function compile($compileNodes, transcludeFn, maxPriority, ignoreDirective,
       
 15766                         previousCompileContext) {
       
 15767       if (!($compileNodes instanceof jqLite)) {
       
 15768         // jquery always rewraps, whereas we need to preserve the original selector so that we can
       
 15769         // modify it.
       
 15770         $compileNodes = jqLite($compileNodes);
       
 15771       }
       
 15772       // We can not compile top level text elements since text nodes can be merged and we will
       
 15773       // not be able to attach scope data to them, so we will wrap them in <span>
       
 15774       forEach($compileNodes, function(node, index){
       
 15775         if (node.nodeType == NODE_TYPE_TEXT && node.nodeValue.match(/\S+/) /* non-empty */ ) {
       
 15776           $compileNodes[index] = jqLite(node).wrap('<span></span>').parent()[0];
       
 15777         }
       
 15778       });
       
 15779       var compositeLinkFn =
       
 15780               compileNodes($compileNodes, transcludeFn, $compileNodes,
       
 15781                            maxPriority, ignoreDirective, previousCompileContext);
       
 15782       compile.$$addScopeClass($compileNodes);
       
 15783       var namespace = null;
       
 15784       return function publicLinkFn(scope, cloneConnectFn, transcludeControllers, parentBoundTranscludeFn, futureParentElement){
       
 15785         assertArg(scope, 'scope');
       
 15786         if (!namespace) {
       
 15787           namespace = detectNamespaceForChildElements(futureParentElement);
       
 15788         }
       
 15789         var $linkNode;
       
 15790         if (namespace !== 'html') {
       
 15791           // When using a directive with replace:true and templateUrl the $compileNodes
       
 15792           // (or a child element inside of them)
       
 15793           // might change, so we need to recreate the namespace adapted compileNodes
       
 15794           // for call to the link function.
       
 15795           // Note: This will already clone the nodes...
       
 15796           $linkNode = jqLite(
       
 15797             wrapTemplate(namespace, jqLite('<div>').append($compileNodes).html())
       
 15798           );
       
 15799         } else if (cloneConnectFn) {
       
 15800           // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
       
 15801           // and sometimes changes the structure of the DOM.
       
 15802           $linkNode = JQLitePrototype.clone.call($compileNodes);
       
 15803         } else {
       
 15804           $linkNode = $compileNodes;
       
 15805         }
       
 15806 
       
 15807         if (transcludeControllers) {
       
 15808           for (var controllerName in transcludeControllers) {
       
 15809             $linkNode.data('$' + controllerName + 'Controller', transcludeControllers[controllerName].instance);
       
 15810           }
       
 15811         }
       
 15812 
       
 15813         compile.$$addScopeInfo($linkNode, scope);
       
 15814 
       
 15815         if (cloneConnectFn) cloneConnectFn($linkNode, scope);
       
 15816         if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode, parentBoundTranscludeFn);
       
 15817         return $linkNode;
       
 15818       };
       
 15819     }
       
 15820 
       
 15821     function detectNamespaceForChildElements(parentElement) {
       
 15822       // TODO: Make this detect MathML as well...
       
 15823       var node = parentElement && parentElement[0];
       
 15824       if (!node) {
       
 15825         return 'html';
       
 15826       } else {
       
 15827         return nodeName_(node) !== 'foreignobject' && node.toString().match(/SVG/) ? 'svg': 'html';
       
 15828       }
       
 15829     }
       
 15830 
       
 15831     /**
       
 15832      * Compile function matches each node in nodeList against the directives. Once all directives
       
 15833      * for a particular node are collected their compile functions are executed. The compile
       
 15834      * functions return values - the linking functions - are combined into a composite linking
       
 15835      * function, which is the a linking function for the node.
       
 15836      *
       
 15837      * @param {NodeList} nodeList an array of nodes or NodeList to compile
       
 15838      * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
       
 15839      *        scope argument is auto-generated to the new child of the transcluded parent scope.
       
 15840      * @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then
       
 15841      *        the rootElement must be set the jqLite collection of the compile root. This is
       
 15842      *        needed so that the jqLite collection items can be replaced with widgets.
       
 15843      * @param {number=} maxPriority Max directive priority.
       
 15844      * @returns {Function} A composite linking function of all of the matched directives or null.
       
 15845      */
       
 15846     function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective,
       
 15847                             previousCompileContext) {
       
 15848       var linkFns = [],
       
 15849           attrs, directives, nodeLinkFn, childNodes, childLinkFn, linkFnFound, nodeLinkFnFound;
       
 15850 
       
 15851       for (var i = 0; i < nodeList.length; i++) {
       
 15852         attrs = new Attributes();
       
 15853 
       
 15854         // we must always refer to nodeList[i] since the nodes can be replaced underneath us.
       
 15855         directives = collectDirectives(nodeList[i], [], attrs, i === 0 ? maxPriority : undefined,
       
 15856                                         ignoreDirective);
       
 15857 
       
 15858         nodeLinkFn = (directives.length)
       
 15859             ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement,
       
 15860                                       null, [], [], previousCompileContext)
       
 15861             : null;
       
 15862 
       
 15863         if (nodeLinkFn && nodeLinkFn.scope) {
       
 15864           compile.$$addScopeClass(attrs.$$element);
       
 15865         }
       
 15866 
       
 15867         childLinkFn = (nodeLinkFn && nodeLinkFn.terminal ||
       
 15868                       !(childNodes = nodeList[i].childNodes) ||
       
 15869                       !childNodes.length)
       
 15870             ? null
       
 15871             : compileNodes(childNodes,
       
 15872                  nodeLinkFn ? (
       
 15873                   (nodeLinkFn.transcludeOnThisElement || !nodeLinkFn.templateOnThisElement)
       
 15874                      && nodeLinkFn.transclude) : transcludeFn);
       
 15875 
       
 15876         if (nodeLinkFn || childLinkFn) {
       
 15877           linkFns.push(i, nodeLinkFn, childLinkFn);
       
 15878           linkFnFound = true;
       
 15879           nodeLinkFnFound = nodeLinkFnFound || nodeLinkFn;
       
 15880         }
       
 15881 
       
 15882         //use the previous context only for the first element in the virtual group
       
 15883         previousCompileContext = null;
       
 15884       }
       
 15885 
       
 15886       // return a linking function if we have found anything, null otherwise
       
 15887       return linkFnFound ? compositeLinkFn : null;
       
 15888 
       
 15889       function compositeLinkFn(scope, nodeList, $rootElement, parentBoundTranscludeFn) {
       
 15890         var nodeLinkFn, childLinkFn, node, childScope, i, ii, idx, childBoundTranscludeFn;
       
 15891         var stableNodeList;
       
 15892 
       
 15893 
       
 15894         if (nodeLinkFnFound) {
       
 15895           // copy nodeList so that if a nodeLinkFn removes or adds an element at this DOM level our
       
 15896           // offsets don't get screwed up
       
 15897           var nodeListLength = nodeList.length;
       
 15898           stableNodeList = new Array(nodeListLength);
       
 15899 
       
 15900           // create a sparse array by only copying the elements which have a linkFn
       
 15901           for (i = 0; i < linkFns.length; i+=3) {
       
 15902             idx = linkFns[i];
       
 15903             stableNodeList[idx] = nodeList[idx];
       
 15904           }
       
 15905         } else {
       
 15906           stableNodeList = nodeList;
       
 15907         }
       
 15908 
       
 15909         for(i = 0, ii = linkFns.length; i < ii;) {
       
 15910           node = stableNodeList[linkFns[i++]];
       
 15911           nodeLinkFn = linkFns[i++];
       
 15912           childLinkFn = linkFns[i++];
       
 15913 
       
 15914           if (nodeLinkFn) {
       
 15915             if (nodeLinkFn.scope) {
       
 15916               childScope = scope.$new();
       
 15917               compile.$$addScopeInfo(jqLite(node), childScope);
       
 15918             } else {
       
 15919               childScope = scope;
       
 15920             }
       
 15921 
       
 15922             if ( nodeLinkFn.transcludeOnThisElement ) {
       
 15923               childBoundTranscludeFn = createBoundTranscludeFn(
       
 15924                   scope, nodeLinkFn.transclude, parentBoundTranscludeFn,
       
 15925                   nodeLinkFn.elementTranscludeOnThisElement);
       
 15926 
       
 15927             } else if (!nodeLinkFn.templateOnThisElement && parentBoundTranscludeFn) {
       
 15928               childBoundTranscludeFn = parentBoundTranscludeFn;
       
 15929 
       
 15930             } else if (!parentBoundTranscludeFn && transcludeFn) {
       
 15931               childBoundTranscludeFn = createBoundTranscludeFn(scope, transcludeFn);
       
 15932 
       
 15933             } else {
       
 15934               childBoundTranscludeFn = null;
       
 15935             }
       
 15936 
       
 15937             nodeLinkFn(childLinkFn, childScope, node, $rootElement, childBoundTranscludeFn);
       
 15938 
       
 15939           } else if (childLinkFn) {
       
 15940             childLinkFn(scope, node.childNodes, undefined, parentBoundTranscludeFn);
       
 15941           }
       
 15942         }
       
 15943       }
       
 15944     }
       
 15945 
       
 15946     function createBoundTranscludeFn(scope, transcludeFn, previousBoundTranscludeFn, elementTransclusion) {
       
 15947 
       
 15948       var boundTranscludeFn = function(transcludedScope, cloneFn, controllers, futureParentElement, containingScope) {
       
 15949 
       
 15950         if (!transcludedScope) {
       
 15951           transcludedScope = scope.$new(false, containingScope);
       
 15952           transcludedScope.$$transcluded = true;
       
 15953         }
       
 15954 
       
 15955         return transcludeFn(transcludedScope, cloneFn, controllers, previousBoundTranscludeFn, futureParentElement);
       
 15956       };
       
 15957 
       
 15958       return boundTranscludeFn;
       
 15959     }
       
 15960 
       
 15961     /**
       
 15962      * Looks for directives on the given node and adds them to the directive collection which is
       
 15963      * sorted.
       
 15964      *
       
 15965      * @param node Node to search.
       
 15966      * @param directives An array to which the directives are added to. This array is sorted before
       
 15967      *        the function returns.
       
 15968      * @param attrs The shared attrs object which is used to populate the normalized attributes.
       
 15969      * @param {number=} maxPriority Max directive priority.
       
 15970      */
       
 15971     function collectDirectives(node, directives, attrs, maxPriority, ignoreDirective) {
       
 15972       var nodeType = node.nodeType,
       
 15973           attrsMap = attrs.$attr,
       
 15974           match,
       
 15975           className;
       
 15976 
       
 15977       switch(nodeType) {
       
 15978         case NODE_TYPE_ELEMENT: /* Element */
       
 15979           // use the node name: <directive>
       
 15980           addDirective(directives,
       
 15981               directiveNormalize(nodeName_(node)), 'E', maxPriority, ignoreDirective);
       
 15982 
       
 15983           // iterate over the attributes
       
 15984           for (var attr, name, nName, ngAttrName, value, isNgAttr, nAttrs = node.attributes,
       
 15985                    j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
       
 15986             var attrStartName = false;
       
 15987             var attrEndName = false;
       
 15988 
       
 15989             attr = nAttrs[j];
       
 15990             name = attr.name;
       
 15991             value = trim(attr.value);
       
 15992 
       
 15993             // support ngAttr attribute binding
       
 15994             ngAttrName = directiveNormalize(name);
       
 15995             if (isNgAttr = NG_ATTR_BINDING.test(ngAttrName)) {
       
 15996               name = snake_case(ngAttrName.substr(6), '-');
       
 15997             }
       
 15998 
       
 15999             var directiveNName = ngAttrName.replace(/(Start|End)$/, '');
       
 16000             if (directiveIsMultiElement(directiveNName)) {
       
 16001               if (ngAttrName === directiveNName + 'Start') {
       
 16002                 attrStartName = name;
       
 16003                 attrEndName = name.substr(0, name.length - 5) + 'end';
       
 16004                 name = name.substr(0, name.length - 6);
       
 16005               }
       
 16006             }
       
 16007 
       
 16008             nName = directiveNormalize(name.toLowerCase());
       
 16009             attrsMap[nName] = name;
       
 16010             if (isNgAttr || !attrs.hasOwnProperty(nName)) {
       
 16011                 attrs[nName] = value;
       
 16012                 if (getBooleanAttrName(node, nName)) {
       
 16013                   attrs[nName] = true; // presence means true
       
 16014                 }
       
 16015             }
       
 16016             addAttrInterpolateDirective(node, directives, value, nName, isNgAttr);
       
 16017             addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName,
       
 16018                           attrEndName);
       
 16019           }
       
 16020 
       
 16021           // use class as directive
       
 16022           className = node.className;
       
 16023           if (isString(className) && className !== '') {
       
 16024             while (match = CLASS_DIRECTIVE_REGEXP.exec(className)) {
       
 16025               nName = directiveNormalize(match[2]);
       
 16026               if (addDirective(directives, nName, 'C', maxPriority, ignoreDirective)) {
       
 16027                 attrs[nName] = trim(match[3]);
       
 16028               }
       
 16029               className = className.substr(match.index + match[0].length);
       
 16030             }
       
 16031           }
       
 16032           break;
       
 16033         case NODE_TYPE_TEXT: /* Text Node */
       
 16034           addTextInterpolateDirective(directives, node.nodeValue);
       
 16035           break;
       
 16036         case NODE_TYPE_COMMENT: /* Comment */
       
 16037           try {
       
 16038             match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue);
       
 16039             if (match) {
       
 16040               nName = directiveNormalize(match[1]);
       
 16041               if (addDirective(directives, nName, 'M', maxPriority, ignoreDirective)) {
       
 16042                 attrs[nName] = trim(match[2]);
       
 16043               }
       
 16044             }
       
 16045           } catch (e) {
       
 16046             // turns out that under some circumstances IE9 throws errors when one attempts to read
       
 16047             // comment's node value.
       
 16048             // Just ignore it and continue. (Can't seem to reproduce in test case.)
       
 16049           }
       
 16050           break;
       
 16051       }
       
 16052 
       
 16053       directives.sort(byPriority);
       
 16054       return directives;
       
 16055     }
       
 16056 
       
 16057     /**
       
 16058      * Given a node with an directive-start it collects all of the siblings until it finds
       
 16059      * directive-end.
       
 16060      * @param node
       
 16061      * @param attrStart
       
 16062      * @param attrEnd
       
 16063      * @returns {*}
       
 16064      */
       
 16065     function groupScan(node, attrStart, attrEnd) {
       
 16066       var nodes = [];
       
 16067       var depth = 0;
       
 16068       if (attrStart && node.hasAttribute && node.hasAttribute(attrStart)) {
       
 16069         var startNode = node;
       
 16070         do {
       
 16071           if (!node) {
       
 16072             throw $compileMinErr('uterdir',
       
 16073                       "Unterminated attribute, found '{0}' but no matching '{1}' found.",
       
 16074                       attrStart, attrEnd);
       
 16075           }
       
 16076           if (node.nodeType == NODE_TYPE_ELEMENT) {
       
 16077             if (node.hasAttribute(attrStart)) depth++;
       
 16078             if (node.hasAttribute(attrEnd)) depth--;
       
 16079           }
       
 16080           nodes.push(node);
       
 16081           node = node.nextSibling;
       
 16082         } while (depth > 0);
       
 16083       } else {
       
 16084         nodes.push(node);
       
 16085       }
       
 16086 
       
 16087       return jqLite(nodes);
       
 16088     }
       
 16089 
       
 16090     /**
       
 16091      * Wrapper for linking function which converts normal linking function into a grouped
       
 16092      * linking function.
       
 16093      * @param linkFn
       
 16094      * @param attrStart
       
 16095      * @param attrEnd
       
 16096      * @returns {Function}
       
 16097      */
       
 16098     function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) {
       
 16099       return function(scope, element, attrs, controllers, transcludeFn) {
       
 16100         element = groupScan(element[0], attrStart, attrEnd);
       
 16101         return linkFn(scope, element, attrs, controllers, transcludeFn);
       
 16102       };
       
 16103     }
       
 16104 
       
 16105     /**
       
 16106      * Once the directives have been collected, their compile functions are executed. This method
       
 16107      * is responsible for inlining directive templates as well as terminating the application
       
 16108      * of the directives if the terminal directive has been reached.
       
 16109      *
       
 16110      * @param {Array} directives Array of collected directives to execute their compile function.
       
 16111      *        this needs to be pre-sorted by priority order.
       
 16112      * @param {Node} compileNode The raw DOM node to apply the compile functions to
       
 16113      * @param {Object} templateAttrs The shared attribute function
       
 16114      * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
       
 16115      *                                                  scope argument is auto-generated to the new
       
 16116      *                                                  child of the transcluded parent scope.
       
 16117      * @param {JQLite} jqCollection If we are working on the root of the compile tree then this
       
 16118      *                              argument has the root jqLite array so that we can replace nodes
       
 16119      *                              on it.
       
 16120      * @param {Object=} originalReplaceDirective An optional directive that will be ignored when
       
 16121      *                                           compiling the transclusion.
       
 16122      * @param {Array.<Function>} preLinkFns
       
 16123      * @param {Array.<Function>} postLinkFns
       
 16124      * @param {Object} previousCompileContext Context used for previous compilation of the current
       
 16125      *                                        node
       
 16126      * @returns {Function} linkFn
       
 16127      */
       
 16128     function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn,
       
 16129                                    jqCollection, originalReplaceDirective, preLinkFns, postLinkFns,
       
 16130                                    previousCompileContext) {
       
 16131       previousCompileContext = previousCompileContext || {};
       
 16132 
       
 16133       var terminalPriority = -Number.MAX_VALUE,
       
 16134           newScopeDirective,
       
 16135           controllerDirectives = previousCompileContext.controllerDirectives,
       
 16136           controllers,
       
 16137           newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective,
       
 16138           templateDirective = previousCompileContext.templateDirective,
       
 16139           nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective,
       
 16140           hasTranscludeDirective = false,
       
 16141           hasTemplate = false,
       
 16142           hasElementTranscludeDirective = previousCompileContext.hasElementTranscludeDirective,
       
 16143           $compileNode = templateAttrs.$$element = jqLite(compileNode),
       
 16144           directive,
       
 16145           directiveName,
       
 16146           $template,
       
 16147           replaceDirective = originalReplaceDirective,
       
 16148           childTranscludeFn = transcludeFn,
       
 16149           linkFn,
       
 16150           directiveValue;
       
 16151 
       
 16152       // executes all directives on the current element
       
 16153       for(var i = 0, ii = directives.length; i < ii; i++) {
       
 16154         directive = directives[i];
       
 16155         var attrStart = directive.$$start;
       
 16156         var attrEnd = directive.$$end;
       
 16157 
       
 16158         // collect multiblock sections
       
 16159         if (attrStart) {
       
 16160           $compileNode = groupScan(compileNode, attrStart, attrEnd);
       
 16161         }
       
 16162         $template = undefined;
       
 16163 
       
 16164         if (terminalPriority > directive.priority) {
       
 16165           break; // prevent further processing of directives
       
 16166         }
       
 16167 
       
 16168         if (directiveValue = directive.scope) {
       
 16169 
       
 16170           // skip the check for directives with async templates, we'll check the derived sync
       
 16171           // directive when the template arrives
       
 16172           if (!directive.templateUrl) {
       
 16173             if (isObject(directiveValue)) {
       
 16174               // This directive is trying to add an isolated scope.
       
 16175               // Check that there is no scope of any kind already
       
 16176               assertNoDuplicate('new/isolated scope', newIsolateScopeDirective || newScopeDirective,
       
 16177                                 directive, $compileNode);
       
 16178               newIsolateScopeDirective = directive;
       
 16179             } else {
       
 16180               // This directive is trying to add a child scope.
       
 16181               // Check that there is no isolated scope already
       
 16182               assertNoDuplicate('new/isolated scope', newIsolateScopeDirective, directive,
       
 16183                                 $compileNode);
       
 16184             }
       
 16185           }
       
 16186 
       
 16187           newScopeDirective = newScopeDirective || directive;
       
 16188         }
       
 16189 
       
 16190         directiveName = directive.name;
       
 16191 
       
 16192         if (!directive.templateUrl && directive.controller) {
       
 16193           directiveValue = directive.controller;
       
 16194           controllerDirectives = controllerDirectives || {};
       
 16195           assertNoDuplicate("'" + directiveName + "' controller",
       
 16196               controllerDirectives[directiveName], directive, $compileNode);
       
 16197           controllerDirectives[directiveName] = directive;
       
 16198         }
       
 16199 
       
 16200         if (directiveValue = directive.transclude) {
       
 16201           hasTranscludeDirective = true;
       
 16202 
       
 16203           // Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion.
       
 16204           // This option should only be used by directives that know how to safely handle element transclusion,
       
 16205           // where the transcluded nodes are added or replaced after linking.
       
 16206           if (!directive.$$tlb) {
       
 16207             assertNoDuplicate('transclusion', nonTlbTranscludeDirective, directive, $compileNode);
       
 16208             nonTlbTranscludeDirective = directive;
       
 16209           }
       
 16210 
       
 16211           if (directiveValue == 'element') {
       
 16212             hasElementTranscludeDirective = true;
       
 16213             terminalPriority = directive.priority;
       
 16214             $template = $compileNode;
       
 16215             $compileNode = templateAttrs.$$element =
       
 16216                 jqLite(document.createComment(' ' + directiveName + ': ' +
       
 16217                                               templateAttrs[directiveName] + ' '));
       
 16218             compileNode = $compileNode[0];
       
 16219             replaceWith(jqCollection, sliceArgs($template), compileNode);
       
 16220 
       
 16221             childTranscludeFn = compile($template, transcludeFn, terminalPriority,
       
 16222                                         replaceDirective && replaceDirective.name, {
       
 16223                                           // Don't pass in:
       
 16224                                           // - controllerDirectives - otherwise we'll create duplicates controllers
       
 16225                                           // - newIsolateScopeDirective or templateDirective - combining templates with
       
 16226                                           //   element transclusion doesn't make sense.
       
 16227                                           //
       
 16228                                           // We need only nonTlbTranscludeDirective so that we prevent putting transclusion
       
 16229                                           // on the same element more than once.
       
 16230                                           nonTlbTranscludeDirective: nonTlbTranscludeDirective
       
 16231                                         });
       
 16232           } else {
       
 16233             $template = jqLite(jqLiteClone(compileNode)).contents();
       
 16234             $compileNode.empty(); // clear contents
       
 16235             childTranscludeFn = compile($template, transcludeFn);
       
 16236           }
       
 16237         }
       
 16238 
       
 16239         if (directive.template) {
       
 16240           hasTemplate = true;
       
 16241           assertNoDuplicate('template', templateDirective, directive, $compileNode);
       
 16242           templateDirective = directive;
       
 16243 
       
 16244           directiveValue = (isFunction(directive.template))
       
 16245               ? directive.template($compileNode, templateAttrs)
       
 16246               : directive.template;
       
 16247 
       
 16248           directiveValue = denormalizeTemplate(directiveValue);
       
 16249 
       
 16250           if (directive.replace) {
       
 16251             replaceDirective = directive;
       
 16252             if (jqLiteIsTextNode(directiveValue)) {
       
 16253               $template = [];
       
 16254             } else {
       
 16255               $template = removeComments(wrapTemplate(directive.templateNamespace, trim(directiveValue)));
       
 16256             }
       
 16257             compileNode = $template[0];
       
 16258 
       
 16259             if ($template.length != 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) {
       
 16260               throw $compileMinErr('tplrt',
       
 16261                   "Template for directive '{0}' must have exactly one root element. {1}",
       
 16262                   directiveName, '');
       
 16263             }
       
 16264 
       
 16265             replaceWith(jqCollection, $compileNode, compileNode);
       
 16266 
       
 16267             var newTemplateAttrs = {$attr: {}};
       
 16268 
       
 16269             // combine directives from the original node and from the template:
       
 16270             // - take the array of directives for this element
       
 16271             // - split it into two parts, those that already applied (processed) and those that weren't (unprocessed)
       
 16272             // - collect directives from the template and sort them by priority
       
 16273             // - combine directives as: processed + template + unprocessed
       
 16274             var templateDirectives = collectDirectives(compileNode, [], newTemplateAttrs);
       
 16275             var unprocessedDirectives = directives.splice(i + 1, directives.length - (i + 1));
       
 16276 
       
 16277             if (newIsolateScopeDirective) {
       
 16278               markDirectivesAsIsolate(templateDirectives);
       
 16279             }
       
 16280             directives = directives.concat(templateDirectives).concat(unprocessedDirectives);
       
 16281             mergeTemplateAttributes(templateAttrs, newTemplateAttrs);
       
 16282 
       
 16283             ii = directives.length;
       
 16284           } else {
       
 16285             $compileNode.html(directiveValue);
       
 16286           }
       
 16287         }
       
 16288 
       
 16289         if (directive.templateUrl) {
       
 16290           hasTemplate = true;
       
 16291           assertNoDuplicate('template', templateDirective, directive, $compileNode);
       
 16292           templateDirective = directive;
       
 16293 
       
 16294           if (directive.replace) {
       
 16295             replaceDirective = directive;
       
 16296           }
       
 16297 
       
 16298           nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode,
       
 16299               templateAttrs, jqCollection, hasTranscludeDirective && childTranscludeFn, preLinkFns, postLinkFns, {
       
 16300                 controllerDirectives: controllerDirectives,
       
 16301                 newIsolateScopeDirective: newIsolateScopeDirective,
       
 16302                 templateDirective: templateDirective,
       
 16303                 nonTlbTranscludeDirective: nonTlbTranscludeDirective
       
 16304               });
       
 16305           ii = directives.length;
       
 16306         } else if (directive.compile) {
       
 16307           try {
       
 16308             linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn);
       
 16309             if (isFunction(linkFn)) {
       
 16310               addLinkFns(null, linkFn, attrStart, attrEnd);
       
 16311             } else if (linkFn) {
       
 16312               addLinkFns(linkFn.pre, linkFn.post, attrStart, attrEnd);
       
 16313             }
       
 16314           } catch (e) {
       
 16315             $exceptionHandler(e, startingTag($compileNode));
       
 16316           }
       
 16317         }
       
 16318 
       
 16319         if (directive.terminal) {
       
 16320           nodeLinkFn.terminal = true;
       
 16321           terminalPriority = Math.max(terminalPriority, directive.priority);
       
 16322         }
       
 16323 
       
 16324       }
       
 16325 
       
 16326       nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
       
 16327       nodeLinkFn.transcludeOnThisElement = hasTranscludeDirective;
       
 16328       nodeLinkFn.elementTranscludeOnThisElement = hasElementTranscludeDirective;
       
 16329       nodeLinkFn.templateOnThisElement = hasTemplate;
       
 16330       nodeLinkFn.transclude = childTranscludeFn;
       
 16331 
       
 16332       previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective;
       
 16333 
       
 16334       // might be normal or delayed nodeLinkFn depending on if templateUrl is present
       
 16335       return nodeLinkFn;
       
 16336 
       
 16337       ////////////////////
       
 16338 
       
 16339       function addLinkFns(pre, post, attrStart, attrEnd) {
       
 16340         if (pre) {
       
 16341           if (attrStart) pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd);
       
 16342           pre.require = directive.require;
       
 16343           pre.directiveName = directiveName;
       
 16344           if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
       
 16345             pre = cloneAndAnnotateFn(pre, {isolateScope: true});
       
 16346           }
       
 16347           preLinkFns.push(pre);
       
 16348         }
       
 16349         if (post) {
       
 16350           if (attrStart) post = groupElementsLinkFnWrapper(post, attrStart, attrEnd);
       
 16351           post.require = directive.require;
       
 16352           post.directiveName = directiveName;
       
 16353           if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
       
 16354             post = cloneAndAnnotateFn(post, {isolateScope: true});
       
 16355           }
       
 16356           postLinkFns.push(post);
       
 16357         }
       
 16358       }
       
 16359 
       
 16360 
       
 16361       function getControllers(directiveName, require, $element, elementControllers) {
       
 16362         var value, retrievalMethod = 'data', optional = false;
       
 16363         var $searchElement = $element;
       
 16364         var match;
       
 16365         if (isString(require)) {
       
 16366           match = require.match(REQUIRE_PREFIX_REGEXP);
       
 16367           require = require.substring(match[0].length);
       
 16368 
       
 16369           if (match[3]) {
       
 16370             if (match[1]) match[3] = null;
       
 16371             else match[1] = match[3];
       
 16372           }
       
 16373           if (match[1] === '^') {
       
 16374             retrievalMethod = 'inheritedData';
       
 16375           } else if (match[1] === '^^') {
       
 16376             retrievalMethod = 'inheritedData';
       
 16377             $searchElement = $element.parent();
       
 16378           }
       
 16379           if (match[2] === '?') {
       
 16380             optional = true;
       
 16381           }
       
 16382 
       
 16383           value = null;
       
 16384 
       
 16385           if (elementControllers && retrievalMethod === 'data') {
       
 16386             if (value = elementControllers[require]) {
       
 16387               value = value.instance;
       
 16388             }
       
 16389           }
       
 16390           value = value || $searchElement[retrievalMethod]('$' + require + 'Controller');
       
 16391 
       
 16392           if (!value && !optional) {
       
 16393             throw $compileMinErr('ctreq',
       
 16394                 "Controller '{0}', required by directive '{1}', can't be found!",
       
 16395                 require, directiveName);
       
 16396           }
       
 16397           return value;
       
 16398         } else if (isArray(require)) {
       
 16399           value = [];
       
 16400           forEach(require, function(require) {
       
 16401             value.push(getControllers(directiveName, require, $element, elementControllers));
       
 16402           });
       
 16403         }
       
 16404         return value;
       
 16405       }
       
 16406 
       
 16407 
       
 16408       function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
       
 16409         var i, ii, linkFn, controller, isolateScope, elementControllers, transcludeFn, $element,
       
 16410             attrs;
       
 16411 
       
 16412         if (compileNode === linkNode) {
       
 16413           attrs = templateAttrs;
       
 16414           $element = templateAttrs.$$element;
       
 16415         } else {
       
 16416           $element = jqLite(linkNode);
       
 16417           attrs = new Attributes($element, templateAttrs);
       
 16418         }
       
 16419 
       
 16420         if (newIsolateScopeDirective) {
       
 16421           isolateScope = scope.$new(true);
       
 16422         }
       
 16423 
       
 16424         transcludeFn = boundTranscludeFn && controllersBoundTransclude;
       
 16425         if (controllerDirectives) {
       
 16426           // TODO: merge `controllers` and `elementControllers` into single object.
       
 16427           controllers = {};
       
 16428           elementControllers = {};
       
 16429           forEach(controllerDirectives, function(directive) {
       
 16430             var locals = {
       
 16431               $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,
       
 16432               $element: $element,
       
 16433               $attrs: attrs,
       
 16434               $transclude: transcludeFn
       
 16435             }, controllerInstance;
       
 16436 
       
 16437             controller = directive.controller;
       
 16438             if (controller == '@') {
       
 16439               controller = attrs[directive.name];
       
 16440             }
       
 16441 
       
 16442             controllerInstance = $controller(controller, locals, true, directive.controllerAs);
       
 16443 
       
 16444             // For directives with element transclusion the element is a comment,
       
 16445             // but jQuery .data doesn't support attaching data to comment nodes as it's hard to
       
 16446             // clean up (http://bugs.jquery.com/ticket/8335).
       
 16447             // Instead, we save the controllers for the element in a local hash and attach to .data
       
 16448             // later, once we have the actual element.
       
 16449             elementControllers[directive.name] = controllerInstance;
       
 16450             if (!hasElementTranscludeDirective) {
       
 16451               $element.data('$' + directive.name + 'Controller', controllerInstance.instance);
       
 16452             }
       
 16453 
       
 16454             controllers[directive.name] = controllerInstance;
       
 16455           });
       
 16456         }
       
 16457 
       
 16458         if (newIsolateScopeDirective) {
       
 16459           var LOCAL_REGEXP = /^\s*([@=&])(\??)\s*(\w*)\s*$/;
       
 16460 
       
 16461           compile.$$addScopeInfo($element, isolateScope, true, !(templateDirective && (templateDirective === newIsolateScopeDirective ||
       
 16462               templateDirective === newIsolateScopeDirective.$$originalDirective)));
       
 16463           compile.$$addScopeClass($element, true);
       
 16464 
       
 16465           var isolateScopeController = controllers && controllers[newIsolateScopeDirective.name];
       
 16466           var isolateBindingContext = isolateScope;
       
 16467           if (isolateScopeController && isolateScopeController.identifier &&
       
 16468               newIsolateScopeDirective.bindToController === true) {
       
 16469             isolateBindingContext = isolateScopeController.instance;
       
 16470           }
       
 16471 
       
 16472           forEach(isolateScope.$$isolateBindings = newIsolateScopeDirective.$$isolateBindings, function(definition, scopeName) {
       
 16473             var attrName = definition.attrName,
       
 16474                 optional = definition.optional,
       
 16475                 mode = definition.mode, // @, =, or &
       
 16476                 lastValue,
       
 16477                 parentGet, parentSet, compare;
       
 16478 
       
 16479             switch (mode) {
       
 16480 
       
 16481               case '@':
       
 16482                 attrs.$observe(attrName, function(value) {
       
 16483                   isolateBindingContext[scopeName] = value;
       
 16484                 });
       
 16485                 attrs.$$observers[attrName].$$scope = scope;
       
 16486                 if( attrs[attrName] ) {
       
 16487                   // If the attribute has been provided then we trigger an interpolation to ensure
       
 16488                   // the value is there for use in the link fn
       
 16489                   isolateBindingContext[scopeName] = $interpolate(attrs[attrName])(scope);
       
 16490                 }
       
 16491                 break;
       
 16492 
       
 16493               case '=':
       
 16494                 if (optional && !attrs[attrName]) {
       
 16495                   return;
       
 16496                 }
       
 16497                 parentGet = $parse(attrs[attrName]);
       
 16498                 if (parentGet.literal) {
       
 16499                   compare = equals;
       
 16500                 } else {
       
 16501                   compare = function(a,b) { return a === b || (a !== a && b !== b); };
       
 16502                 }
       
 16503                 parentSet = parentGet.assign || function() {
       
 16504                   // reset the change, or we will throw this exception on every $digest
       
 16505                   lastValue = isolateBindingContext[scopeName] = parentGet(scope);
       
 16506                   throw $compileMinErr('nonassign',
       
 16507                       "Expression '{0}' used with directive '{1}' is non-assignable!",
       
 16508                       attrs[attrName], newIsolateScopeDirective.name);
       
 16509                 };
       
 16510                 lastValue = isolateBindingContext[scopeName] = parentGet(scope);
       
 16511                 var parentValueWatch = function parentValueWatch(parentValue) {
       
 16512                   if (!compare(parentValue, isolateBindingContext[scopeName])) {
       
 16513                     // we are out of sync and need to copy
       
 16514                     if (!compare(parentValue, lastValue)) {
       
 16515                       // parent changed and it has precedence
       
 16516                       isolateBindingContext[scopeName] = parentValue;
       
 16517                     } else {
       
 16518                       // if the parent can be assigned then do so
       
 16519                       parentSet(scope, parentValue = isolateBindingContext[scopeName]);
       
 16520                     }
       
 16521                   }
       
 16522                   return lastValue = parentValue;
       
 16523                 };
       
 16524                 parentValueWatch.$stateful = true;
       
 16525                 var unwatch = scope.$watch($parse(attrs[attrName], parentValueWatch), null, parentGet.literal);
       
 16526                 isolateScope.$on('$destroy', unwatch);
       
 16527                 break;
       
 16528 
       
 16529               case '&':
       
 16530                 parentGet = $parse(attrs[attrName]);
       
 16531                 isolateBindingContext[scopeName] = function(locals) {
       
 16532                   return parentGet(scope, locals);
       
 16533                 };
       
 16534                 break;
       
 16535             }
       
 16536           });
       
 16537         }
       
 16538         if (controllers) {
       
 16539           forEach(controllers, function(controller) {
       
 16540             controller();
       
 16541           });
       
 16542           controllers = null;
       
 16543         }
       
 16544 
       
 16545         // PRELINKING
       
 16546         for(i = 0, ii = preLinkFns.length; i < ii; i++) {
       
 16547           linkFn = preLinkFns[i];
       
 16548           invokeLinkFn(linkFn,
       
 16549               linkFn.isolateScope ? isolateScope : scope,
       
 16550               $element,
       
 16551               attrs,
       
 16552               linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers),
       
 16553               transcludeFn
       
 16554           );
       
 16555         }
       
 16556 
       
 16557         // RECURSION
       
 16558         // We only pass the isolate scope, if the isolate directive has a template,
       
 16559         // otherwise the child elements do not belong to the isolate directive.
       
 16560         var scopeToChild = scope;
       
 16561         if (newIsolateScopeDirective && (newIsolateScopeDirective.template || newIsolateScopeDirective.templateUrl === null)) {
       
 16562           scopeToChild = isolateScope;
       
 16563         }
       
 16564         childLinkFn && childLinkFn(scopeToChild, linkNode.childNodes, undefined, boundTranscludeFn);
       
 16565 
       
 16566         // POSTLINKING
       
 16567         for(i = postLinkFns.length - 1; i >= 0; i--) {
       
 16568           linkFn = postLinkFns[i];
       
 16569           invokeLinkFn(linkFn,
       
 16570               linkFn.isolateScope ? isolateScope : scope,
       
 16571               $element,
       
 16572               attrs,
       
 16573               linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers),
       
 16574               transcludeFn
       
 16575           );
       
 16576         }
       
 16577 
       
 16578         // This is the function that is injected as `$transclude`.
       
 16579         // Note: all arguments are optional!
       
 16580         function controllersBoundTransclude(scope, cloneAttachFn, futureParentElement) {
       
 16581           var transcludeControllers;
       
 16582 
       
 16583           // No scope passed in:
       
 16584           if (!isScope(scope)) {
       
 16585             futureParentElement = cloneAttachFn;
       
 16586             cloneAttachFn = scope;
       
 16587             scope = undefined;
       
 16588           }
       
 16589 
       
 16590           if (hasElementTranscludeDirective) {
       
 16591             transcludeControllers = elementControllers;
       
 16592           }
       
 16593           if (!futureParentElement) {
       
 16594             futureParentElement = hasElementTranscludeDirective ? $element.parent() : $element;
       
 16595           }
       
 16596           return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild);
       
 16597         }
       
 16598       }
       
 16599     }
       
 16600 
       
 16601     function markDirectivesAsIsolate(directives) {
       
 16602       // mark all directives as needing isolate scope.
       
 16603       for (var j = 0, jj = directives.length; j < jj; j++) {
       
 16604         directives[j] = inherit(directives[j], {$$isolateScope: true});
       
 16605       }
       
 16606     }
       
 16607 
       
 16608     /**
       
 16609      * looks up the directive and decorates it with exception handling and proper parameters. We
       
 16610      * call this the boundDirective.
       
 16611      *
       
 16612      * @param {string} name name of the directive to look up.
       
 16613      * @param {string} location The directive must be found in specific format.
       
 16614      *   String containing any of theses characters:
       
 16615      *
       
 16616      *   * `E`: element name
       
 16617      *   * `A': attribute
       
 16618      *   * `C`: class
       
 16619      *   * `M`: comment
       
 16620      * @returns {boolean} true if directive was added.
       
 16621      */
       
 16622     function addDirective(tDirectives, name, location, maxPriority, ignoreDirective, startAttrName,
       
 16623                           endAttrName) {
       
 16624       if (name === ignoreDirective) return null;
       
 16625       var match = null;
       
 16626       if (hasDirectives.hasOwnProperty(name)) {
       
 16627         for(var directive, directives = $injector.get(name + Suffix),
       
 16628             i = 0, ii = directives.length; i<ii; i++) {
       
 16629           try {
       
 16630             directive = directives[i];
       
 16631             if ( (maxPriority === undefined || maxPriority > directive.priority) &&
       
 16632                  directive.restrict.indexOf(location) != -1) {
       
 16633               if (startAttrName) {
       
 16634                 directive = inherit(directive, {$$start: startAttrName, $$end: endAttrName});
       
 16635               }
       
 16636               tDirectives.push(directive);
       
 16637               match = directive;
       
 16638             }
       
 16639           } catch(e) { $exceptionHandler(e); }
       
 16640         }
       
 16641       }
       
 16642       return match;
       
 16643     }
       
 16644 
       
 16645 
       
 16646     /**
       
 16647      * looks up the directive and returns true if it is a multi-element directive,
       
 16648      * and therefore requires DOM nodes between -start and -end markers to be grouped
       
 16649      * together.
       
 16650      *
       
 16651      * @param {string} name name of the directive to look up.
       
 16652      * @returns true if directive was registered as multi-element.
       
 16653      */
       
 16654     function directiveIsMultiElement(name) {
       
 16655       if (hasDirectives.hasOwnProperty(name)) {
       
 16656         for(var directive, directives = $injector.get(name + Suffix),
       
 16657             i = 0, ii = directives.length; i<ii; i++) {
       
 16658           directive = directives[i];
       
 16659           if (directive.multiElement) {
       
 16660             return true;
       
 16661           }
       
 16662         }
       
 16663       }
       
 16664       return false;
       
 16665     }
       
 16666 
       
 16667     /**
       
 16668      * When the element is replaced with HTML template then the new attributes
       
 16669      * on the template need to be merged with the existing attributes in the DOM.
       
 16670      * The desired effect is to have both of the attributes present.
       
 16671      *
       
 16672      * @param {object} dst destination attributes (original DOM)
       
 16673      * @param {object} src source attributes (from the directive template)
       
 16674      */
       
 16675     function mergeTemplateAttributes(dst, src) {
       
 16676       var srcAttr = src.$attr,
       
 16677           dstAttr = dst.$attr,
       
 16678           $element = dst.$$element;
       
 16679 
       
 16680       // reapply the old attributes to the new element
       
 16681       forEach(dst, function(value, key) {
       
 16682         if (key.charAt(0) != '$') {
       
 16683           if (src[key] && src[key] !== value) {
       
 16684             value += (key === 'style' ? ';' : ' ') + src[key];
       
 16685           }
       
 16686           dst.$set(key, value, true, srcAttr[key]);
       
 16687         }
       
 16688       });
       
 16689 
       
 16690       // copy the new attributes on the old attrs object
       
 16691       forEach(src, function(value, key) {
       
 16692         if (key == 'class') {
       
 16693           safeAddClass($element, value);
       
 16694           dst['class'] = (dst['class'] ? dst['class'] + ' ' : '') + value;
       
 16695         } else if (key == 'style') {
       
 16696           $element.attr('style', $element.attr('style') + ';' + value);
       
 16697           dst['style'] = (dst['style'] ? dst['style'] + ';' : '') + value;
       
 16698           // `dst` will never contain hasOwnProperty as DOM parser won't let it.
       
 16699           // You will get an "InvalidCharacterError: DOM Exception 5" error if you
       
 16700           // have an attribute like "has-own-property" or "data-has-own-property", etc.
       
 16701         } else if (key.charAt(0) != '$' && !dst.hasOwnProperty(key)) {
       
 16702           dst[key] = value;
       
 16703           dstAttr[key] = srcAttr[key];
       
 16704         }
       
 16705       });
       
 16706     }
       
 16707 
       
 16708 
       
 16709     function compileTemplateUrl(directives, $compileNode, tAttrs,
       
 16710         $rootElement, childTranscludeFn, preLinkFns, postLinkFns, previousCompileContext) {
       
 16711       var linkQueue = [],
       
 16712           afterTemplateNodeLinkFn,
       
 16713           afterTemplateChildLinkFn,
       
 16714           beforeTemplateCompileNode = $compileNode[0],
       
 16715           origAsyncDirective = directives.shift(),
       
 16716           // The fact that we have to copy and patch the directive seems wrong!
       
 16717           derivedSyncDirective = extend({}, origAsyncDirective, {
       
 16718             templateUrl: null, transclude: null, replace: null, $$originalDirective: origAsyncDirective
       
 16719           }),
       
 16720           templateUrl = (isFunction(origAsyncDirective.templateUrl))
       
 16721               ? origAsyncDirective.templateUrl($compileNode, tAttrs)
       
 16722               : origAsyncDirective.templateUrl,
       
 16723           templateNamespace = origAsyncDirective.templateNamespace;
       
 16724 
       
 16725       $compileNode.empty();
       
 16726 
       
 16727       $templateRequest($sce.getTrustedResourceUrl(templateUrl))
       
 16728         .then(function(content) {
       
 16729           var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn;
       
 16730 
       
 16731           content = denormalizeTemplate(content);
       
 16732 
       
 16733           if (origAsyncDirective.replace) {
       
 16734             if (jqLiteIsTextNode(content)) {
       
 16735               $template = [];
       
 16736             } else {
       
 16737               $template = removeComments(wrapTemplate(templateNamespace, trim(content)));
       
 16738             }
       
 16739             compileNode = $template[0];
       
 16740 
       
 16741             if ($template.length != 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) {
       
 16742               throw $compileMinErr('tplrt',
       
 16743                   "Template for directive '{0}' must have exactly one root element. {1}",
       
 16744                   origAsyncDirective.name, templateUrl);
       
 16745             }
       
 16746 
       
 16747             tempTemplateAttrs = {$attr: {}};
       
 16748             replaceWith($rootElement, $compileNode, compileNode);
       
 16749             var templateDirectives = collectDirectives(compileNode, [], tempTemplateAttrs);
       
 16750 
       
 16751             if (isObject(origAsyncDirective.scope)) {
       
 16752               markDirectivesAsIsolate(templateDirectives);
       
 16753             }
       
 16754             directives = templateDirectives.concat(directives);
       
 16755             mergeTemplateAttributes(tAttrs, tempTemplateAttrs);
       
 16756           } else {
       
 16757             compileNode = beforeTemplateCompileNode;
       
 16758             $compileNode.html(content);
       
 16759           }
       
 16760 
       
 16761           directives.unshift(derivedSyncDirective);
       
 16762 
       
 16763           afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs,
       
 16764               childTranscludeFn, $compileNode, origAsyncDirective, preLinkFns, postLinkFns,
       
 16765               previousCompileContext);
       
 16766           forEach($rootElement, function(node, i) {
       
 16767             if (node == compileNode) {
       
 16768               $rootElement[i] = $compileNode[0];
       
 16769             }
       
 16770           });
       
 16771           afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn);
       
 16772 
       
 16773           while(linkQueue.length) {
       
 16774             var scope = linkQueue.shift(),
       
 16775                 beforeTemplateLinkNode = linkQueue.shift(),
       
 16776                 linkRootElement = linkQueue.shift(),
       
 16777                 boundTranscludeFn = linkQueue.shift(),
       
 16778                 linkNode = $compileNode[0];
       
 16779 
       
 16780             if (scope.$$destroyed) continue;
       
 16781 
       
 16782             if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
       
 16783               var oldClasses = beforeTemplateLinkNode.className;
       
 16784 
       
 16785               if (!(previousCompileContext.hasElementTranscludeDirective &&
       
 16786                   origAsyncDirective.replace)) {
       
 16787                 // it was cloned therefore we have to clone as well.
       
 16788                 linkNode = jqLiteClone(compileNode);
       
 16789               }
       
 16790               replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);
       
 16791 
       
 16792               // Copy in CSS classes from original node
       
 16793               safeAddClass(jqLite(linkNode), oldClasses);
       
 16794             }
       
 16795             if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
       
 16796               childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
       
 16797             } else {
       
 16798               childBoundTranscludeFn = boundTranscludeFn;
       
 16799             }
       
 16800             afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement,
       
 16801               childBoundTranscludeFn);
       
 16802           }
       
 16803           linkQueue = null;
       
 16804         });
       
 16805 
       
 16806       return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) {
       
 16807         var childBoundTranscludeFn = boundTranscludeFn;
       
 16808         if (scope.$$destroyed) return;
       
 16809         if (linkQueue) {
       
 16810           linkQueue.push(scope);
       
 16811           linkQueue.push(node);
       
 16812           linkQueue.push(rootElement);
       
 16813           linkQueue.push(childBoundTranscludeFn);
       
 16814         } else {
       
 16815           if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
       
 16816             childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
       
 16817           }
       
 16818           afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, childBoundTranscludeFn);
       
 16819         }
       
 16820       };
       
 16821     }
       
 16822 
       
 16823 
       
 16824     /**
       
 16825      * Sorting function for bound directives.
       
 16826      */
       
 16827     function byPriority(a, b) {
       
 16828       var diff = b.priority - a.priority;
       
 16829       if (diff !== 0) return diff;
       
 16830       if (a.name !== b.name) return (a.name < b.name) ? -1 : 1;
       
 16831       return a.index - b.index;
       
 16832     }
       
 16833 
       
 16834 
       
 16835     function assertNoDuplicate(what, previousDirective, directive, element) {
       
 16836       if (previousDirective) {
       
 16837         throw $compileMinErr('multidir', 'Multiple directives [{0}, {1}] asking for {2} on: {3}',
       
 16838             previousDirective.name, directive.name, what, startingTag(element));
       
 16839       }
       
 16840     }
       
 16841 
       
 16842 
       
 16843     function addTextInterpolateDirective(directives, text) {
       
 16844       var interpolateFn = $interpolate(text, true);
       
 16845       if (interpolateFn) {
       
 16846         directives.push({
       
 16847           priority: 0,
       
 16848           compile: function textInterpolateCompileFn(templateNode) {
       
 16849             var templateNodeParent = templateNode.parent(),
       
 16850                 hasCompileParent = !!templateNodeParent.length;
       
 16851 
       
 16852             // When transcluding a template that has bindings in the root
       
 16853             // we don't have a parent and thus need to add the class during linking fn.
       
 16854             if (hasCompileParent) compile.$$addBindingClass(templateNodeParent);
       
 16855 
       
 16856             return function textInterpolateLinkFn(scope, node) {
       
 16857               var parent = node.parent();
       
 16858               if (!hasCompileParent) compile.$$addBindingClass(parent);
       
 16859               compile.$$addBindingInfo(parent, interpolateFn.expressions);
       
 16860               scope.$watch(interpolateFn, function interpolateFnWatchAction(value) {
       
 16861                 node[0].nodeValue = value;
       
 16862               });
       
 16863             };
       
 16864           }
       
 16865         });
       
 16866       }
       
 16867     }
       
 16868 
       
 16869 
       
 16870     function wrapTemplate(type, template) {
       
 16871       type = lowercase(type || 'html');
       
 16872       switch(type) {
       
 16873       case 'svg':
       
 16874       case 'math':
       
 16875         var wrapper = document.createElement('div');
       
 16876         wrapper.innerHTML = '<'+type+'>'+template+'</'+type+'>';
       
 16877         return wrapper.childNodes[0].childNodes;
       
 16878       default:
       
 16879         return template;
       
 16880       }
       
 16881     }
       
 16882 
       
 16883 
       
 16884     function getTrustedContext(node, attrNormalizedName) {
       
 16885       if (attrNormalizedName == "srcdoc") {
       
 16886         return $sce.HTML;
       
 16887       }
       
 16888       var tag = nodeName_(node);
       
 16889       // maction[xlink:href] can source SVG.  It's not limited to <maction>.
       
 16890       if (attrNormalizedName == "xlinkHref" ||
       
 16891           (tag == "form" && attrNormalizedName == "action") ||
       
 16892           (tag != "img" && (attrNormalizedName == "src" ||
       
 16893                             attrNormalizedName == "ngSrc"))) {
       
 16894         return $sce.RESOURCE_URL;
       
 16895       }
       
 16896     }
       
 16897 
       
 16898 
       
 16899     function addAttrInterpolateDirective(node, directives, value, name, allOrNothing) {
       
 16900       var interpolateFn = $interpolate(value, true);
       
 16901 
       
 16902       // no interpolation found -> ignore
       
 16903       if (!interpolateFn) return;
       
 16904 
       
 16905 
       
 16906       if (name === "multiple" && nodeName_(node) === "select") {
       
 16907         throw $compileMinErr("selmulti",
       
 16908             "Binding to the 'multiple' attribute is not supported. Element: {0}",
       
 16909             startingTag(node));
       
 16910       }
       
 16911 
       
 16912       directives.push({
       
 16913         priority: 100,
       
 16914         compile: function() {
       
 16915             return {
       
 16916               pre: function attrInterpolatePreLinkFn(scope, element, attr) {
       
 16917                 var $$observers = (attr.$$observers || (attr.$$observers = {}));
       
 16918 
       
 16919                 if (EVENT_HANDLER_ATTR_REGEXP.test(name)) {
       
 16920                   throw $compileMinErr('nodomevents',
       
 16921                       "Interpolations for HTML DOM event attributes are disallowed.  Please use the " +
       
 16922                           "ng- versions (such as ng-click instead of onclick) instead.");
       
 16923                 }
       
 16924 
       
 16925                 // If the attribute was removed, then we are done
       
 16926                 if (!attr[name]) {
       
 16927                   return;
       
 16928                 }
       
 16929 
       
 16930                 // we need to interpolate again, in case the attribute value has been updated
       
 16931                 // (e.g. by another directive's compile function)
       
 16932                 interpolateFn = $interpolate(attr[name], true, getTrustedContext(node, name),
       
 16933                     ALL_OR_NOTHING_ATTRS[name] || allOrNothing);
       
 16934 
       
 16935                 // if attribute was updated so that there is no interpolation going on we don't want to
       
 16936                 // register any observers
       
 16937                 if (!interpolateFn) return;
       
 16938 
       
 16939                 // initialize attr object so that it's ready in case we need the value for isolate
       
 16940                 // scope initialization, otherwise the value would not be available from isolate
       
 16941                 // directive's linking fn during linking phase
       
 16942                 attr[name] = interpolateFn(scope);
       
 16943 
       
 16944                 ($$observers[name] || ($$observers[name] = [])).$$inter = true;
       
 16945                 (attr.$$observers && attr.$$observers[name].$$scope || scope).
       
 16946                   $watch(interpolateFn, function interpolateFnWatchAction(newValue, oldValue) {
       
 16947                     //special case for class attribute addition + removal
       
 16948                     //so that class changes can tap into the animation
       
 16949                     //hooks provided by the $animate service. Be sure to
       
 16950                     //skip animations when the first digest occurs (when
       
 16951                     //both the new and the old values are the same) since
       
 16952                     //the CSS classes are the non-interpolated values
       
 16953                     if(name === 'class' && newValue != oldValue) {
       
 16954                       attr.$updateClass(newValue, oldValue);
       
 16955                     } else {
       
 16956                       attr.$set(name, newValue);
       
 16957                     }
       
 16958                   });
       
 16959               }
       
 16960             };
       
 16961           }
       
 16962       });
       
 16963     }
       
 16964 
       
 16965 
       
 16966     /**
       
 16967      * This is a special jqLite.replaceWith, which can replace items which
       
 16968      * have no parents, provided that the containing jqLite collection is provided.
       
 16969      *
       
 16970      * @param {JqLite=} $rootElement The root of the compile tree. Used so that we can replace nodes
       
 16971      *                               in the root of the tree.
       
 16972      * @param {JqLite} elementsToRemove The jqLite element which we are going to replace. We keep
       
 16973      *                                  the shell, but replace its DOM node reference.
       
 16974      * @param {Node} newNode The new DOM node.
       
 16975      */
       
 16976     function replaceWith($rootElement, elementsToRemove, newNode) {
       
 16977       var firstElementToRemove = elementsToRemove[0],
       
 16978           removeCount = elementsToRemove.length,
       
 16979           parent = firstElementToRemove.parentNode,
       
 16980           i, ii;
       
 16981 
       
 16982       if ($rootElement) {
       
 16983         for(i = 0, ii = $rootElement.length; i < ii; i++) {
       
 16984           if ($rootElement[i] == firstElementToRemove) {
       
 16985             $rootElement[i++] = newNode;
       
 16986             for (var j = i, j2 = j + removeCount - 1,
       
 16987                      jj = $rootElement.length;
       
 16988                  j < jj; j++, j2++) {
       
 16989               if (j2 < jj) {
       
 16990                 $rootElement[j] = $rootElement[j2];
       
 16991               } else {
       
 16992                 delete $rootElement[j];
       
 16993               }
       
 16994             }
       
 16995             $rootElement.length -= removeCount - 1;
       
 16996 
       
 16997             // If the replaced element is also the jQuery .context then replace it
       
 16998             // .context is a deprecated jQuery api, so we should set it only when jQuery set it
       
 16999             // http://api.jquery.com/context/
       
 17000             if ($rootElement.context === firstElementToRemove) {
       
 17001               $rootElement.context = newNode;
       
 17002             }
       
 17003             break;
       
 17004           }
       
 17005         }
       
 17006       }
       
 17007 
       
 17008       if (parent) {
       
 17009         parent.replaceChild(newNode, firstElementToRemove);
       
 17010       }
       
 17011 
       
 17012       // TODO(perf): what's this document fragment for? is it needed? can we at least reuse it?
       
 17013       var fragment = document.createDocumentFragment();
       
 17014       fragment.appendChild(firstElementToRemove);
       
 17015 
       
 17016       // Copy over user data (that includes Angular's $scope etc.). Don't copy private
       
 17017       // data here because there's no public interface in jQuery to do that and copying over
       
 17018       // event listeners (which is the main use of private data) wouldn't work anyway.
       
 17019       jqLite(newNode).data(jqLite(firstElementToRemove).data());
       
 17020 
       
 17021       // Remove data of the replaced element. We cannot just call .remove()
       
 17022       // on the element it since that would deallocate scope that is needed
       
 17023       // for the new node. Instead, remove the data "manually".
       
 17024       if (!jQuery) {
       
 17025         delete jqLite.cache[firstElementToRemove[jqLite.expando]];
       
 17026       } else {
       
 17027         // jQuery 2.x doesn't expose the data storage. Use jQuery.cleanData to clean up after
       
 17028         // the replaced element. The cleanData version monkey-patched by Angular would cause
       
 17029         // the scope to be trashed and we do need the very same scope to work with the new
       
 17030         // element. However, we cannot just cache the non-patched version and use it here as
       
 17031         // that would break if another library patches the method after Angular does (one
       
 17032         // example is jQuery UI). Instead, set a flag indicating scope destroying should be
       
 17033         // skipped this one time.
       
 17034         skipDestroyOnNextJQueryCleanData = true;
       
 17035         jQuery.cleanData([firstElementToRemove]);
       
 17036       }
       
 17037 
       
 17038       for (var k = 1, kk = elementsToRemove.length; k < kk; k++) {
       
 17039         var element = elementsToRemove[k];
       
 17040         jqLite(element).remove(); // must do this way to clean up expando
       
 17041         fragment.appendChild(element);
       
 17042         delete elementsToRemove[k];
       
 17043       }
       
 17044 
       
 17045       elementsToRemove[0] = newNode;
       
 17046       elementsToRemove.length = 1;
       
 17047     }
       
 17048 
       
 17049 
       
 17050     function cloneAndAnnotateFn(fn, annotation) {
       
 17051       return extend(function() { return fn.apply(null, arguments); }, fn, annotation);
       
 17052     }
       
 17053 
       
 17054 
       
 17055     function invokeLinkFn(linkFn, scope, $element, attrs, controllers, transcludeFn) {
       
 17056       try {
       
 17057         linkFn(scope, $element, attrs, controllers, transcludeFn);
       
 17058       } catch(e) {
       
 17059         $exceptionHandler(e, startingTag($element));
       
 17060       }
       
 17061     }
       
 17062   }];
       
 17063 }
       
 17064 
       
 17065 var PREFIX_REGEXP = /^(x[\:\-_]|data[\:\-_])/i;
       
 17066 /**
       
 17067  * Converts all accepted directives format into proper directive name.
       
 17068  * All of these will become 'myDirective':
       
 17069  *   my:Directive
       
 17070  *   my-directive
       
 17071  *   x-my-directive
       
 17072  *   data-my:directive
       
 17073  *
       
 17074  * Also there is special case for Moz prefix starting with upper case letter.
       
 17075  * @param name Name to normalize
       
 17076  */
       
 17077 function directiveNormalize(name) {
       
 17078   return camelCase(name.replace(PREFIX_REGEXP, ''));
       
 17079 }
       
 17080 
       
 17081 /**
       
 17082  * @ngdoc type
       
 17083  * @name $compile.directive.Attributes
       
 17084  *
       
 17085  * @description
       
 17086  * A shared object between directive compile / linking functions which contains normalized DOM
       
 17087  * element attributes. The values reflect current binding state `{{ }}`. The normalization is
       
 17088  * needed since all of these are treated as equivalent in Angular:
       
 17089  *
       
 17090  * ```
       
 17091  *    <span ng:bind="a" ng-bind="a" data-ng-bind="a" x-ng-bind="a">
       
 17092  * ```
       
 17093  */
       
 17094 
       
 17095 /**
       
 17096  * @ngdoc property
       
 17097  * @name $compile.directive.Attributes#$attr
       
 17098  *
       
 17099  * @description
       
 17100  * A map of DOM element attribute names to the normalized name. This is
       
 17101  * needed to do reverse lookup from normalized name back to actual name.
       
 17102  */
       
 17103 
       
 17104 
       
 17105 /**
       
 17106  * @ngdoc method
       
 17107  * @name $compile.directive.Attributes#$set
       
 17108  * @kind function
       
 17109  *
       
 17110  * @description
       
 17111  * Set DOM element attribute value.
       
 17112  *
       
 17113  *
       
 17114  * @param {string} name Normalized element attribute name of the property to modify. The name is
       
 17115  *          reverse-translated using the {@link ng.$compile.directive.Attributes#$attr $attr}
       
 17116  *          property to the original name.
       
 17117  * @param {string} value Value to set the attribute to. The value can be an interpolated string.
       
 17118  */
       
 17119 
       
 17120 
       
 17121 
       
 17122 /**
       
 17123  * Closure compiler type information
       
 17124  */
       
 17125 
       
 17126 function nodesetLinkingFn(
       
 17127   /* angular.Scope */ scope,
       
 17128   /* NodeList */ nodeList,
       
 17129   /* Element */ rootElement,
       
 17130   /* function(Function) */ boundTranscludeFn
       
 17131 ){}
       
 17132 
       
 17133 function directiveLinkingFn(
       
 17134   /* nodesetLinkingFn */ nodesetLinkingFn,
       
 17135   /* angular.Scope */ scope,
       
 17136   /* Node */ node,
       
 17137   /* Element */ rootElement,
       
 17138   /* function(Function) */ boundTranscludeFn
       
 17139 ){}
       
 17140 
       
 17141 function tokenDifference(str1, str2) {
       
 17142   var values = '',
       
 17143       tokens1 = str1.split(/\s+/),
       
 17144       tokens2 = str2.split(/\s+/);
       
 17145 
       
 17146   outer:
       
 17147   for(var i = 0; i < tokens1.length; i++) {
       
 17148     var token = tokens1[i];
       
 17149     for(var j = 0; j < tokens2.length; j++) {
       
 17150       if(token == tokens2[j]) continue outer;
       
 17151     }
       
 17152     values += (values.length > 0 ? ' ' : '') + token;
       
 17153   }
       
 17154   return values;
       
 17155 }
       
 17156 
       
 17157 function removeComments(jqNodes) {
       
 17158   jqNodes = jqLite(jqNodes);
       
 17159   var i = jqNodes.length;
       
 17160 
       
 17161   if (i <= 1) {
       
 17162     return jqNodes;
       
 17163   }
       
 17164 
       
 17165   while (i--) {
       
 17166     var node = jqNodes[i];
       
 17167     if (node.nodeType === NODE_TYPE_COMMENT) {
       
 17168       splice.call(jqNodes, i, 1);
       
 17169     }
       
 17170   }
       
 17171   return jqNodes;
       
 17172 }
       
 17173 
       
 17174 /**
       
 17175  * @ngdoc provider
       
 17176  * @name $controllerProvider
       
 17177  * @description
       
 17178  * The {@link ng.$controller $controller service} is used by Angular to create new
       
 17179  * controllers.
       
 17180  *
       
 17181  * This provider allows controller registration via the
       
 17182  * {@link ng.$controllerProvider#register register} method.
       
 17183  */
       
 17184 function $ControllerProvider() {
       
 17185   var controllers = {},
       
 17186       globals = false,
       
 17187       CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/;
       
 17188 
       
 17189 
       
 17190   /**
       
 17191    * @ngdoc method
       
 17192    * @name $controllerProvider#register
       
 17193    * @param {string|Object} name Controller name, or an object map of controllers where the keys are
       
 17194    *    the names and the values are the constructors.
       
 17195    * @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI
       
 17196    *    annotations in the array notation).
       
 17197    */
       
 17198   this.register = function(name, constructor) {
       
 17199     assertNotHasOwnProperty(name, 'controller');
       
 17200     if (isObject(name)) {
       
 17201       extend(controllers, name);
       
 17202     } else {
       
 17203       controllers[name] = constructor;
       
 17204     }
       
 17205   };
       
 17206 
       
 17207   /**
       
 17208    * @ngdoc method
       
 17209    * @name $controllerProvider#allowGlobals
       
 17210    * @description If called, allows `$controller` to find controller constructors on `window`
       
 17211    */
       
 17212   this.allowGlobals = function() {
       
 17213     globals = true;
       
 17214   };
       
 17215 
       
 17216 
       
 17217   this.$get = ['$injector', '$window', function($injector, $window) {
       
 17218 
       
 17219     /**
       
 17220      * @ngdoc service
       
 17221      * @name $controller
       
 17222      * @requires $injector
       
 17223      *
       
 17224      * @param {Function|string} constructor If called with a function then it's considered to be the
       
 17225      *    controller constructor function. Otherwise it's considered to be a string which is used
       
 17226      *    to retrieve the controller constructor using the following steps:
       
 17227      *
       
 17228      *    * check if a controller with given name is registered via `$controllerProvider`
       
 17229      *    * check if evaluating the string on the current scope returns a constructor
       
 17230      *    * if $controllerProvider#allowGlobals, check `window[constructor]` on the global
       
 17231      *      `window` object (not recommended)
       
 17232      *
       
 17233      * @param {Object} locals Injection locals for Controller.
       
 17234      * @return {Object} Instance of given controller.
       
 17235      *
       
 17236      * @description
       
 17237      * `$controller` service is responsible for instantiating controllers.
       
 17238      *
       
 17239      * It's just a simple call to {@link auto.$injector $injector}, but extracted into
       
 17240      * a service, so that one can override this service with [BC version](https://gist.github.com/1649788).
       
 17241      */
       
 17242     return function(expression, locals, later, ident) {
       
 17243       // PRIVATE API:
       
 17244       //   param `later` --- indicates that the controller's constructor is invoked at a later time.
       
 17245       //                     If true, $controller will allocate the object with the correct
       
 17246       //                     prototype chain, but will not invoke the controller until a returned
       
 17247       //                     callback is invoked.
       
 17248       //   param `ident` --- An optional label which overrides the label parsed from the controller
       
 17249       //                     expression, if any.
       
 17250       var instance, match, constructor, identifier;
       
 17251       later = later === true;
       
 17252       if (ident && isString(ident)) {
       
 17253         identifier = ident;
       
 17254       }
       
 17255 
       
 17256       if(isString(expression)) {
       
 17257         match = expression.match(CNTRL_REG),
       
 17258         constructor = match[1],
       
 17259         identifier = identifier || match[3];
       
 17260         expression = controllers.hasOwnProperty(constructor)
       
 17261             ? controllers[constructor]
       
 17262             : getter(locals.$scope, constructor, true) ||
       
 17263                 (globals ? getter($window, constructor, true) : undefined);
       
 17264 
       
 17265         assertArgFn(expression, constructor, true);
       
 17266       }
       
 17267 
       
 17268       if (later) {
       
 17269         // Instantiate controller later:
       
 17270         // This machinery is used to create an instance of the object before calling the
       
 17271         // controller's constructor itself.
       
 17272         //
       
 17273         // This allows properties to be added to the controller before the constructor is
       
 17274         // invoked. Primarily, this is used for isolate scope bindings in $compile.
       
 17275         //
       
 17276         // This feature is not intended for use by applications, and is thus not documented
       
 17277         // publicly.
       
 17278         var Constructor = function() {};
       
 17279         Constructor.prototype = (isArray(expression) ?
       
 17280           expression[expression.length - 1] : expression).prototype;
       
 17281         instance = new Constructor();
       
 17282 
       
 17283         if (identifier) {
       
 17284           addIdentifier(locals, identifier, instance, constructor || expression.name);
       
 17285         }
       
 17286 
       
 17287         return extend(function() {
       
 17288           $injector.invoke(expression, instance, locals, constructor);
       
 17289           return instance;
       
 17290         }, {
       
 17291           instance: instance,
       
 17292           identifier: identifier
       
 17293         });
       
 17294       }
       
 17295 
       
 17296       instance = $injector.instantiate(expression, locals, constructor);
       
 17297 
       
 17298       if (identifier) {
       
 17299         addIdentifier(locals, identifier, instance, constructor || expression.name);
       
 17300       }
       
 17301 
       
 17302       return instance;
       
 17303     };
       
 17304 
       
 17305     function addIdentifier(locals, identifier, instance, name) {
       
 17306       if (!(locals && isObject(locals.$scope))) {
       
 17307         throw minErr('$controller')('noscp',
       
 17308           "Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`.",
       
 17309           name, identifier);
       
 17310       }
       
 17311 
       
 17312       locals.$scope[identifier] = instance;
       
 17313     }
       
 17314   }];
       
 17315 }
       
 17316 
       
 17317 /**
       
 17318  * @ngdoc service
       
 17319  * @name $document
       
 17320  * @requires $window
       
 17321  *
       
 17322  * @description
       
 17323  * A {@link angular.element jQuery or jqLite} wrapper for the browser's `window.document` object.
       
 17324  *
       
 17325  * @example
       
 17326    <example module="documentExample">
       
 17327      <file name="index.html">
       
 17328        <div ng-controller="ExampleController">
       
 17329          <p>$document title: <b ng-bind="title"></b></p>
       
 17330          <p>window.document title: <b ng-bind="windowTitle"></b></p>
       
 17331        </div>
       
 17332      </file>
       
 17333      <file name="script.js">
       
 17334        angular.module('documentExample', [])
       
 17335          .controller('ExampleController', ['$scope', '$document', function($scope, $document) {
       
 17336            $scope.title = $document[0].title;
       
 17337            $scope.windowTitle = angular.element(window.document)[0].title;
       
 17338          }]);
       
 17339      </file>
       
 17340    </example>
       
 17341  */
       
 17342 function $DocumentProvider(){
       
 17343   this.$get = ['$window', function(window){
       
 17344     return jqLite(window.document);
       
 17345   }];
       
 17346 }
       
 17347 
       
 17348 /**
       
 17349  * @ngdoc service
       
 17350  * @name $exceptionHandler
       
 17351  * @requires ng.$log
       
 17352  *
       
 17353  * @description
       
 17354  * Any uncaught exception in angular expressions is delegated to this service.
       
 17355  * The default implementation simply delegates to `$log.error` which logs it into
       
 17356  * the browser console.
       
 17357  *
       
 17358  * In unit tests, if `angular-mocks.js` is loaded, this service is overridden by
       
 17359  * {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing.
       
 17360  *
       
 17361  * ## Example:
       
 17362  *
       
 17363  * ```js
       
 17364  *   angular.module('exceptionOverride', []).factory('$exceptionHandler', function () {
       
 17365  *     return function (exception, cause) {
       
 17366  *       exception.message += ' (caused by "' + cause + '")';
       
 17367  *       throw exception;
       
 17368  *     };
       
 17369  *   });
       
 17370  * ```
       
 17371  *
       
 17372  * This example will override the normal action of `$exceptionHandler`, to make angular
       
 17373  * exceptions fail hard when they happen, instead of just logging to the console.
       
 17374  *
       
 17375  * @param {Error} exception Exception associated with the error.
       
 17376  * @param {string=} cause optional information about the context in which
       
 17377  *       the error was thrown.
       
 17378  *
       
 17379  */
       
 17380 function $ExceptionHandlerProvider() {
       
 17381   this.$get = ['$log', function($log) {
       
 17382     return function(exception, cause) {
       
 17383       $log.error.apply($log, arguments);
       
 17384     };
       
 17385   }];
       
 17386 }
       
 17387 
       
 17388 /**
       
 17389  * Parse headers into key value object
       
 17390  *
       
 17391  * @param {string} headers Raw headers as a string
       
 17392  * @returns {Object} Parsed headers as key value object
       
 17393  */
       
 17394 function parseHeaders(headers) {
       
 17395   var parsed = {}, key, val, i;
       
 17396 
       
 17397   if (!headers) return parsed;
       
 17398 
       
 17399   forEach(headers.split('\n'), function(line) {
       
 17400     i = line.indexOf(':');
       
 17401     key = lowercase(trim(line.substr(0, i)));
       
 17402     val = trim(line.substr(i + 1));
       
 17403 
       
 17404     if (key) {
       
 17405       parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val;
       
 17406     }
       
 17407   });
       
 17408 
       
 17409   return parsed;
       
 17410 }
       
 17411 
       
 17412 
       
 17413 /**
       
 17414  * Returns a function that provides access to parsed headers.
       
 17415  *
       
 17416  * Headers are lazy parsed when first requested.
       
 17417  * @see parseHeaders
       
 17418  *
       
 17419  * @param {(string|Object)} headers Headers to provide access to.
       
 17420  * @returns {function(string=)} Returns a getter function which if called with:
       
 17421  *
       
 17422  *   - if called with single an argument returns a single header value or null
       
 17423  *   - if called with no arguments returns an object containing all headers.
       
 17424  */
       
 17425 function headersGetter(headers) {
       
 17426   var headersObj = isObject(headers) ? headers : undefined;
       
 17427 
       
 17428   return function(name) {
       
 17429     if (!headersObj) headersObj =  parseHeaders(headers);
       
 17430 
       
 17431     if (name) {
       
 17432       return headersObj[lowercase(name)] || null;
       
 17433     }
       
 17434 
       
 17435     return headersObj;
       
 17436   };
       
 17437 }
       
 17438 
       
 17439 
       
 17440 /**
       
 17441  * Chain all given functions
       
 17442  *
       
 17443  * This function is used for both request and response transforming
       
 17444  *
       
 17445  * @param {*} data Data to transform.
       
 17446  * @param {function(string=)} headers Http headers getter fn.
       
 17447  * @param {(Function|Array.<Function>)} fns Function or an array of functions.
       
 17448  * @returns {*} Transformed data.
       
 17449  */
       
 17450 function transformData(data, headers, fns) {
       
 17451   if (isFunction(fns))
       
 17452     return fns(data, headers);
       
 17453 
       
 17454   forEach(fns, function(fn) {
       
 17455     data = fn(data, headers);
       
 17456   });
       
 17457 
       
 17458   return data;
       
 17459 }
       
 17460 
       
 17461 
       
 17462 function isSuccess(status) {
       
 17463   return 200 <= status && status < 300;
       
 17464 }
       
 17465 
       
 17466 
       
 17467 /**
       
 17468  * @ngdoc provider
       
 17469  * @name $httpProvider
       
 17470  * @description
       
 17471  * Use `$httpProvider` to change the default behavior of the {@link ng.$http $http} service.
       
 17472  * */
       
 17473 function $HttpProvider() {
       
 17474   var JSON_START = /^\s*(\[|\{[^\{])/,
       
 17475       JSON_END = /[\}\]]\s*$/,
       
 17476       PROTECTION_PREFIX = /^\)\]\}',?\n/,
       
 17477       APPLICATION_JSON = 'application/json',
       
 17478       CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': APPLICATION_JSON + ';charset=utf-8'};
       
 17479 
       
 17480   /**
       
 17481    * @ngdoc property
       
 17482    * @name $httpProvider#defaults
       
 17483    * @description
       
 17484    *
       
 17485    * Object containing default values for all {@link ng.$http $http} requests.
       
 17486    *
       
 17487    * - **`defaults.xsrfCookieName`** - {string} - Name of cookie containing the XSRF token.
       
 17488    * Defaults value is `'XSRF-TOKEN'`.
       
 17489    *
       
 17490    * - **`defaults.xsrfHeaderName`** - {string} - Name of HTTP header to populate with the
       
 17491    * XSRF token. Defaults value is `'X-XSRF-TOKEN'`.
       
 17492    *
       
 17493    * - **`defaults.headers`** - {Object} - Default headers for all $http requests.
       
 17494    * Refer to {@link ng.$http#setting-http-headers $http} for documentation on
       
 17495    * setting default headers.
       
 17496    *     - **`defaults.headers.common`**
       
 17497    *     - **`defaults.headers.post`**
       
 17498    *     - **`defaults.headers.put`**
       
 17499    *     - **`defaults.headers.patch`**
       
 17500    **/
       
 17501   var defaults = this.defaults = {
       
 17502     // transform incoming response data
       
 17503     transformResponse: [function defaultHttpResponseTransform(data, headers) {
       
 17504       if (isString(data)) {
       
 17505         // strip json vulnerability protection prefix
       
 17506         data = data.replace(PROTECTION_PREFIX, '');
       
 17507         var contentType = headers('Content-Type');
       
 17508         if ((contentType && contentType.indexOf(APPLICATION_JSON) === 0) ||
       
 17509             (JSON_START.test(data) && JSON_END.test(data))) {
       
 17510           data = fromJson(data);
       
 17511         }
       
 17512       }
       
 17513       return data;
       
 17514     }],
       
 17515 
       
 17516     // transform outgoing request data
       
 17517     transformRequest: [function(d) {
       
 17518       return isObject(d) && !isFile(d) && !isBlob(d) ? toJson(d) : d;
       
 17519     }],
       
 17520 
       
 17521     // default headers
       
 17522     headers: {
       
 17523       common: {
       
 17524         'Accept': 'application/json, text/plain, */*'
       
 17525       },
       
 17526       post:   shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
       
 17527       put:    shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
       
 17528       patch:  shallowCopy(CONTENT_TYPE_APPLICATION_JSON)
       
 17529     },
       
 17530 
       
 17531     xsrfCookieName: 'XSRF-TOKEN',
       
 17532     xsrfHeaderName: 'X-XSRF-TOKEN'
       
 17533   };
       
 17534 
       
 17535   var useApplyAsync = false;
       
 17536   /**
       
 17537    * @ngdoc method
       
 17538    * @name $httpProvider#useApplyAsync
       
 17539    * @description
       
 17540    *
       
 17541    * Configure $http service to combine processing of multiple http responses received at around
       
 17542    * the same time via {@link ng.$rootScope#applyAsync $rootScope.$applyAsync}. This can result in
       
 17543    * significant performance improvement for bigger applications that make many HTTP requests
       
 17544    * concurrently (common during application bootstrap).
       
 17545    *
       
 17546    * Defaults to false. If no value is specifed, returns the current configured value.
       
 17547    *
       
 17548    * @param {boolean=} value If true, when requests are loaded, they will schedule a deferred
       
 17549    *    "apply" on the next tick, giving time for subsequent requests in a roughly ~10ms window
       
 17550    *    to load and share the same digest cycle.
       
 17551    *
       
 17552    * @returns {boolean|Object} If a value is specified, returns the $httpProvider for chaining.
       
 17553    *    otherwise, returns the current configured value.
       
 17554    **/
       
 17555   this.useApplyAsync = function(value) {
       
 17556     if (isDefined(value)) {
       
 17557       useApplyAsync = !!value;
       
 17558       return this;
       
 17559     }
       
 17560     return useApplyAsync;
       
 17561   };
       
 17562 
       
 17563   /**
       
 17564    * Are ordered by request, i.e. they are applied in the same order as the
       
 17565    * array, on request, but reverse order, on response.
       
 17566    */
       
 17567   var interceptorFactories = this.interceptors = [];
       
 17568 
       
 17569   this.$get = ['$httpBackend', '$browser', '$cacheFactory', '$rootScope', '$q', '$injector',
       
 17570       function($httpBackend, $browser, $cacheFactory, $rootScope, $q, $injector) {
       
 17571 
       
 17572     var defaultCache = $cacheFactory('$http');
       
 17573 
       
 17574     /**
       
 17575      * Interceptors stored in reverse order. Inner interceptors before outer interceptors.
       
 17576      * The reversal is needed so that we can build up the interception chain around the
       
 17577      * server request.
       
 17578      */
       
 17579     var reversedInterceptors = [];
       
 17580 
       
 17581     forEach(interceptorFactories, function(interceptorFactory) {
       
 17582       reversedInterceptors.unshift(isString(interceptorFactory)
       
 17583           ? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory));
       
 17584     });
       
 17585 
       
 17586     /**
       
 17587      * @ngdoc service
       
 17588      * @kind function
       
 17589      * @name $http
       
 17590      * @requires ng.$httpBackend
       
 17591      * @requires $cacheFactory
       
 17592      * @requires $rootScope
       
 17593      * @requires $q
       
 17594      * @requires $injector
       
 17595      *
       
 17596      * @description
       
 17597      * The `$http` service is a core Angular service that facilitates communication with the remote
       
 17598      * HTTP servers via the browser's [XMLHttpRequest](https://developer.mozilla.org/en/xmlhttprequest)
       
 17599      * object or via [JSONP](http://en.wikipedia.org/wiki/JSONP).
       
 17600      *
       
 17601      * For unit testing applications that use `$http` service, see
       
 17602      * {@link ngMock.$httpBackend $httpBackend mock}.
       
 17603      *
       
 17604      * For a higher level of abstraction, please check out the {@link ngResource.$resource
       
 17605      * $resource} service.
       
 17606      *
       
 17607      * The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by
       
 17608      * the $q service. While for simple usage patterns this doesn't matter much, for advanced usage
       
 17609      * it is important to familiarize yourself with these APIs and the guarantees they provide.
       
 17610      *
       
 17611      *
       
 17612      * ## General usage
       
 17613      * The `$http` service is a function which takes a single argument — a configuration object —
       
 17614      * that is used to generate an HTTP request and returns  a {@link ng.$q promise}
       
 17615      * with two $http specific methods: `success` and `error`.
       
 17616      *
       
 17617      * ```js
       
 17618      *   $http({method: 'GET', url: '/someUrl'}).
       
 17619      *     success(function(data, status, headers, config) {
       
 17620      *       // this callback will be called asynchronously
       
 17621      *       // when the response is available
       
 17622      *     }).
       
 17623      *     error(function(data, status, headers, config) {
       
 17624      *       // called asynchronously if an error occurs
       
 17625      *       // or server returns response with an error status.
       
 17626      *     });
       
 17627      * ```
       
 17628      *
       
 17629      * Since the returned value of calling the $http function is a `promise`, you can also use
       
 17630      * the `then` method to register callbacks, and these callbacks will receive a single argument –
       
 17631      * an object representing the response. See the API signature and type info below for more
       
 17632      * details.
       
 17633      *
       
 17634      * A response status code between 200 and 299 is considered a success status and
       
 17635      * will result in the success callback being called. Note that if the response is a redirect,
       
 17636      * XMLHttpRequest will transparently follow it, meaning that the error callback will not be
       
 17637      * called for such responses.
       
 17638      *
       
 17639      * ## Writing Unit Tests that use $http
       
 17640      * When unit testing (using {@link ngMock ngMock}), it is necessary to call
       
 17641      * {@link ngMock.$httpBackend#flush $httpBackend.flush()} to flush each pending
       
 17642      * request using trained responses.
       
 17643      *
       
 17644      * ```
       
 17645      * $httpBackend.expectGET(...);
       
 17646      * $http.get(...);
       
 17647      * $httpBackend.flush();
       
 17648      * ```
       
 17649      *
       
 17650      * ## Shortcut methods
       
 17651      *
       
 17652      * Shortcut methods are also available. All shortcut methods require passing in the URL, and
       
 17653      * request data must be passed in for POST/PUT requests.
       
 17654      *
       
 17655      * ```js
       
 17656      *   $http.get('/someUrl').success(successCallback);
       
 17657      *   $http.post('/someUrl', data).success(successCallback);
       
 17658      * ```
       
 17659      *
       
 17660      * Complete list of shortcut methods:
       
 17661      *
       
 17662      * - {@link ng.$http#get $http.get}
       
 17663      * - {@link ng.$http#head $http.head}
       
 17664      * - {@link ng.$http#post $http.post}
       
 17665      * - {@link ng.$http#put $http.put}
       
 17666      * - {@link ng.$http#delete $http.delete}
       
 17667      * - {@link ng.$http#jsonp $http.jsonp}
       
 17668      * - {@link ng.$http#patch $http.patch}
       
 17669      *
       
 17670      *
       
 17671      * ## Setting HTTP Headers
       
 17672      *
       
 17673      * The $http service will automatically add certain HTTP headers to all requests. These defaults
       
 17674      * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration
       
 17675      * object, which currently contains this default configuration:
       
 17676      *
       
 17677      * - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
       
 17678      *   - `Accept: application/json, text/plain, * / *`
       
 17679      * - `$httpProvider.defaults.headers.post`: (header defaults for POST requests)
       
 17680      *   - `Content-Type: application/json`
       
 17681      * - `$httpProvider.defaults.headers.put` (header defaults for PUT requests)
       
 17682      *   - `Content-Type: application/json`
       
 17683      *
       
 17684      * To add or overwrite these defaults, simply add or remove a property from these configuration
       
 17685      * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
       
 17686      * with the lowercased HTTP method name as the key, e.g.
       
 17687      * `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }.
       
 17688      *
       
 17689      * The defaults can also be set at runtime via the `$http.defaults` object in the same
       
 17690      * fashion. For example:
       
 17691      *
       
 17692      * ```
       
 17693      * module.run(function($http) {
       
 17694      *   $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w'
       
 17695      * });
       
 17696      * ```
       
 17697      *
       
 17698      * In addition, you can supply a `headers` property in the config object passed when
       
 17699      * calling `$http(config)`, which overrides the defaults without changing them globally.
       
 17700      *
       
 17701      *
       
 17702      * ## Transforming Requests and Responses
       
 17703      *
       
 17704      * Both requests and responses can be transformed using transformation functions: `transformRequest`
       
 17705      * and `transformResponse`. These properties can be a single function that returns
       
 17706      * the transformed value (`{function(data, headersGetter)`) or an array of such transformation functions,
       
 17707      * which allows you to `push` or `unshift` a new transformation function into the transformation chain.
       
 17708      *
       
 17709      * ### Default Transformations
       
 17710      *
       
 17711      * The `$httpProvider` provider and `$http` service expose `defaults.transformRequest` and
       
 17712      * `defaults.transformResponse` properties. If a request does not provide its own transformations
       
 17713      * then these will be applied.
       
 17714      *
       
 17715      * You can augment or replace the default transformations by modifying these properties by adding to or
       
 17716      * replacing the array.
       
 17717      *
       
 17718      * Angular provides the following default transformations:
       
 17719      *
       
 17720      * Request transformations (`$httpProvider.defaults.transformRequest` and `$http.defaults.transformRequest`):
       
 17721      *
       
 17722      * - If the `data` property of the request configuration object contains an object, serialize it
       
 17723      *   into JSON format.
       
 17724      *
       
 17725      * Response transformations (`$httpProvider.defaults.transformResponse` and `$http.defaults.transformResponse`):
       
 17726      *
       
 17727      *  - If XSRF prefix is detected, strip it (see Security Considerations section below).
       
 17728      *  - If JSON response is detected, deserialize it using a JSON parser.
       
 17729      *
       
 17730      *
       
 17731      * ### Overriding the Default Transformations Per Request
       
 17732      *
       
 17733      * If you wish override the request/response transformations only for a single request then provide
       
 17734      * `transformRequest` and/or `transformResponse` properties on the configuration object passed
       
 17735      * into `$http`.
       
 17736      *
       
 17737      * Note that if you provide these properties on the config object the default transformations will be
       
 17738      * overwritten. If you wish to augment the default transformations then you must include them in your
       
 17739      * local transformation array.
       
 17740      *
       
 17741      * The following code demonstrates adding a new response transformation to be run after the default response
       
 17742      * transformations have been run.
       
 17743      *
       
 17744      * ```js
       
 17745      * function appendTransform(defaults, transform) {
       
 17746      *
       
 17747      *   // We can't guarantee that the default transformation is an array
       
 17748      *   defaults = angular.isArray(defaults) ? defaults : [defaults];
       
 17749      *
       
 17750      *   // Append the new transformation to the defaults
       
 17751      *   return defaults.concat(transform);
       
 17752      * }
       
 17753      *
       
 17754      * $http({
       
 17755      *   url: '...',
       
 17756      *   method: 'GET',
       
 17757      *   transformResponse: appendTransform($http.defaults.transformResponse, function(value) {
       
 17758      *     return doTransform(value);
       
 17759      *   })
       
 17760      * });
       
 17761      * ```
       
 17762      *
       
 17763      *
       
 17764      * ## Caching
       
 17765      *
       
 17766      * To enable caching, set the request configuration `cache` property to `true` (to use default
       
 17767      * cache) or to a custom cache object (built with {@link ng.$cacheFactory `$cacheFactory`}).
       
 17768      * When the cache is enabled, `$http` stores the response from the server in the specified
       
 17769      * cache. The next time the same request is made, the response is served from the cache without
       
 17770      * sending a request to the server.
       
 17771      *
       
 17772      * Note that even if the response is served from cache, delivery of the data is asynchronous in
       
 17773      * the same way that real requests are.
       
 17774      *
       
 17775      * If there are multiple GET requests for the same URL that should be cached using the same
       
 17776      * cache, but the cache is not populated yet, only one request to the server will be made and
       
 17777      * the remaining requests will be fulfilled using the response from the first request.
       
 17778      *
       
 17779      * You can change the default cache to a new object (built with
       
 17780      * {@link ng.$cacheFactory `$cacheFactory`}) by updating the
       
 17781      * {@link ng.$http#properties_defaults `$http.defaults.cache`} property. All requests who set
       
 17782      * their `cache` property to `true` will now use this cache object.
       
 17783      *
       
 17784      * If you set the default cache to `false` then only requests that specify their own custom
       
 17785      * cache object will be cached.
       
 17786      *
       
 17787      * ## Interceptors
       
 17788      *
       
 17789      * Before you start creating interceptors, be sure to understand the
       
 17790      * {@link ng.$q $q and deferred/promise APIs}.
       
 17791      *
       
 17792      * For purposes of global error handling, authentication, or any kind of synchronous or
       
 17793      * asynchronous pre-processing of request or postprocessing of responses, it is desirable to be
       
 17794      * able to intercept requests before they are handed to the server and
       
 17795      * responses before they are handed over to the application code that
       
 17796      * initiated these requests. The interceptors leverage the {@link ng.$q
       
 17797      * promise APIs} to fulfill this need for both synchronous and asynchronous pre-processing.
       
 17798      *
       
 17799      * The interceptors are service factories that are registered with the `$httpProvider` by
       
 17800      * adding them to the `$httpProvider.interceptors` array. The factory is called and
       
 17801      * injected with dependencies (if specified) and returns the interceptor.
       
 17802      *
       
 17803      * There are two kinds of interceptors (and two kinds of rejection interceptors):
       
 17804      *
       
 17805      *   * `request`: interceptors get called with a http `config` object. The function is free to
       
 17806      *     modify the `config` object or create a new one. The function needs to return the `config`
       
 17807      *     object directly, or a promise containing the `config` or a new `config` object.
       
 17808      *   * `requestError`: interceptor gets called when a previous interceptor threw an error or
       
 17809      *     resolved with a rejection.
       
 17810      *   * `response`: interceptors get called with http `response` object. The function is free to
       
 17811      *     modify the `response` object or create a new one. The function needs to return the `response`
       
 17812      *     object directly, or as a promise containing the `response` or a new `response` object.
       
 17813      *   * `responseError`: interceptor gets called when a previous interceptor threw an error or
       
 17814      *     resolved with a rejection.
       
 17815      *
       
 17816      *
       
 17817      * ```js
       
 17818      *   // register the interceptor as a service
       
 17819      *   $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
       
 17820      *     return {
       
 17821      *       // optional method
       
 17822      *       'request': function(config) {
       
 17823      *         // do something on success
       
 17824      *         return config;
       
 17825      *       },
       
 17826      *
       
 17827      *       // optional method
       
 17828      *      'requestError': function(rejection) {
       
 17829      *         // do something on error
       
 17830      *         if (canRecover(rejection)) {
       
 17831      *           return responseOrNewPromise
       
 17832      *         }
       
 17833      *         return $q.reject(rejection);
       
 17834      *       },
       
 17835      *
       
 17836      *
       
 17837      *
       
 17838      *       // optional method
       
 17839      *       'response': function(response) {
       
 17840      *         // do something on success
       
 17841      *         return response;
       
 17842      *       },
       
 17843      *
       
 17844      *       // optional method
       
 17845      *      'responseError': function(rejection) {
       
 17846      *         // do something on error
       
 17847      *         if (canRecover(rejection)) {
       
 17848      *           return responseOrNewPromise
       
 17849      *         }
       
 17850      *         return $q.reject(rejection);
       
 17851      *       }
       
 17852      *     };
       
 17853      *   });
       
 17854      *
       
 17855      *   $httpProvider.interceptors.push('myHttpInterceptor');
       
 17856      *
       
 17857      *
       
 17858      *   // alternatively, register the interceptor via an anonymous factory
       
 17859      *   $httpProvider.interceptors.push(function($q, dependency1, dependency2) {
       
 17860      *     return {
       
 17861      *      'request': function(config) {
       
 17862      *          // same as above
       
 17863      *       },
       
 17864      *
       
 17865      *       'response': function(response) {
       
 17866      *          // same as above
       
 17867      *       }
       
 17868      *     };
       
 17869      *   });
       
 17870      * ```
       
 17871      *
       
 17872      * ## Security Considerations
       
 17873      *
       
 17874      * When designing web applications, consider security threats from:
       
 17875      *
       
 17876      * - [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
       
 17877      * - [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery)
       
 17878      *
       
 17879      * Both server and the client must cooperate in order to eliminate these threats. Angular comes
       
 17880      * pre-configured with strategies that address these issues, but for this to work backend server
       
 17881      * cooperation is required.
       
 17882      *
       
 17883      * ### JSON Vulnerability Protection
       
 17884      *
       
 17885      * A [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
       
 17886      * allows third party website to turn your JSON resource URL into
       
 17887      * [JSONP](http://en.wikipedia.org/wiki/JSONP) request under some conditions. To
       
 17888      * counter this your server can prefix all JSON requests with following string `")]}',\n"`.
       
 17889      * Angular will automatically strip the prefix before processing it as JSON.
       
 17890      *
       
 17891      * For example if your server needs to return:
       
 17892      * ```js
       
 17893      * ['one','two']
       
 17894      * ```
       
 17895      *
       
 17896      * which is vulnerable to attack, your server can return:
       
 17897      * ```js
       
 17898      * )]}',
       
 17899      * ['one','two']
       
 17900      * ```
       
 17901      *
       
 17902      * Angular will strip the prefix, before processing the JSON.
       
 17903      *
       
 17904      *
       
 17905      * ### Cross Site Request Forgery (XSRF) Protection
       
 17906      *
       
 17907      * [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) is a technique by which
       
 17908      * an unauthorized site can gain your user's private data. Angular provides a mechanism
       
 17909      * to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie
       
 17910      * (by default, `XSRF-TOKEN`) and sets it as an HTTP header (`X-XSRF-TOKEN`). Since only
       
 17911      * JavaScript that runs on your domain could read the cookie, your server can be assured that
       
 17912      * the XHR came from JavaScript running on your domain. The header will not be set for
       
 17913      * cross-domain requests.
       
 17914      *
       
 17915      * To take advantage of this, your server needs to set a token in a JavaScript readable session
       
 17916      * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the
       
 17917      * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure
       
 17918      * that only JavaScript running on your domain could have sent the request. The token must be
       
 17919      * unique for each user and must be verifiable by the server (to prevent the JavaScript from
       
 17920      * making up its own tokens). We recommend that the token is a digest of your site's
       
 17921      * authentication cookie with a [salt](https://en.wikipedia.org/wiki/Salt_(cryptography&#41;)
       
 17922      * for added security.
       
 17923      *
       
 17924      * The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName
       
 17925      * properties of either $httpProvider.defaults at config-time, $http.defaults at run-time,
       
 17926      * or the per-request config object.
       
 17927      *
       
 17928      *
       
 17929      * @param {object} config Object describing the request to be made and how it should be
       
 17930      *    processed. The object has following properties:
       
 17931      *
       
 17932      *    - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc)
       
 17933      *    - **url** – `{string}` – Absolute or relative URL of the resource that is being requested.
       
 17934      *    - **params** – `{Object.<string|Object>}` – Map of strings or objects which will be turned
       
 17935      *      to `?key1=value1&key2=value2` after the url. If the value is not a string, it will be
       
 17936      *      JSONified.
       
 17937      *    - **data** – `{string|Object}` – Data to be sent as the request message data.
       
 17938      *    - **headers** – `{Object}` – Map of strings or functions which return strings representing
       
 17939      *      HTTP headers to send to the server. If the return value of a function is null, the
       
 17940      *      header will not be sent.
       
 17941      *    - **xsrfHeaderName** – `{string}` – Name of HTTP header to populate with the XSRF token.
       
 17942      *    - **xsrfCookieName** – `{string}` – Name of cookie containing the XSRF token.
       
 17943      *    - **transformRequest** –
       
 17944      *      `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
       
 17945      *      transform function or an array of such functions. The transform function takes the http
       
 17946      *      request body and headers and returns its transformed (typically serialized) version.
       
 17947      *      See {@link #overriding-the-default-transformations-per-request Overriding the Default Transformations}
       
 17948      *    - **transformResponse** –
       
 17949      *      `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
       
 17950      *      transform function or an array of such functions. The transform function takes the http
       
 17951      *      response body and headers and returns its transformed (typically deserialized) version.
       
 17952      *      See {@link #overriding-the-default-transformations-per-request Overriding the Default Transformations}
       
 17953      *    - **cache** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
       
 17954      *      GET request, otherwise if a cache instance built with
       
 17955      *      {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
       
 17956      *      caching.
       
 17957      *    - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise}
       
 17958      *      that should abort the request when resolved.
       
 17959      *    - **withCredentials** - `{boolean}` - whether to set the `withCredentials` flag on the
       
 17960      *      XHR object. See [requests with credentials](https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials)
       
 17961      *      for more information.
       
 17962      *    - **responseType** - `{string}` - see
       
 17963      *      [requestType](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType).
       
 17964      *
       
 17965      * @returns {HttpPromise} Returns a {@link ng.$q promise} object with the
       
 17966      *   standard `then` method and two http specific methods: `success` and `error`. The `then`
       
 17967      *   method takes two arguments a success and an error callback which will be called with a
       
 17968      *   response object. The `success` and `error` methods take a single argument - a function that
       
 17969      *   will be called when the request succeeds or fails respectively. The arguments passed into
       
 17970      *   these functions are destructured representation of the response object passed into the
       
 17971      *   `then` method. The response object has these properties:
       
 17972      *
       
 17973      *   - **data** – `{string|Object}` – The response body transformed with the transform
       
 17974      *     functions.
       
 17975      *   - **status** – `{number}` – HTTP status code of the response.
       
 17976      *   - **headers** – `{function([headerName])}` – Header getter function.
       
 17977      *   - **config** – `{Object}` – The configuration object that was used to generate the request.
       
 17978      *   - **statusText** – `{string}` – HTTP status text of the response.
       
 17979      *
       
 17980      * @property {Array.<Object>} pendingRequests Array of config objects for currently pending
       
 17981      *   requests. This is primarily meant to be used for debugging purposes.
       
 17982      *
       
 17983      *
       
 17984      * @example
       
 17985 <example module="httpExample">
       
 17986 <file name="index.html">
       
 17987   <div ng-controller="FetchController">
       
 17988     <select ng-model="method">
       
 17989       <option>GET</option>
       
 17990       <option>JSONP</option>
       
 17991     </select>
       
 17992     <input type="text" ng-model="url" size="80"/>
       
 17993     <button id="fetchbtn" ng-click="fetch()">fetch</button><br>
       
 17994     <button id="samplegetbtn" ng-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
       
 17995     <button id="samplejsonpbtn"
       
 17996       ng-click="updateModel('JSONP',
       
 17997                     'https://angularjs.org/greet.php?callback=JSON_CALLBACK&name=Super%20Hero')">
       
 17998       Sample JSONP
       
 17999     </button>
       
 18000     <button id="invalidjsonpbtn"
       
 18001       ng-click="updateModel('JSONP', 'https://angularjs.org/doesntexist&callback=JSON_CALLBACK')">
       
 18002         Invalid JSONP
       
 18003       </button>
       
 18004     <pre>http status code: {{status}}</pre>
       
 18005     <pre>http response data: {{data}}</pre>
       
 18006   </div>
       
 18007 </file>
       
 18008 <file name="script.js">
       
 18009   angular.module('httpExample', [])
       
 18010     .controller('FetchController', ['$scope', '$http', '$templateCache',
       
 18011       function($scope, $http, $templateCache) {
       
 18012         $scope.method = 'GET';
       
 18013         $scope.url = 'http-hello.html';
       
 18014 
       
 18015         $scope.fetch = function() {
       
 18016           $scope.code = null;
       
 18017           $scope.response = null;
       
 18018 
       
 18019           $http({method: $scope.method, url: $scope.url, cache: $templateCache}).
       
 18020             success(function(data, status) {
       
 18021               $scope.status = status;
       
 18022               $scope.data = data;
       
 18023             }).
       
 18024             error(function(data, status) {
       
 18025               $scope.data = data || "Request failed";
       
 18026               $scope.status = status;
       
 18027           });
       
 18028         };
       
 18029 
       
 18030         $scope.updateModel = function(method, url) {
       
 18031           $scope.method = method;
       
 18032           $scope.url = url;
       
 18033         };
       
 18034       }]);
       
 18035 </file>
       
 18036 <file name="http-hello.html">
       
 18037   Hello, $http!
       
 18038 </file>
       
 18039 <file name="protractor.js" type="protractor">
       
 18040   var status = element(by.binding('status'));
       
 18041   var data = element(by.binding('data'));
       
 18042   var fetchBtn = element(by.id('fetchbtn'));
       
 18043   var sampleGetBtn = element(by.id('samplegetbtn'));
       
 18044   var sampleJsonpBtn = element(by.id('samplejsonpbtn'));
       
 18045   var invalidJsonpBtn = element(by.id('invalidjsonpbtn'));
       
 18046 
       
 18047   it('should make an xhr GET request', function() {
       
 18048     sampleGetBtn.click();
       
 18049     fetchBtn.click();
       
 18050     expect(status.getText()).toMatch('200');
       
 18051     expect(data.getText()).toMatch(/Hello, \$http!/);
       
 18052   });
       
 18053 
       
 18054 // Commented out due to flakes. See https://github.com/angular/angular.js/issues/9185
       
 18055 // it('should make a JSONP request to angularjs.org', function() {
       
 18056 //   sampleJsonpBtn.click();
       
 18057 //   fetchBtn.click();
       
 18058 //   expect(status.getText()).toMatch('200');
       
 18059 //   expect(data.getText()).toMatch(/Super Hero!/);
       
 18060 // });
       
 18061 
       
 18062   it('should make JSONP request to invalid URL and invoke the error handler',
       
 18063       function() {
       
 18064     invalidJsonpBtn.click();
       
 18065     fetchBtn.click();
       
 18066     expect(status.getText()).toMatch('0');
       
 18067     expect(data.getText()).toMatch('Request failed');
       
 18068   });
       
 18069 </file>
       
 18070 </example>
       
 18071      */
       
 18072     function $http(requestConfig) {
       
 18073       var config = {
       
 18074         method: 'get',
       
 18075         transformRequest: defaults.transformRequest,
       
 18076         transformResponse: defaults.transformResponse
       
 18077       };
       
 18078       var headers = mergeHeaders(requestConfig);
       
 18079 
       
 18080       extend(config, requestConfig);
       
 18081       config.headers = headers;
       
 18082       config.method = uppercase(config.method);
       
 18083 
       
 18084       var serverRequest = function(config) {
       
 18085         headers = config.headers;
       
 18086         var reqData = transformData(config.data, headersGetter(headers), config.transformRequest);
       
 18087 
       
 18088         // strip content-type if data is undefined
       
 18089         if (isUndefined(reqData)) {
       
 18090           forEach(headers, function(value, header) {
       
 18091             if (lowercase(header) === 'content-type') {
       
 18092                 delete headers[header];
       
 18093             }
       
 18094           });
       
 18095         }
       
 18096 
       
 18097         if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) {
       
 18098           config.withCredentials = defaults.withCredentials;
       
 18099         }
       
 18100 
       
 18101         // send request
       
 18102         return sendReq(config, reqData, headers).then(transformResponse, transformResponse);
       
 18103       };
       
 18104 
       
 18105       var chain = [serverRequest, undefined];
       
 18106       var promise = $q.when(config);
       
 18107 
       
 18108       // apply interceptors
       
 18109       forEach(reversedInterceptors, function(interceptor) {
       
 18110         if (interceptor.request || interceptor.requestError) {
       
 18111           chain.unshift(interceptor.request, interceptor.requestError);
       
 18112         }
       
 18113         if (interceptor.response || interceptor.responseError) {
       
 18114           chain.push(interceptor.response, interceptor.responseError);
       
 18115         }
       
 18116       });
       
 18117 
       
 18118       while(chain.length) {
       
 18119         var thenFn = chain.shift();
       
 18120         var rejectFn = chain.shift();
       
 18121 
       
 18122         promise = promise.then(thenFn, rejectFn);
       
 18123       }
       
 18124 
       
 18125       promise.success = function(fn) {
       
 18126         promise.then(function(response) {
       
 18127           fn(response.data, response.status, response.headers, config);
       
 18128         });
       
 18129         return promise;
       
 18130       };
       
 18131 
       
 18132       promise.error = function(fn) {
       
 18133         promise.then(null, function(response) {
       
 18134           fn(response.data, response.status, response.headers, config);
       
 18135         });
       
 18136         return promise;
       
 18137       };
       
 18138 
       
 18139       return promise;
       
 18140 
       
 18141       function transformResponse(response) {
       
 18142         // make a copy since the response must be cacheable
       
 18143         var resp = extend({}, response, {
       
 18144           data: transformData(response.data, response.headers, config.transformResponse)
       
 18145         });
       
 18146         return (isSuccess(response.status))
       
 18147           ? resp
       
 18148           : $q.reject(resp);
       
 18149       }
       
 18150 
       
 18151       function mergeHeaders(config) {
       
 18152         var defHeaders = defaults.headers,
       
 18153             reqHeaders = extend({}, config.headers),
       
 18154             defHeaderName, lowercaseDefHeaderName, reqHeaderName;
       
 18155 
       
 18156         defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]);
       
 18157 
       
 18158         // using for-in instead of forEach to avoid unecessary iteration after header has been found
       
 18159         defaultHeadersIteration:
       
 18160         for (defHeaderName in defHeaders) {
       
 18161           lowercaseDefHeaderName = lowercase(defHeaderName);
       
 18162 
       
 18163           for (reqHeaderName in reqHeaders) {
       
 18164             if (lowercase(reqHeaderName) === lowercaseDefHeaderName) {
       
 18165               continue defaultHeadersIteration;
       
 18166             }
       
 18167           }
       
 18168 
       
 18169           reqHeaders[defHeaderName] = defHeaders[defHeaderName];
       
 18170         }
       
 18171 
       
 18172         // execute if header value is a function for merged headers
       
 18173         execHeaders(reqHeaders);
       
 18174         return reqHeaders;
       
 18175 
       
 18176         function execHeaders(headers) {
       
 18177           var headerContent;
       
 18178 
       
 18179           forEach(headers, function(headerFn, header) {
       
 18180             if (isFunction(headerFn)) {
       
 18181               headerContent = headerFn();
       
 18182               if (headerContent != null) {
       
 18183                 headers[header] = headerContent;
       
 18184               } else {
       
 18185                 delete headers[header];
       
 18186               }
       
 18187             }
       
 18188           });
       
 18189         }
       
 18190       }
       
 18191     }
       
 18192 
       
 18193     $http.pendingRequests = [];
       
 18194 
       
 18195     /**
       
 18196      * @ngdoc method
       
 18197      * @name $http#get
       
 18198      *
       
 18199      * @description
       
 18200      * Shortcut method to perform `GET` request.
       
 18201      *
       
 18202      * @param {string} url Relative or absolute URL specifying the destination of the request
       
 18203      * @param {Object=} config Optional configuration object
       
 18204      * @returns {HttpPromise} Future object
       
 18205      */
       
 18206 
       
 18207     /**
       
 18208      * @ngdoc method
       
 18209      * @name $http#delete
       
 18210      *
       
 18211      * @description
       
 18212      * Shortcut method to perform `DELETE` request.
       
 18213      *
       
 18214      * @param {string} url Relative or absolute URL specifying the destination of the request
       
 18215      * @param {Object=} config Optional configuration object
       
 18216      * @returns {HttpPromise} Future object
       
 18217      */
       
 18218 
       
 18219     /**
       
 18220      * @ngdoc method
       
 18221      * @name $http#head
       
 18222      *
       
 18223      * @description
       
 18224      * Shortcut method to perform `HEAD` request.
       
 18225      *
       
 18226      * @param {string} url Relative or absolute URL specifying the destination of the request
       
 18227      * @param {Object=} config Optional configuration object
       
 18228      * @returns {HttpPromise} Future object
       
 18229      */
       
 18230 
       
 18231     /**
       
 18232      * @ngdoc method
       
 18233      * @name $http#jsonp
       
 18234      *
       
 18235      * @description
       
 18236      * Shortcut method to perform `JSONP` request.
       
 18237      *
       
 18238      * @param {string} url Relative or absolute URL specifying the destination of the request.
       
 18239      *                     The name of the callback should be the string `JSON_CALLBACK`.
       
 18240      * @param {Object=} config Optional configuration object
       
 18241      * @returns {HttpPromise} Future object
       
 18242      */
       
 18243     createShortMethods('get', 'delete', 'head', 'jsonp');
       
 18244 
       
 18245     /**
       
 18246      * @ngdoc method
       
 18247      * @name $http#post
       
 18248      *
       
 18249      * @description
       
 18250      * Shortcut method to perform `POST` request.
       
 18251      *
       
 18252      * @param {string} url Relative or absolute URL specifying the destination of the request
       
 18253      * @param {*} data Request content
       
 18254      * @param {Object=} config Optional configuration object
       
 18255      * @returns {HttpPromise} Future object
       
 18256      */
       
 18257 
       
 18258     /**
       
 18259      * @ngdoc method
       
 18260      * @name $http#put
       
 18261      *
       
 18262      * @description
       
 18263      * Shortcut method to perform `PUT` request.
       
 18264      *
       
 18265      * @param {string} url Relative or absolute URL specifying the destination of the request
       
 18266      * @param {*} data Request content
       
 18267      * @param {Object=} config Optional configuration object
       
 18268      * @returns {HttpPromise} Future object
       
 18269      */
       
 18270 
       
 18271      /**
       
 18272       * @ngdoc method
       
 18273       * @name $http#patch
       
 18274       *
       
 18275       * @description
       
 18276       * Shortcut method to perform `PATCH` request.
       
 18277       *
       
 18278       * @param {string} url Relative or absolute URL specifying the destination of the request
       
 18279       * @param {*} data Request content
       
 18280       * @param {Object=} config Optional configuration object
       
 18281       * @returns {HttpPromise} Future object
       
 18282       */
       
 18283     createShortMethodsWithData('post', 'put', 'patch');
       
 18284 
       
 18285         /**
       
 18286          * @ngdoc property
       
 18287          * @name $http#defaults
       
 18288          *
       
 18289          * @description
       
 18290          * Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of
       
 18291          * default headers, withCredentials as well as request and response transformations.
       
 18292          *
       
 18293          * See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above.
       
 18294          */
       
 18295     $http.defaults = defaults;
       
 18296 
       
 18297 
       
 18298     return $http;
       
 18299 
       
 18300 
       
 18301     function createShortMethods(names) {
       
 18302       forEach(arguments, function(name) {
       
 18303         $http[name] = function(url, config) {
       
 18304           return $http(extend(config || {}, {
       
 18305             method: name,
       
 18306             url: url
       
 18307           }));
       
 18308         };
       
 18309       });
       
 18310     }
       
 18311 
       
 18312 
       
 18313     function createShortMethodsWithData(name) {
       
 18314       forEach(arguments, function(name) {
       
 18315         $http[name] = function(url, data, config) {
       
 18316           return $http(extend(config || {}, {
       
 18317             method: name,
       
 18318             url: url,
       
 18319             data: data
       
 18320           }));
       
 18321         };
       
 18322       });
       
 18323     }
       
 18324 
       
 18325 
       
 18326     /**
       
 18327      * Makes the request.
       
 18328      *
       
 18329      * !!! ACCESSES CLOSURE VARS:
       
 18330      * $httpBackend, defaults, $log, $rootScope, defaultCache, $http.pendingRequests
       
 18331      */
       
 18332     function sendReq(config, reqData, reqHeaders) {
       
 18333       var deferred = $q.defer(),
       
 18334           promise = deferred.promise,
       
 18335           cache,
       
 18336           cachedResp,
       
 18337           url = buildUrl(config.url, config.params);
       
 18338 
       
 18339       $http.pendingRequests.push(config);
       
 18340       promise.then(removePendingReq, removePendingReq);
       
 18341 
       
 18342 
       
 18343       if ((config.cache || defaults.cache) && config.cache !== false &&
       
 18344           (config.method === 'GET' || config.method === 'JSONP')) {
       
 18345         cache = isObject(config.cache) ? config.cache
       
 18346               : isObject(defaults.cache) ? defaults.cache
       
 18347               : defaultCache;
       
 18348       }
       
 18349 
       
 18350       if (cache) {
       
 18351         cachedResp = cache.get(url);
       
 18352         if (isDefined(cachedResp)) {
       
 18353           if (isPromiseLike(cachedResp)) {
       
 18354             // cached request has already been sent, but there is no response yet
       
 18355             cachedResp.then(removePendingReq, removePendingReq);
       
 18356             return cachedResp;
       
 18357           } else {
       
 18358             // serving from cache
       
 18359             if (isArray(cachedResp)) {
       
 18360               resolvePromise(cachedResp[1], cachedResp[0], shallowCopy(cachedResp[2]), cachedResp[3]);
       
 18361             } else {
       
 18362               resolvePromise(cachedResp, 200, {}, 'OK');
       
 18363             }
       
 18364           }
       
 18365         } else {
       
 18366           // put the promise for the non-transformed response into cache as a placeholder
       
 18367           cache.put(url, promise);
       
 18368         }
       
 18369       }
       
 18370 
       
 18371 
       
 18372       // if we won't have the response in cache, set the xsrf headers and
       
 18373       // send the request to the backend
       
 18374       if (isUndefined(cachedResp)) {
       
 18375         var xsrfValue = urlIsSameOrigin(config.url)
       
 18376             ? $browser.cookies()[config.xsrfCookieName || defaults.xsrfCookieName]
       
 18377             : undefined;
       
 18378         if (xsrfValue) {
       
 18379           reqHeaders[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue;
       
 18380         }
       
 18381 
       
 18382         $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
       
 18383             config.withCredentials, config.responseType);
       
 18384       }
       
 18385 
       
 18386       return promise;
       
 18387 
       
 18388 
       
 18389       /**
       
 18390        * Callback registered to $httpBackend():
       
 18391        *  - caches the response if desired
       
 18392        *  - resolves the raw $http promise
       
 18393        *  - calls $apply
       
 18394        */
       
 18395       function done(status, response, headersString, statusText) {
       
 18396         if (cache) {
       
 18397           if (isSuccess(status)) {
       
 18398             cache.put(url, [status, response, parseHeaders(headersString), statusText]);
       
 18399           } else {
       
 18400             // remove promise from the cache
       
 18401             cache.remove(url);
       
 18402           }
       
 18403         }
       
 18404 
       
 18405         function resolveHttpPromise() {
       
 18406           resolvePromise(response, status, headersString, statusText);
       
 18407         }
       
 18408 
       
 18409         if (useApplyAsync) {
       
 18410           $rootScope.$applyAsync(resolveHttpPromise);
       
 18411         } else {
       
 18412           resolveHttpPromise();
       
 18413           if (!$rootScope.$$phase) $rootScope.$apply();
       
 18414         }
       
 18415       }
       
 18416 
       
 18417 
       
 18418       /**
       
 18419        * Resolves the raw $http promise.
       
 18420        */
       
 18421       function resolvePromise(response, status, headers, statusText) {
       
 18422         // normalize internal statuses to 0
       
 18423         status = Math.max(status, 0);
       
 18424 
       
 18425         (isSuccess(status) ? deferred.resolve : deferred.reject)({
       
 18426           data: response,
       
 18427           status: status,
       
 18428           headers: headersGetter(headers),
       
 18429           config: config,
       
 18430           statusText : statusText
       
 18431         });
       
 18432       }
       
 18433 
       
 18434 
       
 18435       function removePendingReq() {
       
 18436         var idx = $http.pendingRequests.indexOf(config);
       
 18437         if (idx !== -1) $http.pendingRequests.splice(idx, 1);
       
 18438       }
       
 18439     }
       
 18440 
       
 18441 
       
 18442     function buildUrl(url, params) {
       
 18443       if (!params) return url;
       
 18444       var parts = [];
       
 18445       forEachSorted(params, function(value, key) {
       
 18446         if (value === null || isUndefined(value)) return;
       
 18447         if (!isArray(value)) value = [value];
       
 18448 
       
 18449         forEach(value, function(v) {
       
 18450           if (isObject(v)) {
       
 18451             if (isDate(v)){
       
 18452               v = v.toISOString();
       
 18453             } else {
       
 18454               v = toJson(v);
       
 18455             }
       
 18456           }
       
 18457           parts.push(encodeUriQuery(key) + '=' +
       
 18458                      encodeUriQuery(v));
       
 18459         });
       
 18460       });
       
 18461       if(parts.length > 0) {
       
 18462         url += ((url.indexOf('?') == -1) ? '?' : '&') + parts.join('&');
       
 18463       }
       
 18464       return url;
       
 18465     }
       
 18466   }];
       
 18467 }
       
 18468 
       
 18469 function createXhr() {
       
 18470     return new window.XMLHttpRequest();
       
 18471 }
       
 18472 
       
 18473 /**
       
 18474  * @ngdoc service
       
 18475  * @name $httpBackend
       
 18476  * @requires $window
       
 18477  * @requires $document
       
 18478  *
       
 18479  * @description
       
 18480  * HTTP backend used by the {@link ng.$http service} that delegates to
       
 18481  * XMLHttpRequest object or JSONP and deals with browser incompatibilities.
       
 18482  *
       
 18483  * You should never need to use this service directly, instead use the higher-level abstractions:
       
 18484  * {@link ng.$http $http} or {@link ngResource.$resource $resource}.
       
 18485  *
       
 18486  * During testing this implementation is swapped with {@link ngMock.$httpBackend mock
       
 18487  * $httpBackend} which can be trained with responses.
       
 18488  */
       
 18489 function $HttpBackendProvider() {
       
 18490   this.$get = ['$browser', '$window', '$document', function($browser, $window, $document) {
       
 18491     return createHttpBackend($browser, createXhr, $browser.defer, $window.angular.callbacks, $document[0]);
       
 18492   }];
       
 18493 }
       
 18494 
       
 18495 function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) {
       
 18496   // TODO(vojta): fix the signature
       
 18497   return function(method, url, post, callback, headers, timeout, withCredentials, responseType) {
       
 18498     $browser.$$incOutstandingRequestCount();
       
 18499     url = url || $browser.url();
       
 18500 
       
 18501     if (lowercase(method) == 'jsonp') {
       
 18502       var callbackId = '_' + (callbacks.counter++).toString(36);
       
 18503       callbacks[callbackId] = function(data) {
       
 18504         callbacks[callbackId].data = data;
       
 18505         callbacks[callbackId].called = true;
       
 18506       };
       
 18507 
       
 18508       var jsonpDone = jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId),
       
 18509           callbackId, function(status, text) {
       
 18510         completeRequest(callback, status, callbacks[callbackId].data, "", text);
       
 18511         callbacks[callbackId] = noop;
       
 18512       });
       
 18513     } else {
       
 18514 
       
 18515       var xhr = createXhr();
       
 18516 
       
 18517       xhr.open(method, url, true);
       
 18518       forEach(headers, function(value, key) {
       
 18519         if (isDefined(value)) {
       
 18520             xhr.setRequestHeader(key, value);
       
 18521         }
       
 18522       });
       
 18523 
       
 18524       xhr.onload = function requestLoaded() {
       
 18525         var statusText = xhr.statusText || '';
       
 18526 
       
 18527         // responseText is the old-school way of retrieving response (supported by IE8 & 9)
       
 18528         // response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
       
 18529         var response = ('response' in xhr) ? xhr.response : xhr.responseText;
       
 18530 
       
 18531         // normalize IE9 bug (http://bugs.jquery.com/ticket/1450)
       
 18532         var status = xhr.status === 1223 ? 204 : xhr.status;
       
 18533 
       
 18534         // fix status code when it is 0 (0 status is undocumented).
       
 18535         // Occurs when accessing file resources or on Android 4.1 stock browser
       
 18536         // while retrieving files from application cache.
       
 18537         if (status === 0) {
       
 18538           status = response ? 200 : urlResolve(url).protocol == 'file' ? 404 : 0;
       
 18539         }
       
 18540 
       
 18541         completeRequest(callback,
       
 18542             status,
       
 18543             response,
       
 18544             xhr.getAllResponseHeaders(),
       
 18545             statusText);
       
 18546       };
       
 18547 
       
 18548       var requestError = function () {
       
 18549         // The response is always empty
       
 18550         // See https://xhr.spec.whatwg.org/#request-error-steps and https://fetch.spec.whatwg.org/#concept-network-error
       
 18551         completeRequest(callback, -1, null, null, '');
       
 18552       };
       
 18553 
       
 18554       xhr.onerror = requestError;
       
 18555       xhr.onabort = requestError;
       
 18556 
       
 18557       if (withCredentials) {
       
 18558         xhr.withCredentials = true;
       
 18559       }
       
 18560 
       
 18561       if (responseType) {
       
 18562         try {
       
 18563           xhr.responseType = responseType;
       
 18564         } catch (e) {
       
 18565           // WebKit added support for the json responseType value on 09/03/2013
       
 18566           // https://bugs.webkit.org/show_bug.cgi?id=73648. Versions of Safari prior to 7 are
       
 18567           // known to throw when setting the value "json" as the response type. Other older
       
 18568           // browsers implementing the responseType
       
 18569           //
       
 18570           // The json response type can be ignored if not supported, because JSON payloads are
       
 18571           // parsed on the client-side regardless.
       
 18572           if (responseType !== 'json') {
       
 18573             throw e;
       
 18574           }
       
 18575         }
       
 18576       }
       
 18577 
       
 18578       xhr.send(post || null);
       
 18579     }
       
 18580 
       
 18581     if (timeout > 0) {
       
 18582       var timeoutId = $browserDefer(timeoutRequest, timeout);
       
 18583     } else if (isPromiseLike(timeout)) {
       
 18584       timeout.then(timeoutRequest);
       
 18585     }
       
 18586 
       
 18587 
       
 18588     function timeoutRequest() {
       
 18589       jsonpDone && jsonpDone();
       
 18590       xhr && xhr.abort();
       
 18591     }
       
 18592 
       
 18593     function completeRequest(callback, status, response, headersString, statusText) {
       
 18594       // cancel timeout and subsequent timeout promise resolution
       
 18595       timeoutId && $browserDefer.cancel(timeoutId);
       
 18596       jsonpDone = xhr = null;
       
 18597 
       
 18598       callback(status, response, headersString, statusText);
       
 18599       $browser.$$completeOutstandingRequest(noop);
       
 18600     }
       
 18601   };
       
 18602 
       
 18603   function jsonpReq(url, callbackId, done) {
       
 18604     // we can't use jQuery/jqLite here because jQuery does crazy shit with script elements, e.g.:
       
 18605     // - fetches local scripts via XHR and evals them
       
 18606     // - adds and immediately removes script elements from the document
       
 18607     var script = rawDocument.createElement('script'), callback = null;
       
 18608     script.type = "text/javascript";
       
 18609     script.src = url;
       
 18610     script.async = true;
       
 18611 
       
 18612     callback = function(event) {
       
 18613       removeEventListenerFn(script, "load", callback);
       
 18614       removeEventListenerFn(script, "error", callback);
       
 18615       rawDocument.body.removeChild(script);
       
 18616       script = null;
       
 18617       var status = -1;
       
 18618       var text = "unknown";
       
 18619 
       
 18620       if (event) {
       
 18621         if (event.type === "load" && !callbacks[callbackId].called) {
       
 18622           event = { type: "error" };
       
 18623         }
       
 18624         text = event.type;
       
 18625         status = event.type === "error" ? 404 : 200;
       
 18626       }
       
 18627 
       
 18628       if (done) {
       
 18629         done(status, text);
       
 18630       }
       
 18631     };
       
 18632 
       
 18633     addEventListenerFn(script, "load", callback);
       
 18634     addEventListenerFn(script, "error", callback);
       
 18635     rawDocument.body.appendChild(script);
       
 18636     return callback;
       
 18637   }
       
 18638 }
       
 18639 
       
 18640 var $interpolateMinErr = minErr('$interpolate');
       
 18641 
       
 18642 /**
       
 18643  * @ngdoc provider
       
 18644  * @name $interpolateProvider
       
 18645  *
       
 18646  * @description
       
 18647  *
       
 18648  * Used for configuring the interpolation markup. Defaults to `{{` and `}}`.
       
 18649  *
       
 18650  * @example
       
 18651 <example module="customInterpolationApp">
       
 18652 <file name="index.html">
       
 18653 <script>
       
 18654   var customInterpolationApp = angular.module('customInterpolationApp', []);
       
 18655 
       
 18656   customInterpolationApp.config(function($interpolateProvider) {
       
 18657     $interpolateProvider.startSymbol('//');
       
 18658     $interpolateProvider.endSymbol('//');
       
 18659   });
       
 18660 
       
 18661 
       
 18662   customInterpolationApp.controller('DemoController', function() {
       
 18663       this.label = "This binding is brought you by // interpolation symbols.";
       
 18664   });
       
 18665 </script>
       
 18666 <div ng-app="App" ng-controller="DemoController as demo">
       
 18667     //demo.label//
       
 18668 </div>
       
 18669 </file>
       
 18670 <file name="protractor.js" type="protractor">
       
 18671   it('should interpolate binding with custom symbols', function() {
       
 18672     expect(element(by.binding('demo.label')).getText()).toBe('This binding is brought you by // interpolation symbols.');
       
 18673   });
       
 18674 </file>
       
 18675 </example>
       
 18676  */
       
 18677 function $InterpolateProvider() {
       
 18678   var startSymbol = '{{';
       
 18679   var endSymbol = '}}';
       
 18680 
       
 18681   /**
       
 18682    * @ngdoc method
       
 18683    * @name $interpolateProvider#startSymbol
       
 18684    * @description
       
 18685    * Symbol to denote start of expression in the interpolated string. Defaults to `{{`.
       
 18686    *
       
 18687    * @param {string=} value new value to set the starting symbol to.
       
 18688    * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
       
 18689    */
       
 18690   this.startSymbol = function(value){
       
 18691     if (value) {
       
 18692       startSymbol = value;
       
 18693       return this;
       
 18694     } else {
       
 18695       return startSymbol;
       
 18696     }
       
 18697   };
       
 18698 
       
 18699   /**
       
 18700    * @ngdoc method
       
 18701    * @name $interpolateProvider#endSymbol
       
 18702    * @description
       
 18703    * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
       
 18704    *
       
 18705    * @param {string=} value new value to set the ending symbol to.
       
 18706    * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
       
 18707    */
       
 18708   this.endSymbol = function(value){
       
 18709     if (value) {
       
 18710       endSymbol = value;
       
 18711       return this;
       
 18712     } else {
       
 18713       return endSymbol;
       
 18714     }
       
 18715   };
       
 18716 
       
 18717 
       
 18718   this.$get = ['$parse', '$exceptionHandler', '$sce', function($parse, $exceptionHandler, $sce) {
       
 18719     var startSymbolLength = startSymbol.length,
       
 18720         endSymbolLength = endSymbol.length,
       
 18721         escapedStartRegexp = new RegExp(startSymbol.replace(/./g, escape), 'g'),
       
 18722         escapedEndRegexp = new RegExp(endSymbol.replace(/./g, escape), 'g');
       
 18723 
       
 18724     function escape(ch) {
       
 18725       return '\\\\\\' + ch;
       
 18726     }
       
 18727 
       
 18728     /**
       
 18729      * @ngdoc service
       
 18730      * @name $interpolate
       
 18731      * @kind function
       
 18732      *
       
 18733      * @requires $parse
       
 18734      * @requires $sce
       
 18735      *
       
 18736      * @description
       
 18737      *
       
 18738      * Compiles a string with markup into an interpolation function. This service is used by the
       
 18739      * HTML {@link ng.$compile $compile} service for data binding. See
       
 18740      * {@link ng.$interpolateProvider $interpolateProvider} for configuring the
       
 18741      * interpolation markup.
       
 18742      *
       
 18743      *
       
 18744      * ```js
       
 18745      *   var $interpolate = ...; // injected
       
 18746      *   var exp = $interpolate('Hello {{name | uppercase}}!');
       
 18747      *   expect(exp({name:'Angular'}).toEqual('Hello ANGULAR!');
       
 18748      * ```
       
 18749      *
       
 18750      * `$interpolate` takes an optional fourth argument, `allOrNothing`. If `allOrNothing` is
       
 18751      * `true`, the interpolation function will return `undefined` unless all embedded expressions
       
 18752      * evaluate to a value other than `undefined`.
       
 18753      *
       
 18754      * ```js
       
 18755      *   var $interpolate = ...; // injected
       
 18756      *   var context = {greeting: 'Hello', name: undefined };
       
 18757      *
       
 18758      *   // default "forgiving" mode
       
 18759      *   var exp = $interpolate('{{greeting}} {{name}}!');
       
 18760      *   expect(exp(context)).toEqual('Hello !');
       
 18761      *
       
 18762      *   // "allOrNothing" mode
       
 18763      *   exp = $interpolate('{{greeting}} {{name}}!', false, null, true);
       
 18764      *   expect(exp(context)).toBeUndefined();
       
 18765      *   context.name = 'Angular';
       
 18766      *   expect(exp(context)).toEqual('Hello Angular!');
       
 18767      * ```
       
 18768      *
       
 18769      * `allOrNothing` is useful for interpolating URLs. `ngSrc` and `ngSrcset` use this behavior.
       
 18770      *
       
 18771      * ####Escaped Interpolation
       
 18772      * $interpolate provides a mechanism for escaping interpolation markers. Start and end markers
       
 18773      * can be escaped by preceding each of their characters with a REVERSE SOLIDUS U+005C (backslash).
       
 18774      * It will be rendered as a regular start/end marker, and will not be interpreted as an expression
       
 18775      * or binding.
       
 18776      *
       
 18777      * This enables web-servers to prevent script injection attacks and defacing attacks, to some
       
 18778      * degree, while also enabling code examples to work without relying on the
       
 18779      * {@link ng.directive:ngNonBindable ngNonBindable} directive.
       
 18780      *
       
 18781      * **For security purposes, it is strongly encouraged that web servers escape user-supplied data,
       
 18782      * replacing angle brackets (&lt;, &gt;) with &amp;lt; and &amp;gt; respectively, and replacing all
       
 18783      * interpolation start/end markers with their escaped counterparts.**
       
 18784      *
       
 18785      * Escaped interpolation markers are only replaced with the actual interpolation markers in rendered
       
 18786      * output when the $interpolate service processes the text. So, for HTML elements interpolated
       
 18787      * by {@link ng.$compile $compile}, or otherwise interpolated with the `mustHaveExpression` parameter
       
 18788      * set to `true`, the interpolated text must contain an unescaped interpolation expression. As such,
       
 18789      * this is typically useful only when user-data is used in rendering a template from the server, or
       
 18790      * when otherwise untrusted data is used by a directive.
       
 18791      *
       
 18792      * <example>
       
 18793      *  <file name="index.html">
       
 18794      *    <div ng-init="username='A user'">
       
 18795      *      <p ng-init="apptitle='Escaping demo'">{{apptitle}}: \{\{ username = "defaced value"; \}\}
       
 18796      *        </p>
       
 18797      *      <p><strong>{{username}}</strong> attempts to inject code which will deface the
       
 18798      *        application, but fails to accomplish their task, because the server has correctly
       
 18799      *        escaped the interpolation start/end markers with REVERSE SOLIDUS U+005C (backslash)
       
 18800      *        characters.</p>
       
 18801      *      <p>Instead, the result of the attempted script injection is visible, and can be removed
       
 18802      *        from the database by an administrator.</p>
       
 18803      *    </div>
       
 18804      *  </file>
       
 18805      * </example>
       
 18806      *
       
 18807      * @param {string} text The text with markup to interpolate.
       
 18808      * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
       
 18809      *    embedded expression in order to return an interpolation function. Strings with no
       
 18810      *    embedded expression will return null for the interpolation function.
       
 18811      * @param {string=} trustedContext when provided, the returned function passes the interpolated
       
 18812      *    result through {@link ng.$sce#getTrusted $sce.getTrusted(interpolatedResult,
       
 18813      *    trustedContext)} before returning it.  Refer to the {@link ng.$sce $sce} service that
       
 18814      *    provides Strict Contextual Escaping for details.
       
 18815      * @param {boolean=} allOrNothing if `true`, then the returned function returns undefined
       
 18816      *    unless all embedded expressions evaluate to a value other than `undefined`.
       
 18817      * @returns {function(context)} an interpolation function which is used to compute the
       
 18818      *    interpolated string. The function has these parameters:
       
 18819      *
       
 18820      * - `context`: evaluation context for all expressions embedded in the interpolated text
       
 18821      */
       
 18822     function $interpolate(text, mustHaveExpression, trustedContext, allOrNothing) {
       
 18823       allOrNothing = !!allOrNothing;
       
 18824       var startIndex,
       
 18825           endIndex,
       
 18826           index = 0,
       
 18827           expressions = [],
       
 18828           parseFns = [],
       
 18829           textLength = text.length,
       
 18830           exp,
       
 18831           concat = [],
       
 18832           expressionPositions = [];
       
 18833 
       
 18834       while(index < textLength) {
       
 18835         if ( ((startIndex = text.indexOf(startSymbol, index)) != -1) &&
       
 18836              ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1) ) {
       
 18837           if (index !== startIndex) {
       
 18838             concat.push(unescapeText(text.substring(index, startIndex)));
       
 18839           }
       
 18840           exp = text.substring(startIndex + startSymbolLength, endIndex);
       
 18841           expressions.push(exp);
       
 18842           parseFns.push($parse(exp, parseStringifyInterceptor));
       
 18843           index = endIndex + endSymbolLength;
       
 18844           expressionPositions.push(concat.length);
       
 18845           concat.push('');
       
 18846         } else {
       
 18847           // we did not find an interpolation, so we have to add the remainder to the separators array
       
 18848           if (index !== textLength) {
       
 18849             concat.push(unescapeText(text.substring(index)));
       
 18850           }
       
 18851           break;
       
 18852         }
       
 18853       }
       
 18854 
       
 18855       // Concatenating expressions makes it hard to reason about whether some combination of
       
 18856       // concatenated values are unsafe to use and could easily lead to XSS.  By requiring that a
       
 18857       // single expression be used for iframe[src], object[src], etc., we ensure that the value
       
 18858       // that's used is assigned or constructed by some JS code somewhere that is more testable or
       
 18859       // make it obvious that you bound the value to some user controlled value.  This helps reduce
       
 18860       // the load when auditing for XSS issues.
       
 18861       if (trustedContext && concat.length > 1) {
       
 18862           throw $interpolateMinErr('noconcat',
       
 18863               "Error while interpolating: {0}\nStrict Contextual Escaping disallows " +
       
 18864               "interpolations that concatenate multiple expressions when a trusted value is " +
       
 18865               "required.  See http://docs.angularjs.org/api/ng.$sce", text);
       
 18866       }
       
 18867 
       
 18868       if (!mustHaveExpression || expressions.length) {
       
 18869         var compute = function(values) {
       
 18870           for(var i = 0, ii = expressions.length; i < ii; i++) {
       
 18871             if (allOrNothing && isUndefined(values[i])) return;
       
 18872             concat[expressionPositions[i]] = values[i];
       
 18873           }
       
 18874           return concat.join('');
       
 18875         };
       
 18876 
       
 18877         var getValue = function (value) {
       
 18878           return trustedContext ?
       
 18879             $sce.getTrusted(trustedContext, value) :
       
 18880             $sce.valueOf(value);
       
 18881         };
       
 18882 
       
 18883         var stringify = function (value) {
       
 18884           if (value == null) { // null || undefined
       
 18885             return '';
       
 18886           }
       
 18887           switch (typeof value) {
       
 18888             case 'string': {
       
 18889               break;
       
 18890             }
       
 18891             case 'number': {
       
 18892               value = '' + value;
       
 18893               break;
       
 18894             }
       
 18895             default: {
       
 18896               value = toJson(value);
       
 18897             }
       
 18898           }
       
 18899 
       
 18900           return value;
       
 18901         };
       
 18902 
       
 18903         return extend(function interpolationFn(context) {
       
 18904             var i = 0;
       
 18905             var ii = expressions.length;
       
 18906             var values = new Array(ii);
       
 18907 
       
 18908             try {
       
 18909               for (; i < ii; i++) {
       
 18910                 values[i] = parseFns[i](context);
       
 18911               }
       
 18912 
       
 18913               return compute(values);
       
 18914             } catch(err) {
       
 18915               var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text,
       
 18916                   err.toString());
       
 18917               $exceptionHandler(newErr);
       
 18918             }
       
 18919 
       
 18920           }, {
       
 18921           // all of these properties are undocumented for now
       
 18922           exp: text, //just for compatibility with regular watchers created via $watch
       
 18923           expressions: expressions,
       
 18924           $$watchDelegate: function (scope, listener, objectEquality) {
       
 18925             var lastValue;
       
 18926             return scope.$watchGroup(parseFns, function interpolateFnWatcher(values, oldValues) {
       
 18927               var currValue = compute(values);
       
 18928               if (isFunction(listener)) {
       
 18929                 listener.call(this, currValue, values !== oldValues ? lastValue : currValue, scope);
       
 18930               }
       
 18931               lastValue = currValue;
       
 18932             }, objectEquality);
       
 18933           }
       
 18934         });
       
 18935       }
       
 18936 
       
 18937       function unescapeText(text) {
       
 18938         return text.replace(escapedStartRegexp, startSymbol).
       
 18939           replace(escapedEndRegexp, endSymbol);
       
 18940       }
       
 18941 
       
 18942       function parseStringifyInterceptor(value) {
       
 18943         try {
       
 18944           return stringify(getValue(value));
       
 18945         } catch(err) {
       
 18946           var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text,
       
 18947             err.toString());
       
 18948           $exceptionHandler(newErr);
       
 18949         }
       
 18950       }
       
 18951     }
       
 18952 
       
 18953 
       
 18954     /**
       
 18955      * @ngdoc method
       
 18956      * @name $interpolate#startSymbol
       
 18957      * @description
       
 18958      * Symbol to denote the start of expression in the interpolated string. Defaults to `{{`.
       
 18959      *
       
 18960      * Use {@link ng.$interpolateProvider#startSymbol `$interpolateProvider.startSymbol`} to change
       
 18961      * the symbol.
       
 18962      *
       
 18963      * @returns {string} start symbol.
       
 18964      */
       
 18965     $interpolate.startSymbol = function() {
       
 18966       return startSymbol;
       
 18967     };
       
 18968 
       
 18969 
       
 18970     /**
       
 18971      * @ngdoc method
       
 18972      * @name $interpolate#endSymbol
       
 18973      * @description
       
 18974      * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
       
 18975      *
       
 18976      * Use {@link ng.$interpolateProvider#endSymbol `$interpolateProvider.endSymbol`} to change
       
 18977      * the symbol.
       
 18978      *
       
 18979      * @returns {string} end symbol.
       
 18980      */
       
 18981     $interpolate.endSymbol = function() {
       
 18982       return endSymbol;
       
 18983     };
       
 18984 
       
 18985     return $interpolate;
       
 18986   }];
       
 18987 }
       
 18988 
       
 18989 function $IntervalProvider() {
       
 18990   this.$get = ['$rootScope', '$window', '$q', '$$q',
       
 18991        function($rootScope,   $window,   $q,   $$q) {
       
 18992     var intervals = {};
       
 18993 
       
 18994 
       
 18995      /**
       
 18996       * @ngdoc service
       
 18997       * @name $interval
       
 18998       *
       
 18999       * @description
       
 19000       * Angular's wrapper for `window.setInterval`. The `fn` function is executed every `delay`
       
 19001       * milliseconds.
       
 19002       *
       
 19003       * The return value of registering an interval function is a promise. This promise will be
       
 19004       * notified upon each tick of the interval, and will be resolved after `count` iterations, or
       
 19005       * run indefinitely if `count` is not defined. The value of the notification will be the
       
 19006       * number of iterations that have run.
       
 19007       * To cancel an interval, call `$interval.cancel(promise)`.
       
 19008       *
       
 19009       * In tests you can use {@link ngMock.$interval#flush `$interval.flush(millis)`} to
       
 19010       * move forward by `millis` milliseconds and trigger any functions scheduled to run in that
       
 19011       * time.
       
 19012       *
       
 19013       * <div class="alert alert-warning">
       
 19014       * **Note**: Intervals created by this service must be explicitly destroyed when you are finished
       
 19015       * with them.  In particular they are not automatically destroyed when a controller's scope or a
       
 19016       * directive's element are destroyed.
       
 19017       * You should take this into consideration and make sure to always cancel the interval at the
       
 19018       * appropriate moment.  See the example below for more details on how and when to do this.
       
 19019       * </div>
       
 19020       *
       
 19021       * @param {function()} fn A function that should be called repeatedly.
       
 19022       * @param {number} delay Number of milliseconds between each function call.
       
 19023       * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat
       
 19024       *   indefinitely.
       
 19025       * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
       
 19026       *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
       
 19027       * @returns {promise} A promise which will be notified on each iteration.
       
 19028       *
       
 19029       * @example
       
 19030       * <example module="intervalExample">
       
 19031       * <file name="index.html">
       
 19032       *   <script>
       
 19033       *     angular.module('intervalExample', [])
       
 19034       *       .controller('ExampleController', ['$scope', '$interval',
       
 19035       *         function($scope, $interval) {
       
 19036       *           $scope.format = 'M/d/yy h:mm:ss a';
       
 19037       *           $scope.blood_1 = 100;
       
 19038       *           $scope.blood_2 = 120;
       
 19039       *
       
 19040       *           var stop;
       
 19041       *           $scope.fight = function() {
       
 19042       *             // Don't start a new fight if we are already fighting
       
 19043       *             if ( angular.isDefined(stop) ) return;
       
 19044       *
       
 19045       *           stop = $interval(function() {
       
 19046       *             if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
       
 19047       *               $scope.blood_1 = $scope.blood_1 - 3;
       
 19048       *               $scope.blood_2 = $scope.blood_2 - 4;
       
 19049       *             } else {
       
 19050       *               $scope.stopFight();
       
 19051       *             }
       
 19052       *           }, 100);
       
 19053       *         };
       
 19054       *
       
 19055       *         $scope.stopFight = function() {
       
 19056       *           if (angular.isDefined(stop)) {
       
 19057       *             $interval.cancel(stop);
       
 19058       *             stop = undefined;
       
 19059       *           }
       
 19060       *         };
       
 19061       *
       
 19062       *         $scope.resetFight = function() {
       
 19063       *           $scope.blood_1 = 100;
       
 19064       *           $scope.blood_2 = 120;
       
 19065       *         };
       
 19066       *
       
 19067       *         $scope.$on('$destroy', function() {
       
 19068       *           // Make sure that the interval is destroyed too
       
 19069       *           $scope.stopFight();
       
 19070       *         });
       
 19071       *       }])
       
 19072       *       // Register the 'myCurrentTime' directive factory method.
       
 19073       *       // We inject $interval and dateFilter service since the factory method is DI.
       
 19074       *       .directive('myCurrentTime', ['$interval', 'dateFilter',
       
 19075       *         function($interval, dateFilter) {
       
 19076       *           // return the directive link function. (compile function not needed)
       
 19077       *           return function(scope, element, attrs) {
       
 19078       *             var format,  // date format
       
 19079       *                 stopTime; // so that we can cancel the time updates
       
 19080       *
       
 19081       *             // used to update the UI
       
 19082       *             function updateTime() {
       
 19083       *               element.text(dateFilter(new Date(), format));
       
 19084       *             }
       
 19085       *
       
 19086       *             // watch the expression, and update the UI on change.
       
 19087       *             scope.$watch(attrs.myCurrentTime, function(value) {
       
 19088       *               format = value;
       
 19089       *               updateTime();
       
 19090       *             });
       
 19091       *
       
 19092       *             stopTime = $interval(updateTime, 1000);
       
 19093       *
       
 19094       *             // listen on DOM destroy (removal) event, and cancel the next UI update
       
 19095       *             // to prevent updating time after the DOM element was removed.
       
 19096       *             element.on('$destroy', function() {
       
 19097       *               $interval.cancel(stopTime);
       
 19098       *             });
       
 19099       *           }
       
 19100       *         }]);
       
 19101       *   </script>
       
 19102       *
       
 19103       *   <div>
       
 19104       *     <div ng-controller="ExampleController">
       
 19105       *       Date format: <input ng-model="format"> <hr/>
       
 19106       *       Current time is: <span my-current-time="format"></span>
       
 19107       *       <hr/>
       
 19108       *       Blood 1 : <font color='red'>{{blood_1}}</font>
       
 19109       *       Blood 2 : <font color='red'>{{blood_2}}</font>
       
 19110       *       <button type="button" data-ng-click="fight()">Fight</button>
       
 19111       *       <button type="button" data-ng-click="stopFight()">StopFight</button>
       
 19112       *       <button type="button" data-ng-click="resetFight()">resetFight</button>
       
 19113       *     </div>
       
 19114       *   </div>
       
 19115       *
       
 19116       * </file>
       
 19117       * </example>
       
 19118       */
       
 19119     function interval(fn, delay, count, invokeApply) {
       
 19120       var setInterval = $window.setInterval,
       
 19121           clearInterval = $window.clearInterval,
       
 19122           iteration = 0,
       
 19123           skipApply = (isDefined(invokeApply) && !invokeApply),
       
 19124           deferred = (skipApply ? $$q : $q).defer(),
       
 19125           promise = deferred.promise;
       
 19126 
       
 19127       count = isDefined(count) ? count : 0;
       
 19128 
       
 19129       promise.then(null, null, fn);
       
 19130 
       
 19131       promise.$$intervalId = setInterval(function tick() {
       
 19132         deferred.notify(iteration++);
       
 19133 
       
 19134         if (count > 0 && iteration >= count) {
       
 19135           deferred.resolve(iteration);
       
 19136           clearInterval(promise.$$intervalId);
       
 19137           delete intervals[promise.$$intervalId];
       
 19138         }
       
 19139 
       
 19140         if (!skipApply) $rootScope.$apply();
       
 19141 
       
 19142       }, delay);
       
 19143 
       
 19144       intervals[promise.$$intervalId] = deferred;
       
 19145 
       
 19146       return promise;
       
 19147     }
       
 19148 
       
 19149 
       
 19150      /**
       
 19151       * @ngdoc method
       
 19152       * @name $interval#cancel
       
 19153       *
       
 19154       * @description
       
 19155       * Cancels a task associated with the `promise`.
       
 19156       *
       
 19157       * @param {promise} promise returned by the `$interval` function.
       
 19158       * @returns {boolean} Returns `true` if the task was successfully canceled.
       
 19159       */
       
 19160     interval.cancel = function(promise) {
       
 19161       if (promise && promise.$$intervalId in intervals) {
       
 19162         intervals[promise.$$intervalId].reject('canceled');
       
 19163         $window.clearInterval(promise.$$intervalId);
       
 19164         delete intervals[promise.$$intervalId];
       
 19165         return true;
       
 19166       }
       
 19167       return false;
       
 19168     };
       
 19169 
       
 19170     return interval;
       
 19171   }];
       
 19172 }
       
 19173 
       
 19174 /**
       
 19175  * @ngdoc service
       
 19176  * @name $locale
       
 19177  *
       
 19178  * @description
       
 19179  * $locale service provides localization rules for various Angular components. As of right now the
       
 19180  * only public api is:
       
 19181  *
       
 19182  * * `id` – `{string}` – locale id formatted as `languageId-countryId` (e.g. `en-us`)
       
 19183  */
       
 19184 function $LocaleProvider(){
       
 19185   this.$get = function() {
       
 19186     return {
       
 19187       id: 'en-us',
       
 19188 
       
 19189       NUMBER_FORMATS: {
       
 19190         DECIMAL_SEP: '.',
       
 19191         GROUP_SEP: ',',
       
 19192         PATTERNS: [
       
 19193           { // Decimal Pattern
       
 19194             minInt: 1,
       
 19195             minFrac: 0,
       
 19196             maxFrac: 3,
       
 19197             posPre: '',
       
 19198             posSuf: '',
       
 19199             negPre: '-',
       
 19200             negSuf: '',
       
 19201             gSize: 3,
       
 19202             lgSize: 3
       
 19203           },{ //Currency Pattern
       
 19204             minInt: 1,
       
 19205             minFrac: 2,
       
 19206             maxFrac: 2,
       
 19207             posPre: '\u00A4',
       
 19208             posSuf: '',
       
 19209             negPre: '(\u00A4',
       
 19210             negSuf: ')',
       
 19211             gSize: 3,
       
 19212             lgSize: 3
       
 19213           }
       
 19214         ],
       
 19215         CURRENCY_SYM: '$'
       
 19216       },
       
 19217 
       
 19218       DATETIME_FORMATS: {
       
 19219         MONTH:
       
 19220             'January,February,March,April,May,June,July,August,September,October,November,December'
       
 19221             .split(','),
       
 19222         SHORTMONTH:  'Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec'.split(','),
       
 19223         DAY: 'Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday'.split(','),
       
 19224         SHORTDAY: 'Sun,Mon,Tue,Wed,Thu,Fri,Sat'.split(','),
       
 19225         AMPMS: ['AM','PM'],
       
 19226         medium: 'MMM d, y h:mm:ss a',
       
 19227         short: 'M/d/yy h:mm a',
       
 19228         fullDate: 'EEEE, MMMM d, y',
       
 19229         longDate: 'MMMM d, y',
       
 19230         mediumDate: 'MMM d, y',
       
 19231         shortDate: 'M/d/yy',
       
 19232         mediumTime: 'h:mm:ss a',
       
 19233         shortTime: 'h:mm a'
       
 19234       },
       
 19235 
       
 19236       pluralCat: function(num) {
       
 19237         if (num === 1) {
       
 19238           return 'one';
       
 19239         }
       
 19240         return 'other';
       
 19241       }
       
 19242     };
       
 19243   };
       
 19244 }
       
 19245 
       
 19246 var PATH_MATCH = /^([^\?#]*)(\?([^#]*))?(#(.*))?$/,
       
 19247     DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21};
       
 19248 var $locationMinErr = minErr('$location');
       
 19249 
       
 19250 
       
 19251 /**
       
 19252  * Encode path using encodeUriSegment, ignoring forward slashes
       
 19253  *
       
 19254  * @param {string} path Path to encode
       
 19255  * @returns {string}
       
 19256  */
       
 19257 function encodePath(path) {
       
 19258   var segments = path.split('/'),
       
 19259       i = segments.length;
       
 19260 
       
 19261   while (i--) {
       
 19262     segments[i] = encodeUriSegment(segments[i]);
       
 19263   }
       
 19264 
       
 19265   return segments.join('/');
       
 19266 }
       
 19267 
       
 19268 function parseAbsoluteUrl(absoluteUrl, locationObj, appBase) {
       
 19269   var parsedUrl = urlResolve(absoluteUrl, appBase);
       
 19270 
       
 19271   locationObj.$$protocol = parsedUrl.protocol;
       
 19272   locationObj.$$host = parsedUrl.hostname;
       
 19273   locationObj.$$port = int(parsedUrl.port) || DEFAULT_PORTS[parsedUrl.protocol] || null;
       
 19274 }
       
 19275 
       
 19276 
       
 19277 function parseAppUrl(relativeUrl, locationObj, appBase) {
       
 19278   var prefixed = (relativeUrl.charAt(0) !== '/');
       
 19279   if (prefixed) {
       
 19280     relativeUrl = '/' + relativeUrl;
       
 19281   }
       
 19282   var match = urlResolve(relativeUrl, appBase);
       
 19283   locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ?
       
 19284       match.pathname.substring(1) : match.pathname);
       
 19285   locationObj.$$search = parseKeyValue(match.search);
       
 19286   locationObj.$$hash = decodeURIComponent(match.hash);
       
 19287 
       
 19288   // make sure path starts with '/';
       
 19289   if (locationObj.$$path && locationObj.$$path.charAt(0) != '/') {
       
 19290     locationObj.$$path = '/' + locationObj.$$path;
       
 19291   }
       
 19292 }
       
 19293 
       
 19294 
       
 19295 /**
       
 19296  *
       
 19297  * @param {string} begin
       
 19298  * @param {string} whole
       
 19299  * @returns {string} returns text from whole after begin or undefined if it does not begin with
       
 19300  *                   expected string.
       
 19301  */
       
 19302 function beginsWith(begin, whole) {
       
 19303   if (whole.indexOf(begin) === 0) {
       
 19304     return whole.substr(begin.length);
       
 19305   }
       
 19306 }
       
 19307 
       
 19308 
       
 19309 function stripHash(url) {
       
 19310   var index = url.indexOf('#');
       
 19311   return index == -1 ? url : url.substr(0, index);
       
 19312 }
       
 19313 
       
 19314 
       
 19315 function stripFile(url) {
       
 19316   return url.substr(0, stripHash(url).lastIndexOf('/') + 1);
       
 19317 }
       
 19318 
       
 19319 /* return the server only (scheme://host:port) */
       
 19320 function serverBase(url) {
       
 19321   return url.substring(0, url.indexOf('/', url.indexOf('//') + 2));
       
 19322 }
       
 19323 
       
 19324 
       
 19325 /**
       
 19326  * LocationHtml5Url represents an url
       
 19327  * This object is exposed as $location service when HTML5 mode is enabled and supported
       
 19328  *
       
 19329  * @constructor
       
 19330  * @param {string} appBase application base URL
       
 19331  * @param {string} basePrefix url path prefix
       
 19332  */
       
 19333 function LocationHtml5Url(appBase, basePrefix) {
       
 19334   this.$$html5 = true;
       
 19335   basePrefix = basePrefix || '';
       
 19336   var appBaseNoFile = stripFile(appBase);
       
 19337   parseAbsoluteUrl(appBase, this, appBase);
       
 19338 
       
 19339 
       
 19340   /**
       
 19341    * Parse given html5 (regular) url string into properties
       
 19342    * @param {string} newAbsoluteUrl HTML5 url
       
 19343    * @private
       
 19344    */
       
 19345   this.$$parse = function(url) {
       
 19346     var pathUrl = beginsWith(appBaseNoFile, url);
       
 19347     if (!isString(pathUrl)) {
       
 19348       throw $locationMinErr('ipthprfx', 'Invalid url "{0}", missing path prefix "{1}".', url,
       
 19349           appBaseNoFile);
       
 19350     }
       
 19351 
       
 19352     parseAppUrl(pathUrl, this, appBase);
       
 19353 
       
 19354     if (!this.$$path) {
       
 19355       this.$$path = '/';
       
 19356     }
       
 19357 
       
 19358     this.$$compose();
       
 19359   };
       
 19360 
       
 19361   /**
       
 19362    * Compose url and update `absUrl` property
       
 19363    * @private
       
 19364    */
       
 19365   this.$$compose = function() {
       
 19366     var search = toKeyValue(this.$$search),
       
 19367         hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
       
 19368 
       
 19369     this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
       
 19370     this.$$absUrl = appBaseNoFile + this.$$url.substr(1); // first char is always '/'
       
 19371   };
       
 19372 
       
 19373   this.$$parseLinkUrl = function(url, relHref) {
       
 19374     if (relHref && relHref[0] === '#') {
       
 19375       // special case for links to hash fragments:
       
 19376       // keep the old url and only replace the hash fragment
       
 19377       this.hash(relHref.slice(1));
       
 19378       return true;
       
 19379     }
       
 19380     var appUrl, prevAppUrl;
       
 19381     var rewrittenUrl;
       
 19382 
       
 19383     if ( (appUrl = beginsWith(appBase, url)) !== undefined ) {
       
 19384       prevAppUrl = appUrl;
       
 19385       if ( (appUrl = beginsWith(basePrefix, appUrl)) !== undefined ) {
       
 19386         rewrittenUrl = appBaseNoFile + (beginsWith('/', appUrl) || appUrl);
       
 19387       } else {
       
 19388         rewrittenUrl = appBase + prevAppUrl;
       
 19389       }
       
 19390     } else if ( (appUrl = beginsWith(appBaseNoFile, url)) !== undefined ) {
       
 19391       rewrittenUrl = appBaseNoFile + appUrl;
       
 19392     } else if (appBaseNoFile == url + '/') {
       
 19393       rewrittenUrl = appBaseNoFile;
       
 19394     }
       
 19395     if (rewrittenUrl) {
       
 19396       this.$$parse(rewrittenUrl);
       
 19397     }
       
 19398     return !!rewrittenUrl;
       
 19399   };
       
 19400 }
       
 19401 
       
 19402 
       
 19403 /**
       
 19404  * LocationHashbangUrl represents url
       
 19405  * This object is exposed as $location service when developer doesn't opt into html5 mode.
       
 19406  * It also serves as the base class for html5 mode fallback on legacy browsers.
       
 19407  *
       
 19408  * @constructor
       
 19409  * @param {string} appBase application base URL
       
 19410  * @param {string} hashPrefix hashbang prefix
       
 19411  */
       
 19412 function LocationHashbangUrl(appBase, hashPrefix) {
       
 19413   var appBaseNoFile = stripFile(appBase);
       
 19414 
       
 19415   parseAbsoluteUrl(appBase, this, appBase);
       
 19416 
       
 19417 
       
 19418   /**
       
 19419    * Parse given hashbang url into properties
       
 19420    * @param {string} url Hashbang url
       
 19421    * @private
       
 19422    */
       
 19423   this.$$parse = function(url) {
       
 19424     var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url);
       
 19425     var withoutHashUrl = withoutBaseUrl.charAt(0) == '#'
       
 19426         ? beginsWith(hashPrefix, withoutBaseUrl)
       
 19427         : (this.$$html5)
       
 19428           ? withoutBaseUrl
       
 19429           : '';
       
 19430 
       
 19431     if (!isString(withoutHashUrl)) {
       
 19432       throw $locationMinErr('ihshprfx', 'Invalid url "{0}", missing hash prefix "{1}".', url,
       
 19433           hashPrefix);
       
 19434     }
       
 19435     parseAppUrl(withoutHashUrl, this, appBase);
       
 19436 
       
 19437     this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase);
       
 19438 
       
 19439     this.$$compose();
       
 19440 
       
 19441     /*
       
 19442      * In Windows, on an anchor node on documents loaded from
       
 19443      * the filesystem, the browser will return a pathname
       
 19444      * prefixed with the drive name ('/C:/path') when a
       
 19445      * pathname without a drive is set:
       
 19446      *  * a.setAttribute('href', '/foo')
       
 19447      *   * a.pathname === '/C:/foo' //true
       
 19448      *
       
 19449      * Inside of Angular, we're always using pathnames that
       
 19450      * do not include drive names for routing.
       
 19451      */
       
 19452     function removeWindowsDriveName (path, url, base) {
       
 19453       /*
       
 19454       Matches paths for file protocol on windows,
       
 19455       such as /C:/foo/bar, and captures only /foo/bar.
       
 19456       */
       
 19457       var windowsFilePathExp = /^\/[A-Z]:(\/.*)/;
       
 19458 
       
 19459       var firstPathSegmentMatch;
       
 19460 
       
 19461       //Get the relative path from the input URL.
       
 19462       if (url.indexOf(base) === 0) {
       
 19463         url = url.replace(base, '');
       
 19464       }
       
 19465 
       
 19466       // The input URL intentionally contains a first path segment that ends with a colon.
       
 19467       if (windowsFilePathExp.exec(url)) {
       
 19468         return path;
       
 19469       }
       
 19470 
       
 19471       firstPathSegmentMatch = windowsFilePathExp.exec(path);
       
 19472       return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path;
       
 19473     }
       
 19474   };
       
 19475 
       
 19476   /**
       
 19477    * Compose hashbang url and update `absUrl` property
       
 19478    * @private
       
 19479    */
       
 19480   this.$$compose = function() {
       
 19481     var search = toKeyValue(this.$$search),
       
 19482         hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
       
 19483 
       
 19484     this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
       
 19485     this.$$absUrl = appBase + (this.$$url ? hashPrefix + this.$$url : '');
       
 19486   };
       
 19487 
       
 19488   this.$$parseLinkUrl = function(url, relHref) {
       
 19489     if(stripHash(appBase) == stripHash(url)) {
       
 19490       this.$$parse(url);
       
 19491       return true;
       
 19492     }
       
 19493     return false;
       
 19494   };
       
 19495 }
       
 19496 
       
 19497 
       
 19498 /**
       
 19499  * LocationHashbangUrl represents url
       
 19500  * This object is exposed as $location service when html5 history api is enabled but the browser
       
 19501  * does not support it.
       
 19502  *
       
 19503  * @constructor
       
 19504  * @param {string} appBase application base URL
       
 19505  * @param {string} hashPrefix hashbang prefix
       
 19506  */
       
 19507 function LocationHashbangInHtml5Url(appBase, hashPrefix) {
       
 19508   this.$$html5 = true;
       
 19509   LocationHashbangUrl.apply(this, arguments);
       
 19510 
       
 19511   var appBaseNoFile = stripFile(appBase);
       
 19512 
       
 19513   this.$$parseLinkUrl = function(url, relHref) {
       
 19514     if (relHref && relHref[0] === '#') {
       
 19515       // special case for links to hash fragments:
       
 19516       // keep the old url and only replace the hash fragment
       
 19517       this.hash(relHref.slice(1));
       
 19518       return true;
       
 19519     }
       
 19520 
       
 19521     var rewrittenUrl;
       
 19522     var appUrl;
       
 19523 
       
 19524     if ( appBase == stripHash(url) ) {
       
 19525       rewrittenUrl = url;
       
 19526     } else if ( (appUrl = beginsWith(appBaseNoFile, url)) ) {
       
 19527       rewrittenUrl = appBase + hashPrefix + appUrl;
       
 19528     } else if ( appBaseNoFile === url + '/') {
       
 19529       rewrittenUrl = appBaseNoFile;
       
 19530     }
       
 19531     if (rewrittenUrl) {
       
 19532       this.$$parse(rewrittenUrl);
       
 19533     }
       
 19534     return !!rewrittenUrl;
       
 19535   };
       
 19536 
       
 19537   this.$$compose = function() {
       
 19538     var search = toKeyValue(this.$$search),
       
 19539         hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
       
 19540 
       
 19541     this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
       
 19542     // include hashPrefix in $$absUrl when $$url is empty so IE8 & 9 do not reload page because of removal of '#'
       
 19543     this.$$absUrl = appBase + hashPrefix + this.$$url;
       
 19544   };
       
 19545 
       
 19546 }
       
 19547 
       
 19548 
       
 19549 var locationPrototype = {
       
 19550 
       
 19551   /**
       
 19552    * Are we in html5 mode?
       
 19553    * @private
       
 19554    */
       
 19555   $$html5: false,
       
 19556 
       
 19557   /**
       
 19558    * Has any change been replacing?
       
 19559    * @private
       
 19560    */
       
 19561   $$replace: false,
       
 19562 
       
 19563   /**
       
 19564    * @ngdoc method
       
 19565    * @name $location#absUrl
       
 19566    *
       
 19567    * @description
       
 19568    * This method is getter only.
       
 19569    *
       
 19570    * Return full url representation with all segments encoded according to rules specified in
       
 19571    * [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt).
       
 19572    *
       
 19573    * @return {string} full url
       
 19574    */
       
 19575   absUrl: locationGetter('$$absUrl'),
       
 19576 
       
 19577   /**
       
 19578    * @ngdoc method
       
 19579    * @name $location#url
       
 19580    *
       
 19581    * @description
       
 19582    * This method is getter / setter.
       
 19583    *
       
 19584    * Return url (e.g. `/path?a=b#hash`) when called without any parameter.
       
 19585    *
       
 19586    * Change path, search and hash, when called with parameter and return `$location`.
       
 19587    *
       
 19588    * @param {string=} url New url without base prefix (e.g. `/path?a=b#hash`)
       
 19589    * @return {string} url
       
 19590    */
       
 19591   url: function(url) {
       
 19592     if (isUndefined(url))
       
 19593       return this.$$url;
       
 19594 
       
 19595     var match = PATH_MATCH.exec(url);
       
 19596     if (match[1]) this.path(decodeURIComponent(match[1]));
       
 19597     if (match[2] || match[1]) this.search(match[3] || '');
       
 19598     this.hash(match[5] || '');
       
 19599 
       
 19600     return this;
       
 19601   },
       
 19602 
       
 19603   /**
       
 19604    * @ngdoc method
       
 19605    * @name $location#protocol
       
 19606    *
       
 19607    * @description
       
 19608    * This method is getter only.
       
 19609    *
       
 19610    * Return protocol of current url.
       
 19611    *
       
 19612    * @return {string} protocol of current url
       
 19613    */
       
 19614   protocol: locationGetter('$$protocol'),
       
 19615 
       
 19616   /**
       
 19617    * @ngdoc method
       
 19618    * @name $location#host
       
 19619    *
       
 19620    * @description
       
 19621    * This method is getter only.
       
 19622    *
       
 19623    * Return host of current url.
       
 19624    *
       
 19625    * @return {string} host of current url.
       
 19626    */
       
 19627   host: locationGetter('$$host'),
       
 19628 
       
 19629   /**
       
 19630    * @ngdoc method
       
 19631    * @name $location#port
       
 19632    *
       
 19633    * @description
       
 19634    * This method is getter only.
       
 19635    *
       
 19636    * Return port of current url.
       
 19637    *
       
 19638    * @return {Number} port
       
 19639    */
       
 19640   port: locationGetter('$$port'),
       
 19641 
       
 19642   /**
       
 19643    * @ngdoc method
       
 19644    * @name $location#path
       
 19645    *
       
 19646    * @description
       
 19647    * This method is getter / setter.
       
 19648    *
       
 19649    * Return path of current url when called without any parameter.
       
 19650    *
       
 19651    * Change path when called with parameter and return `$location`.
       
 19652    *
       
 19653    * Note: Path should always begin with forward slash (/), this method will add the forward slash
       
 19654    * if it is missing.
       
 19655    *
       
 19656    * @param {(string|number)=} path New path
       
 19657    * @return {string} path
       
 19658    */
       
 19659   path: locationGetterSetter('$$path', function(path) {
       
 19660     path = path !== null ? path.toString() : '';
       
 19661     return path.charAt(0) == '/' ? path : '/' + path;
       
 19662   }),
       
 19663 
       
 19664   /**
       
 19665    * @ngdoc method
       
 19666    * @name $location#search
       
 19667    *
       
 19668    * @description
       
 19669    * This method is getter / setter.
       
 19670    *
       
 19671    * Return search part (as object) of current url when called without any parameter.
       
 19672    *
       
 19673    * Change search part when called with parameter and return `$location`.
       
 19674    *
       
 19675    *
       
 19676    * ```js
       
 19677    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
       
 19678    * var searchObject = $location.search();
       
 19679    * // => {foo: 'bar', baz: 'xoxo'}
       
 19680    *
       
 19681    *
       
 19682    * // set foo to 'yipee'
       
 19683    * $location.search('foo', 'yipee');
       
 19684    * // => $location
       
 19685    * ```
       
 19686    *
       
 19687    * @param {string|Object.<string>|Object.<Array.<string>>} search New search params - string or
       
 19688    * hash object.
       
 19689    *
       
 19690    * When called with a single argument the method acts as a setter, setting the `search` component
       
 19691    * of `$location` to the specified value.
       
 19692    *
       
 19693    * If the argument is a hash object containing an array of values, these values will be encoded
       
 19694    * as duplicate search parameters in the url.
       
 19695    *
       
 19696    * @param {(string|Number|Array<string>|boolean)=} paramValue If `search` is a string or number, then `paramValue`
       
 19697    * will override only a single search property.
       
 19698    *
       
 19699    * If `paramValue` is an array, it will override the property of the `search` component of
       
 19700    * `$location` specified via the first argument.
       
 19701    *
       
 19702    * If `paramValue` is `null`, the property specified via the first argument will be deleted.
       
 19703    *
       
 19704    * If `paramValue` is `true`, the property specified via the first argument will be added with no
       
 19705    * value nor trailing equal sign.
       
 19706    *
       
 19707    * @return {Object} If called with no arguments returns the parsed `search` object. If called with
       
 19708    * one or more arguments returns `$location` object itself.
       
 19709    */
       
 19710   search: function(search, paramValue) {
       
 19711     switch (arguments.length) {
       
 19712       case 0:
       
 19713         return this.$$search;
       
 19714       case 1:
       
 19715         if (isString(search) || isNumber(search)) {
       
 19716           search = search.toString();
       
 19717           this.$$search = parseKeyValue(search);
       
 19718         } else if (isObject(search)) {
       
 19719           // remove object undefined or null properties
       
 19720           forEach(search, function(value, key) {
       
 19721             if (value == null) delete search[key];
       
 19722           });
       
 19723 
       
 19724           this.$$search = search;
       
 19725         } else {
       
 19726           throw $locationMinErr('isrcharg',
       
 19727               'The first argument of the `$location#search()` call must be a string or an object.');
       
 19728         }
       
 19729         break;
       
 19730       default:
       
 19731         if (isUndefined(paramValue) || paramValue === null) {
       
 19732           delete this.$$search[search];
       
 19733         } else {
       
 19734           this.$$search[search] = paramValue;
       
 19735         }
       
 19736     }
       
 19737 
       
 19738     this.$$compose();
       
 19739     return this;
       
 19740   },
       
 19741 
       
 19742   /**
       
 19743    * @ngdoc method
       
 19744    * @name $location#hash
       
 19745    *
       
 19746    * @description
       
 19747    * This method is getter / setter.
       
 19748    *
       
 19749    * Return hash fragment when called without any parameter.
       
 19750    *
       
 19751    * Change hash fragment when called with parameter and return `$location`.
       
 19752    *
       
 19753    * @param {(string|number)=} hash New hash fragment
       
 19754    * @return {string} hash
       
 19755    */
       
 19756   hash: locationGetterSetter('$$hash', function(hash) {
       
 19757     return hash !== null ? hash.toString() : '';
       
 19758   }),
       
 19759 
       
 19760   /**
       
 19761    * @ngdoc method
       
 19762    * @name $location#replace
       
 19763    *
       
 19764    * @description
       
 19765    * If called, all changes to $location during current `$digest` will be replacing current history
       
 19766    * record, instead of adding new one.
       
 19767    */
       
 19768   replace: function() {
       
 19769     this.$$replace = true;
       
 19770     return this;
       
 19771   }
       
 19772 };
       
 19773 
       
 19774 forEach([LocationHashbangInHtml5Url, LocationHashbangUrl, LocationHtml5Url], function (Location) {
       
 19775   Location.prototype = Object.create(locationPrototype);
       
 19776 
       
 19777   /**
       
 19778    * @ngdoc method
       
 19779    * @name $location#state
       
 19780    *
       
 19781    * @description
       
 19782    * This method is getter / setter.
       
 19783    *
       
 19784    * Return the history state object when called without any parameter.
       
 19785    *
       
 19786    * Change the history state object when called with one parameter and return `$location`.
       
 19787    * The state object is later passed to `pushState` or `replaceState`.
       
 19788    *
       
 19789    * NOTE: This method is supported only in HTML5 mode and only in browsers supporting
       
 19790    * the HTML5 History API (i.e. methods `pushState` and `replaceState`). If you need to support
       
 19791    * older browsers (like IE9 or Android < 4.0), don't use this method.
       
 19792    *
       
 19793    * @param {object=} state State object for pushState or replaceState
       
 19794    * @return {object} state
       
 19795    */
       
 19796   Location.prototype.state = function(state) {
       
 19797     if (!arguments.length)
       
 19798       return this.$$state;
       
 19799 
       
 19800     if (Location !== LocationHtml5Url || !this.$$html5) {
       
 19801       throw $locationMinErr('nostate', 'History API state support is available only ' +
       
 19802         'in HTML5 mode and only in browsers supporting HTML5 History API');
       
 19803     }
       
 19804     // The user might modify `stateObject` after invoking `$location.state(stateObject)`
       
 19805     // but we're changing the $$state reference to $browser.state() during the $digest
       
 19806     // so the modification window is narrow.
       
 19807     this.$$state = isUndefined(state) ? null : state;
       
 19808 
       
 19809     return this;
       
 19810   };
       
 19811 });
       
 19812 
       
 19813 
       
 19814 function locationGetter(property) {
       
 19815   return function() {
       
 19816     return this[property];
       
 19817   };
       
 19818 }
       
 19819 
       
 19820 
       
 19821 function locationGetterSetter(property, preprocess) {
       
 19822   return function(value) {
       
 19823     if (isUndefined(value))
       
 19824       return this[property];
       
 19825 
       
 19826     this[property] = preprocess(value);
       
 19827     this.$$compose();
       
 19828 
       
 19829     return this;
       
 19830   };
       
 19831 }
       
 19832 
       
 19833 
       
 19834 /**
       
 19835  * @ngdoc service
       
 19836  * @name $location
       
 19837  *
       
 19838  * @requires $rootElement
       
 19839  *
       
 19840  * @description
       
 19841  * The $location service parses the URL in the browser address bar (based on the
       
 19842  * [window.location](https://developer.mozilla.org/en/window.location)) and makes the URL
       
 19843  * available to your application. Changes to the URL in the address bar are reflected into
       
 19844  * $location service and changes to $location are reflected into the browser address bar.
       
 19845  *
       
 19846  * **The $location service:**
       
 19847  *
       
 19848  * - Exposes the current URL in the browser address bar, so you can
       
 19849  *   - Watch and observe the URL.
       
 19850  *   - Change the URL.
       
 19851  * - Synchronizes the URL with the browser when the user
       
 19852  *   - Changes the address bar.
       
 19853  *   - Clicks the back or forward button (or clicks a History link).
       
 19854  *   - Clicks on a link.
       
 19855  * - Represents the URL object as a set of methods (protocol, host, port, path, search, hash).
       
 19856  *
       
 19857  * For more information see {@link guide/$location Developer Guide: Using $location}
       
 19858  */
       
 19859 
       
 19860 /**
       
 19861  * @ngdoc provider
       
 19862  * @name $locationProvider
       
 19863  * @description
       
 19864  * Use the `$locationProvider` to configure how the application deep linking paths are stored.
       
 19865  */
       
 19866 function $LocationProvider(){
       
 19867   var hashPrefix = '',
       
 19868       html5Mode = {
       
 19869         enabled: false,
       
 19870         requireBase: true,
       
 19871         rewriteLinks: true
       
 19872       };
       
 19873 
       
 19874   /**
       
 19875    * @ngdoc method
       
 19876    * @name $locationProvider#hashPrefix
       
 19877    * @description
       
 19878    * @param {string=} prefix Prefix for hash part (containing path and search)
       
 19879    * @returns {*} current value if used as getter or itself (chaining) if used as setter
       
 19880    */
       
 19881   this.hashPrefix = function(prefix) {
       
 19882     if (isDefined(prefix)) {
       
 19883       hashPrefix = prefix;
       
 19884       return this;
       
 19885     } else {
       
 19886       return hashPrefix;
       
 19887     }
       
 19888   };
       
 19889 
       
 19890   /**
       
 19891    * @ngdoc method
       
 19892    * @name $locationProvider#html5Mode
       
 19893    * @description
       
 19894    * @param {(boolean|Object)=} mode If boolean, sets `html5Mode.enabled` to value.
       
 19895    *   If object, sets `enabled`, `requireBase` and `rewriteLinks` to respective values. Supported
       
 19896    *   properties:
       
 19897    *   - **enabled** – `{boolean}` – (default: false) If true, will rely on `history.pushState` to
       
 19898    *     change urls where supported. Will fall back to hash-prefixed paths in browsers that do not
       
 19899    *     support `pushState`.
       
 19900    *   - **requireBase** - `{boolean}` - (default: `true`) When html5Mode is enabled, specifies
       
 19901    *     whether or not a <base> tag is required to be present. If `enabled` and `requireBase` are
       
 19902    *     true, and a base tag is not present, an error will be thrown when `$location` is injected.
       
 19903    *     See the {@link guide/$location $location guide for more information}
       
 19904    *   - **rewriteLinks** - `{boolean}` - (default: `false`) When html5Mode is enabled, disables
       
 19905    *     url rewriting for relative linksTurns off url rewriting for relative links.
       
 19906    *
       
 19907    * @returns {Object} html5Mode object if used as getter or itself (chaining) if used as setter
       
 19908    */
       
 19909   this.html5Mode = function(mode) {
       
 19910     if (isBoolean(mode)) {
       
 19911       html5Mode.enabled = mode;
       
 19912       return this;
       
 19913     } else if (isObject(mode)) {
       
 19914 
       
 19915       if (isBoolean(mode.enabled)) {
       
 19916         html5Mode.enabled =  mode.enabled;
       
 19917       }
       
 19918 
       
 19919       if (isBoolean(mode.requireBase)) {
       
 19920         html5Mode.requireBase = mode.requireBase;
       
 19921       }
       
 19922 
       
 19923       if (isBoolean(mode.rewriteLinks)) {
       
 19924         html5Mode.rewriteLinks =  mode.rewriteLinks;
       
 19925       }
       
 19926 
       
 19927       return this;
       
 19928     } else {
       
 19929       return html5Mode;
       
 19930     }
       
 19931   };
       
 19932 
       
 19933   /**
       
 19934    * @ngdoc event
       
 19935    * @name $location#$locationChangeStart
       
 19936    * @eventType broadcast on root scope
       
 19937    * @description
       
 19938    * Broadcasted before a URL will change.
       
 19939    *
       
 19940    * This change can be prevented by calling
       
 19941    * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more
       
 19942    * details about event object. Upon successful change
       
 19943    * {@link ng.$location#events_$locationChangeSuccess $locationChangeSuccess} is fired.
       
 19944    *
       
 19945    * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when
       
 19946    * the browser supports the HTML5 History API.
       
 19947    *
       
 19948    * @param {Object} angularEvent Synthetic event object.
       
 19949    * @param {string} newUrl New URL
       
 19950    * @param {string=} oldUrl URL that was before it was changed.
       
 19951    * @param {string=} newState New history state object
       
 19952    * @param {string=} oldState History state object that was before it was changed.
       
 19953    */
       
 19954 
       
 19955   /**
       
 19956    * @ngdoc event
       
 19957    * @name $location#$locationChangeSuccess
       
 19958    * @eventType broadcast on root scope
       
 19959    * @description
       
 19960    * Broadcasted after a URL was changed.
       
 19961    *
       
 19962    * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when
       
 19963    * the browser supports the HTML5 History API.
       
 19964    *
       
 19965    * @param {Object} angularEvent Synthetic event object.
       
 19966    * @param {string} newUrl New URL
       
 19967    * @param {string=} oldUrl URL that was before it was changed.
       
 19968    * @param {string=} newState New history state object
       
 19969    * @param {string=} oldState History state object that was before it was changed.
       
 19970    */
       
 19971 
       
 19972   this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement',
       
 19973       function( $rootScope,   $browser,   $sniffer,   $rootElement) {
       
 19974     var $location,
       
 19975         LocationMode,
       
 19976         baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to ''
       
 19977         initialUrl = $browser.url(),
       
 19978         appBase;
       
 19979 
       
 19980     if (html5Mode.enabled) {
       
 19981       if (!baseHref && html5Mode.requireBase) {
       
 19982         throw $locationMinErr('nobase',
       
 19983           "$location in HTML5 mode requires a <base> tag to be present!");
       
 19984       }
       
 19985       appBase = serverBase(initialUrl) + (baseHref || '/');
       
 19986       LocationMode = $sniffer.history ? LocationHtml5Url : LocationHashbangInHtml5Url;
       
 19987     } else {
       
 19988       appBase = stripHash(initialUrl);
       
 19989       LocationMode = LocationHashbangUrl;
       
 19990     }
       
 19991     $location = new LocationMode(appBase, '#' + hashPrefix);
       
 19992     $location.$$parseLinkUrl(initialUrl, initialUrl);
       
 19993 
       
 19994     $location.$$state = $browser.state();
       
 19995 
       
 19996     var IGNORE_URI_REGEXP = /^\s*(javascript|mailto):/i;
       
 19997 
       
 19998     function setBrowserUrlWithFallback(url, replace, state) {
       
 19999       var oldUrl = $location.url();
       
 20000       var oldState = $location.$$state;
       
 20001       try {
       
 20002         $browser.url(url, replace, state);
       
 20003 
       
 20004         // Make sure $location.state() returns referentially identical (not just deeply equal)
       
 20005         // state object; this makes possible quick checking if the state changed in the digest
       
 20006         // loop. Checking deep equality would be too expensive.
       
 20007         $location.$$state = $browser.state();
       
 20008       } catch (e) {
       
 20009         // Restore old values if pushState fails
       
 20010         $location.url(oldUrl);
       
 20011         $location.$$state = oldState;
       
 20012 
       
 20013         throw e;
       
 20014       }
       
 20015     }
       
 20016 
       
 20017     $rootElement.on('click', function(event) {
       
 20018       // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
       
 20019       // currently we open nice url link and redirect then
       
 20020 
       
 20021       if (!html5Mode.rewriteLinks || event.ctrlKey || event.metaKey || event.which == 2) return;
       
 20022 
       
 20023       var elm = jqLite(event.target);
       
 20024 
       
 20025       // traverse the DOM up to find first A tag
       
 20026       while (nodeName_(elm[0]) !== 'a') {
       
 20027         // ignore rewriting if no A tag (reached root element, or no parent - removed from document)
       
 20028         if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return;
       
 20029       }
       
 20030 
       
 20031       var absHref = elm.prop('href');
       
 20032       // get the actual href attribute - see
       
 20033       // http://msdn.microsoft.com/en-us/library/ie/dd347148(v=vs.85).aspx
       
 20034       var relHref = elm.attr('href') || elm.attr('xlink:href');
       
 20035 
       
 20036       if (isObject(absHref) && absHref.toString() === '[object SVGAnimatedString]') {
       
 20037         // SVGAnimatedString.animVal should be identical to SVGAnimatedString.baseVal, unless during
       
 20038         // an animation.
       
 20039         absHref = urlResolve(absHref.animVal).href;
       
 20040       }
       
 20041 
       
 20042       // Ignore when url is started with javascript: or mailto:
       
 20043       if (IGNORE_URI_REGEXP.test(absHref)) return;
       
 20044 
       
 20045       if (absHref && !elm.attr('target') && !event.isDefaultPrevented()) {
       
 20046         if ($location.$$parseLinkUrl(absHref, relHref)) {
       
 20047           // We do a preventDefault for all urls that are part of the angular application,
       
 20048           // in html5mode and also without, so that we are able to abort navigation without
       
 20049           // getting double entries in the location history.
       
 20050           event.preventDefault();
       
 20051           // update location manually
       
 20052           if ($location.absUrl() != $browser.url()) {
       
 20053             $rootScope.$apply();
       
 20054             // hack to work around FF6 bug 684208 when scenario runner clicks on links
       
 20055             window.angular['ff-684208-preventDefault'] = true;
       
 20056           }
       
 20057         }
       
 20058       }
       
 20059     });
       
 20060 
       
 20061 
       
 20062     // rewrite hashbang url <> html5 url
       
 20063     if ($location.absUrl() != initialUrl) {
       
 20064       $browser.url($location.absUrl(), true);
       
 20065     }
       
 20066 
       
 20067     var initializing = true;
       
 20068 
       
 20069     // update $location when $browser url changes
       
 20070     $browser.onUrlChange(function(newUrl, newState) {
       
 20071       $rootScope.$evalAsync(function() {
       
 20072         var oldUrl = $location.absUrl();
       
 20073         var oldState = $location.$$state;
       
 20074 
       
 20075         $location.$$parse(newUrl);
       
 20076         $location.$$state = newState;
       
 20077         if ($rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
       
 20078             newState, oldState).defaultPrevented) {
       
 20079           $location.$$parse(oldUrl);
       
 20080           $location.$$state = oldState;
       
 20081           setBrowserUrlWithFallback(oldUrl, false, oldState);
       
 20082         } else {
       
 20083           initializing = false;
       
 20084           afterLocationChange(oldUrl, oldState);
       
 20085         }
       
 20086       });
       
 20087       if (!$rootScope.$$phase) $rootScope.$digest();
       
 20088     });
       
 20089 
       
 20090     // update browser
       
 20091     $rootScope.$watch(function $locationWatch() {
       
 20092       var oldUrl = $browser.url();
       
 20093       var oldState = $browser.state();
       
 20094       var currentReplace = $location.$$replace;
       
 20095 
       
 20096       if (initializing || oldUrl !== $location.absUrl() ||
       
 20097           ($location.$$html5 && $sniffer.history && oldState !== $location.$$state)) {
       
 20098         initializing = false;
       
 20099 
       
 20100         $rootScope.$evalAsync(function() {
       
 20101           if ($rootScope.$broadcast('$locationChangeStart', $location.absUrl(), oldUrl,
       
 20102               $location.$$state, oldState).defaultPrevented) {
       
 20103             $location.$$parse(oldUrl);
       
 20104             $location.$$state = oldState;
       
 20105           } else {
       
 20106             setBrowserUrlWithFallback($location.absUrl(), currentReplace,
       
 20107                                       oldState === $location.$$state ? null : $location.$$state);
       
 20108             afterLocationChange(oldUrl, oldState);
       
 20109           }
       
 20110         });
       
 20111       }
       
 20112 
       
 20113       $location.$$replace = false;
       
 20114 
       
 20115       // we don't need to return anything because $evalAsync will make the digest loop dirty when
       
 20116       // there is a change
       
 20117     });
       
 20118 
       
 20119     return $location;
       
 20120 
       
 20121     function afterLocationChange(oldUrl, oldState) {
       
 20122       $rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl,
       
 20123         $location.$$state, oldState);
       
 20124     }
       
 20125 }];
       
 20126 }
       
 20127 
       
 20128 /**
       
 20129  * @ngdoc service
       
 20130  * @name $log
       
 20131  * @requires $window
       
 20132  *
       
 20133  * @description
       
 20134  * Simple service for logging. Default implementation safely writes the message
       
 20135  * into the browser's console (if present).
       
 20136  *
       
 20137  * The main purpose of this service is to simplify debugging and troubleshooting.
       
 20138  *
       
 20139  * The default is to log `debug` messages. You can use
       
 20140  * {@link ng.$logProvider ng.$logProvider#debugEnabled} to change this.
       
 20141  *
       
 20142  * @example
       
 20143    <example module="logExample">
       
 20144      <file name="script.js">
       
 20145        angular.module('logExample', [])
       
 20146          .controller('LogController', ['$scope', '$log', function($scope, $log) {
       
 20147            $scope.$log = $log;
       
 20148            $scope.message = 'Hello World!';
       
 20149          }]);
       
 20150      </file>
       
 20151      <file name="index.html">
       
 20152        <div ng-controller="LogController">
       
 20153          <p>Reload this page with open console, enter text and hit the log button...</p>
       
 20154          Message:
       
 20155          <input type="text" ng-model="message"/>
       
 20156          <button ng-click="$log.log(message)">log</button>
       
 20157          <button ng-click="$log.warn(message)">warn</button>
       
 20158          <button ng-click="$log.info(message)">info</button>
       
 20159          <button ng-click="$log.error(message)">error</button>
       
 20160        </div>
       
 20161      </file>
       
 20162    </example>
       
 20163  */
       
 20164 
       
 20165 /**
       
 20166  * @ngdoc provider
       
 20167  * @name $logProvider
       
 20168  * @description
       
 20169  * Use the `$logProvider` to configure how the application logs messages
       
 20170  */
       
 20171 function $LogProvider(){
       
 20172   var debug = true,
       
 20173       self = this;
       
 20174 
       
 20175   /**
       
 20176    * @ngdoc method
       
 20177    * @name $logProvider#debugEnabled
       
 20178    * @description
       
 20179    * @param {boolean=} flag enable or disable debug level messages
       
 20180    * @returns {*} current value if used as getter or itself (chaining) if used as setter
       
 20181    */
       
 20182   this.debugEnabled = function(flag) {
       
 20183     if (isDefined(flag)) {
       
 20184       debug = flag;
       
 20185     return this;
       
 20186     } else {
       
 20187       return debug;
       
 20188     }
       
 20189   };
       
 20190 
       
 20191   this.$get = ['$window', function($window){
       
 20192     return {
       
 20193       /**
       
 20194        * @ngdoc method
       
 20195        * @name $log#log
       
 20196        *
       
 20197        * @description
       
 20198        * Write a log message
       
 20199        */
       
 20200       log: consoleLog('log'),
       
 20201 
       
 20202       /**
       
 20203        * @ngdoc method
       
 20204        * @name $log#info
       
 20205        *
       
 20206        * @description
       
 20207        * Write an information message
       
 20208        */
       
 20209       info: consoleLog('info'),
       
 20210 
       
 20211       /**
       
 20212        * @ngdoc method
       
 20213        * @name $log#warn
       
 20214        *
       
 20215        * @description
       
 20216        * Write a warning message
       
 20217        */
       
 20218       warn: consoleLog('warn'),
       
 20219 
       
 20220       /**
       
 20221        * @ngdoc method
       
 20222        * @name $log#error
       
 20223        *
       
 20224        * @description
       
 20225        * Write an error message
       
 20226        */
       
 20227       error: consoleLog('error'),
       
 20228 
       
 20229       /**
       
 20230        * @ngdoc method
       
 20231        * @name $log#debug
       
 20232        *
       
 20233        * @description
       
 20234        * Write a debug message
       
 20235        */
       
 20236       debug: (function () {
       
 20237         var fn = consoleLog('debug');
       
 20238 
       
 20239         return function() {
       
 20240           if (debug) {
       
 20241             fn.apply(self, arguments);
       
 20242           }
       
 20243         };
       
 20244       }())
       
 20245     };
       
 20246 
       
 20247     function formatError(arg) {
       
 20248       if (arg instanceof Error) {
       
 20249         if (arg.stack) {
       
 20250           arg = (arg.message && arg.stack.indexOf(arg.message) === -1)
       
 20251               ? 'Error: ' + arg.message + '\n' + arg.stack
       
 20252               : arg.stack;
       
 20253         } else if (arg.sourceURL) {
       
 20254           arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line;
       
 20255         }
       
 20256       }
       
 20257       return arg;
       
 20258     }
       
 20259 
       
 20260     function consoleLog(type) {
       
 20261       var console = $window.console || {},
       
 20262           logFn = console[type] || console.log || noop,
       
 20263           hasApply = false;
       
 20264 
       
 20265       // Note: reading logFn.apply throws an error in IE11 in IE8 document mode.
       
 20266       // The reason behind this is that console.log has type "object" in IE8...
       
 20267       try {
       
 20268         hasApply = !!logFn.apply;
       
 20269       } catch (e) {}
       
 20270 
       
 20271       if (hasApply) {
       
 20272         return function() {
       
 20273           var args = [];
       
 20274           forEach(arguments, function(arg) {
       
 20275             args.push(formatError(arg));
       
 20276           });
       
 20277           return logFn.apply(console, args);
       
 20278         };
       
 20279       }
       
 20280 
       
 20281       // we are IE which either doesn't have window.console => this is noop and we do nothing,
       
 20282       // or we are IE where console.log doesn't have apply so we log at least first 2 args
       
 20283       return function(arg1, arg2) {
       
 20284         logFn(arg1, arg2 == null ? '' : arg2);
       
 20285       };
       
 20286     }
       
 20287   }];
       
 20288 }
       
 20289 
       
 20290 var $parseMinErr = minErr('$parse');
       
 20291 
       
 20292 // Sandboxing Angular Expressions
       
 20293 // ------------------------------
       
 20294 // Angular expressions are generally considered safe because these expressions only have direct
       
 20295 // access to $scope and locals. However, one can obtain the ability to execute arbitrary JS code by
       
 20296 // obtaining a reference to native JS functions such as the Function constructor.
       
 20297 //
       
 20298 // As an example, consider the following Angular expression:
       
 20299 //
       
 20300 //   {}.toString.constructor('alert("evil JS code")')
       
 20301 //
       
 20302 // This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits
       
 20303 // against the expression language, but not to prevent exploits that were enabled by exposing
       
 20304 // sensitive JavaScript or browser apis on Scope. Exposing such objects on a Scope is never a good
       
 20305 // practice and therefore we are not even trying to protect against interaction with an object
       
 20306 // explicitly exposed in this way.
       
 20307 //
       
 20308 // In general, it is not possible to access a Window object from an angular expression unless a
       
 20309 // window or some DOM object that has a reference to window is published onto a Scope.
       
 20310 // Similarly we prevent invocations of function known to be dangerous, as well as assignments to
       
 20311 // native objects.
       
 20312 
       
 20313 
       
 20314 function ensureSafeMemberName(name, fullExpression) {
       
 20315   if (name === "__defineGetter__" || name === "__defineSetter__"
       
 20316       || name === "__lookupGetter__" || name === "__lookupSetter__"
       
 20317       || name === "__proto__") {
       
 20318     throw $parseMinErr('isecfld',
       
 20319         'Attempting to access a disallowed field in Angular expressions! '
       
 20320         +'Expression: {0}', fullExpression);
       
 20321   }
       
 20322   return name;
       
 20323 }
       
 20324 
       
 20325 function ensureSafeObject(obj, fullExpression) {
       
 20326   // nifty check if obj is Function that is fast and works across iframes and other contexts
       
 20327   if (obj) {
       
 20328     if (obj.constructor === obj) {
       
 20329       throw $parseMinErr('isecfn',
       
 20330           'Referencing Function in Angular expressions is disallowed! Expression: {0}',
       
 20331           fullExpression);
       
 20332     } else if (// isWindow(obj)
       
 20333         obj.window === obj) {
       
 20334       throw $parseMinErr('isecwindow',
       
 20335           'Referencing the Window in Angular expressions is disallowed! Expression: {0}',
       
 20336           fullExpression);
       
 20337     } else if (// isElement(obj)
       
 20338         obj.children && (obj.nodeName || (obj.prop && obj.attr && obj.find))) {
       
 20339       throw $parseMinErr('isecdom',
       
 20340           'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}',
       
 20341           fullExpression);
       
 20342     } else if (// block Object so that we can't get hold of dangerous Object.* methods
       
 20343         obj === Object) {
       
 20344       throw $parseMinErr('isecobj',
       
 20345           'Referencing Object in Angular expressions is disallowed! Expression: {0}',
       
 20346           fullExpression);
       
 20347     }
       
 20348   }
       
 20349   return obj;
       
 20350 }
       
 20351 
       
 20352 var CALL = Function.prototype.call;
       
 20353 var APPLY = Function.prototype.apply;
       
 20354 var BIND = Function.prototype.bind;
       
 20355 
       
 20356 function ensureSafeFunction(obj, fullExpression) {
       
 20357   if (obj) {
       
 20358     if (obj.constructor === obj) {
       
 20359       throw $parseMinErr('isecfn',
       
 20360         'Referencing Function in Angular expressions is disallowed! Expression: {0}',
       
 20361         fullExpression);
       
 20362     } else if (obj === CALL || obj === APPLY || obj === BIND) {
       
 20363       throw $parseMinErr('isecff',
       
 20364         'Referencing call, apply or bind in Angular expressions is disallowed! Expression: {0}',
       
 20365         fullExpression);
       
 20366     }
       
 20367   }
       
 20368 }
       
 20369 
       
 20370 //Keyword constants
       
 20371 var CONSTANTS = createMap();
       
 20372 forEach({
       
 20373   'null': function() { return null; },
       
 20374   'true': function() { return true; },
       
 20375   'false': function() { return false; },
       
 20376   'undefined': function() {}
       
 20377 }, function(constantGetter, name) {
       
 20378   constantGetter.constant = constantGetter.literal = constantGetter.sharedGetter = true;
       
 20379   CONSTANTS[name] = constantGetter;
       
 20380 });
       
 20381 
       
 20382 //Not quite a constant, but can be lex/parsed the same
       
 20383 CONSTANTS['this'] = function(self) { return self; };
       
 20384 CONSTANTS['this'].sharedGetter = true;
       
 20385 
       
 20386 
       
 20387 //Operators - will be wrapped by binaryFn/unaryFn/assignment/filter
       
 20388 var OPERATORS = extend(createMap(), {
       
 20389     /* jshint bitwise : false */
       
 20390     '+':function(self, locals, a,b){
       
 20391       a=a(self, locals); b=b(self, locals);
       
 20392       if (isDefined(a)) {
       
 20393         if (isDefined(b)) {
       
 20394           return a + b;
       
 20395         }
       
 20396         return a;
       
 20397       }
       
 20398       return isDefined(b)?b:undefined;},
       
 20399     '-':function(self, locals, a,b){
       
 20400           a=a(self, locals); b=b(self, locals);
       
 20401           return (isDefined(a)?a:0)-(isDefined(b)?b:0);
       
 20402         },
       
 20403     '*':function(self, locals, a,b){return a(self, locals)*b(self, locals);},
       
 20404     '/':function(self, locals, a,b){return a(self, locals)/b(self, locals);},
       
 20405     '%':function(self, locals, a,b){return a(self, locals)%b(self, locals);},
       
 20406     '^':function(self, locals, a,b){return a(self, locals)^b(self, locals);},
       
 20407     '===':function(self, locals, a, b){return a(self, locals)===b(self, locals);},
       
 20408     '!==':function(self, locals, a, b){return a(self, locals)!==b(self, locals);},
       
 20409     '==':function(self, locals, a,b){return a(self, locals)==b(self, locals);},
       
 20410     '!=':function(self, locals, a,b){return a(self, locals)!=b(self, locals);},
       
 20411     '<':function(self, locals, a,b){return a(self, locals)<b(self, locals);},
       
 20412     '>':function(self, locals, a,b){return a(self, locals)>b(self, locals);},
       
 20413     '<=':function(self, locals, a,b){return a(self, locals)<=b(self, locals);},
       
 20414     '>=':function(self, locals, a,b){return a(self, locals)>=b(self, locals);},
       
 20415     '&&':function(self, locals, a,b){return a(self, locals)&&b(self, locals);},
       
 20416     '||':function(self, locals, a,b){return a(self, locals)||b(self, locals);},
       
 20417     '&':function(self, locals, a,b){return a(self, locals)&b(self, locals);},
       
 20418     '!':function(self, locals, a){return !a(self, locals);},
       
 20419 
       
 20420     //Tokenized as operators but parsed as assignment/filters
       
 20421     '=':true,
       
 20422     '|':true
       
 20423 });
       
 20424 /* jshint bitwise: true */
       
 20425 var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
       
 20426 
       
 20427 
       
 20428 /////////////////////////////////////////
       
 20429 
       
 20430 
       
 20431 /**
       
 20432  * @constructor
       
 20433  */
       
 20434 var Lexer = function (options) {
       
 20435   this.options = options;
       
 20436 };
       
 20437 
       
 20438 Lexer.prototype = {
       
 20439   constructor: Lexer,
       
 20440 
       
 20441   lex: function (text) {
       
 20442     this.text = text;
       
 20443     this.index = 0;
       
 20444     this.ch = undefined;
       
 20445     this.tokens = [];
       
 20446 
       
 20447     while (this.index < this.text.length) {
       
 20448       this.ch = this.text.charAt(this.index);
       
 20449       if (this.is('"\'')) {
       
 20450         this.readString(this.ch);
       
 20451       } else if (this.isNumber(this.ch) || this.is('.') && this.isNumber(this.peek())) {
       
 20452         this.readNumber();
       
 20453       } else if (this.isIdent(this.ch)) {
       
 20454         this.readIdent();
       
 20455       } else if (this.is('(){}[].,;:?')) {
       
 20456         this.tokens.push({
       
 20457           index: this.index,
       
 20458           text: this.ch
       
 20459         });
       
 20460         this.index++;
       
 20461       } else if (this.isWhitespace(this.ch)) {
       
 20462         this.index++;
       
 20463       } else {
       
 20464         var ch2 = this.ch + this.peek();
       
 20465         var ch3 = ch2 + this.peek(2);
       
 20466         var fn = OPERATORS[this.ch];
       
 20467         var fn2 = OPERATORS[ch2];
       
 20468         var fn3 = OPERATORS[ch3];
       
 20469         if (fn3) {
       
 20470           this.tokens.push({index: this.index, text: ch3, fn: fn3});
       
 20471           this.index += 3;
       
 20472         } else if (fn2) {
       
 20473           this.tokens.push({index: this.index, text: ch2, fn: fn2});
       
 20474           this.index += 2;
       
 20475         } else if (fn) {
       
 20476           this.tokens.push({
       
 20477             index: this.index,
       
 20478             text: this.ch,
       
 20479             fn: fn
       
 20480           });
       
 20481           this.index += 1;
       
 20482         } else {
       
 20483           this.throwError('Unexpected next character ', this.index, this.index + 1);
       
 20484         }
       
 20485       }
       
 20486     }
       
 20487     return this.tokens;
       
 20488   },
       
 20489 
       
 20490   is: function(chars) {
       
 20491     return chars.indexOf(this.ch) !== -1;
       
 20492   },
       
 20493 
       
 20494   peek: function(i) {
       
 20495     var num = i || 1;
       
 20496     return (this.index + num < this.text.length) ? this.text.charAt(this.index + num) : false;
       
 20497   },
       
 20498 
       
 20499   isNumber: function(ch) {
       
 20500     return ('0' <= ch && ch <= '9');
       
 20501   },
       
 20502 
       
 20503   isWhitespace: function(ch) {
       
 20504     // IE treats non-breaking space as \u00A0
       
 20505     return (ch === ' ' || ch === '\r' || ch === '\t' ||
       
 20506             ch === '\n' || ch === '\v' || ch === '\u00A0');
       
 20507   },
       
 20508 
       
 20509   isIdent: function(ch) {
       
 20510     return ('a' <= ch && ch <= 'z' ||
       
 20511             'A' <= ch && ch <= 'Z' ||
       
 20512             '_' === ch || ch === '$');
       
 20513   },
       
 20514 
       
 20515   isExpOperator: function(ch) {
       
 20516     return (ch === '-' || ch === '+' || this.isNumber(ch));
       
 20517   },
       
 20518 
       
 20519   throwError: function(error, start, end) {
       
 20520     end = end || this.index;
       
 20521     var colStr = (isDefined(start)
       
 20522             ? 's ' + start +  '-' + this.index + ' [' + this.text.substring(start, end) + ']'
       
 20523             : ' ' + end);
       
 20524     throw $parseMinErr('lexerr', 'Lexer Error: {0} at column{1} in expression [{2}].',
       
 20525         error, colStr, this.text);
       
 20526   },
       
 20527 
       
 20528   readNumber: function() {
       
 20529     var number = '';
       
 20530     var start = this.index;
       
 20531     while (this.index < this.text.length) {
       
 20532       var ch = lowercase(this.text.charAt(this.index));
       
 20533       if (ch == '.' || this.isNumber(ch)) {
       
 20534         number += ch;
       
 20535       } else {
       
 20536         var peekCh = this.peek();
       
 20537         if (ch == 'e' && this.isExpOperator(peekCh)) {
       
 20538           number += ch;
       
 20539         } else if (this.isExpOperator(ch) &&
       
 20540             peekCh && this.isNumber(peekCh) &&
       
 20541             number.charAt(number.length - 1) == 'e') {
       
 20542           number += ch;
       
 20543         } else if (this.isExpOperator(ch) &&
       
 20544             (!peekCh || !this.isNumber(peekCh)) &&
       
 20545             number.charAt(number.length - 1) == 'e') {
       
 20546           this.throwError('Invalid exponent');
       
 20547         } else {
       
 20548           break;
       
 20549         }
       
 20550       }
       
 20551       this.index++;
       
 20552     }
       
 20553     number = 1 * number;
       
 20554     this.tokens.push({
       
 20555       index: start,
       
 20556       text: number,
       
 20557       constant: true,
       
 20558       fn: function() { return number; }
       
 20559     });
       
 20560   },
       
 20561 
       
 20562   readIdent: function() {
       
 20563     var expression = this.text;
       
 20564 
       
 20565     var ident = '';
       
 20566     var start = this.index;
       
 20567 
       
 20568     var lastDot, peekIndex, methodName, ch;
       
 20569 
       
 20570     while (this.index < this.text.length) {
       
 20571       ch = this.text.charAt(this.index);
       
 20572       if (ch === '.' || this.isIdent(ch) || this.isNumber(ch)) {
       
 20573         if (ch === '.') lastDot = this.index;
       
 20574         ident += ch;
       
 20575       } else {
       
 20576         break;
       
 20577       }
       
 20578       this.index++;
       
 20579     }
       
 20580 
       
 20581     //check if the identifier ends with . and if so move back one char
       
 20582     if (lastDot && ident[ident.length - 1] === '.') {
       
 20583       this.index--;
       
 20584       ident = ident.slice(0, -1);
       
 20585       lastDot = ident.lastIndexOf('.');
       
 20586       if (lastDot === -1) {
       
 20587         lastDot = undefined;
       
 20588       }
       
 20589     }
       
 20590 
       
 20591     //check if this is not a method invocation and if it is back out to last dot
       
 20592     if (lastDot) {
       
 20593       peekIndex = this.index;
       
 20594       while (peekIndex < this.text.length) {
       
 20595         ch = this.text.charAt(peekIndex);
       
 20596         if (ch === '(') {
       
 20597           methodName = ident.substr(lastDot - start + 1);
       
 20598           ident = ident.substr(0, lastDot - start);
       
 20599           this.index = peekIndex;
       
 20600           break;
       
 20601         }
       
 20602         if (this.isWhitespace(ch)) {
       
 20603           peekIndex++;
       
 20604         } else {
       
 20605           break;
       
 20606         }
       
 20607       }
       
 20608     }
       
 20609 
       
 20610     this.tokens.push({
       
 20611       index: start,
       
 20612       text: ident,
       
 20613       fn: CONSTANTS[ident] || getterFn(ident, this.options, expression)
       
 20614     });
       
 20615 
       
 20616     if (methodName) {
       
 20617       this.tokens.push({
       
 20618         index: lastDot,
       
 20619         text: '.'
       
 20620       });
       
 20621       this.tokens.push({
       
 20622         index: lastDot + 1,
       
 20623         text: methodName
       
 20624       });
       
 20625     }
       
 20626   },
       
 20627 
       
 20628   readString: function(quote) {
       
 20629     var start = this.index;
       
 20630     this.index++;
       
 20631     var string = '';
       
 20632     var rawString = quote;
       
 20633     var escape = false;
       
 20634     while (this.index < this.text.length) {
       
 20635       var ch = this.text.charAt(this.index);
       
 20636       rawString += ch;
       
 20637       if (escape) {
       
 20638         if (ch === 'u') {
       
 20639           var hex = this.text.substring(this.index + 1, this.index + 5);
       
 20640           if (!hex.match(/[\da-f]{4}/i))
       
 20641             this.throwError('Invalid unicode escape [\\u' + hex + ']');
       
 20642           this.index += 4;
       
 20643           string += String.fromCharCode(parseInt(hex, 16));
       
 20644         } else {
       
 20645           var rep = ESCAPE[ch];
       
 20646           string = string + (rep || ch);
       
 20647         }
       
 20648         escape = false;
       
 20649       } else if (ch === '\\') {
       
 20650         escape = true;
       
 20651       } else if (ch === quote) {
       
 20652         this.index++;
       
 20653         this.tokens.push({
       
 20654           index: start,
       
 20655           text: rawString,
       
 20656           string: string,
       
 20657           constant: true,
       
 20658           fn: function() { return string; }
       
 20659         });
       
 20660         return;
       
 20661       } else {
       
 20662         string += ch;
       
 20663       }
       
 20664       this.index++;
       
 20665     }
       
 20666     this.throwError('Unterminated quote', start);
       
 20667   }
       
 20668 };
       
 20669 
       
 20670 
       
 20671 function isConstant(exp) {
       
 20672   return exp.constant;
       
 20673 }
       
 20674 
       
 20675 /**
       
 20676  * @constructor
       
 20677  */
       
 20678 var Parser = function (lexer, $filter, options) {
       
 20679   this.lexer = lexer;
       
 20680   this.$filter = $filter;
       
 20681   this.options = options;
       
 20682 };
       
 20683 
       
 20684 Parser.ZERO = extend(function () {
       
 20685   return 0;
       
 20686 }, {
       
 20687   sharedGetter: true,
       
 20688   constant: true
       
 20689 });
       
 20690 
       
 20691 Parser.prototype = {
       
 20692   constructor: Parser,
       
 20693 
       
 20694   parse: function (text) {
       
 20695     this.text = text;
       
 20696     this.tokens = this.lexer.lex(text);
       
 20697 
       
 20698     var value = this.statements();
       
 20699 
       
 20700     if (this.tokens.length !== 0) {
       
 20701       this.throwError('is an unexpected token', this.tokens[0]);
       
 20702     }
       
 20703 
       
 20704     value.literal = !!value.literal;
       
 20705     value.constant = !!value.constant;
       
 20706 
       
 20707     return value;
       
 20708   },
       
 20709 
       
 20710   primary: function () {
       
 20711     var primary;
       
 20712     if (this.expect('(')) {
       
 20713       primary = this.filterChain();
       
 20714       this.consume(')');
       
 20715     } else if (this.expect('[')) {
       
 20716       primary = this.arrayDeclaration();
       
 20717     } else if (this.expect('{')) {
       
 20718       primary = this.object();
       
 20719     } else {
       
 20720       var token = this.expect();
       
 20721       primary = token.fn;
       
 20722       if (!primary) {
       
 20723         this.throwError('not a primary expression', token);
       
 20724       }
       
 20725       if (token.constant) {
       
 20726         primary.constant = true;
       
 20727         primary.literal = true;
       
 20728       }
       
 20729     }
       
 20730 
       
 20731     var next, context;
       
 20732     while ((next = this.expect('(', '[', '.'))) {
       
 20733       if (next.text === '(') {
       
 20734         primary = this.functionCall(primary, context);
       
 20735         context = null;
       
 20736       } else if (next.text === '[') {
       
 20737         context = primary;
       
 20738         primary = this.objectIndex(primary);
       
 20739       } else if (next.text === '.') {
       
 20740         context = primary;
       
 20741         primary = this.fieldAccess(primary);
       
 20742       } else {
       
 20743         this.throwError('IMPOSSIBLE');
       
 20744       }
       
 20745     }
       
 20746     return primary;
       
 20747   },
       
 20748 
       
 20749   throwError: function(msg, token) {
       
 20750     throw $parseMinErr('syntax',
       
 20751         'Syntax Error: Token \'{0}\' {1} at column {2} of the expression [{3}] starting at [{4}].',
       
 20752           token.text, msg, (token.index + 1), this.text, this.text.substring(token.index));
       
 20753   },
       
 20754 
       
 20755   peekToken: function() {
       
 20756     if (this.tokens.length === 0)
       
 20757       throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
       
 20758     return this.tokens[0];
       
 20759   },
       
 20760 
       
 20761   peek: function(e1, e2, e3, e4) {
       
 20762     if (this.tokens.length > 0) {
       
 20763       var token = this.tokens[0];
       
 20764       var t = token.text;
       
 20765       if (t === e1 || t === e2 || t === e3 || t === e4 ||
       
 20766           (!e1 && !e2 && !e3 && !e4)) {
       
 20767         return token;
       
 20768       }
       
 20769     }
       
 20770     return false;
       
 20771   },
       
 20772 
       
 20773   expect: function(e1, e2, e3, e4){
       
 20774     var token = this.peek(e1, e2, e3, e4);
       
 20775     if (token) {
       
 20776       this.tokens.shift();
       
 20777       return token;
       
 20778     }
       
 20779     return false;
       
 20780   },
       
 20781 
       
 20782   consume: function(e1){
       
 20783     if (!this.expect(e1)) {
       
 20784       this.throwError('is unexpected, expecting [' + e1 + ']', this.peek());
       
 20785     }
       
 20786   },
       
 20787 
       
 20788   unaryFn: function(fn, right) {
       
 20789     return extend(function $parseUnaryFn(self, locals) {
       
 20790       return fn(self, locals, right);
       
 20791     }, {
       
 20792       constant:right.constant,
       
 20793       inputs: [right]
       
 20794     });
       
 20795   },
       
 20796 
       
 20797   binaryFn: function(left, fn, right, isBranching) {
       
 20798     return extend(function $parseBinaryFn(self, locals) {
       
 20799       return fn(self, locals, left, right);
       
 20800     }, {
       
 20801       constant: left.constant && right.constant,
       
 20802       inputs: !isBranching && [left, right]
       
 20803     });
       
 20804   },
       
 20805 
       
 20806   statements: function() {
       
 20807     var statements = [];
       
 20808     while (true) {
       
 20809       if (this.tokens.length > 0 && !this.peek('}', ')', ';', ']'))
       
 20810         statements.push(this.filterChain());
       
 20811       if (!this.expect(';')) {
       
 20812         // optimize for the common case where there is only one statement.
       
 20813         // TODO(size): maybe we should not support multiple statements?
       
 20814         return (statements.length === 1)
       
 20815             ? statements[0]
       
 20816             : function $parseStatements(self, locals) {
       
 20817                 var value;
       
 20818                 for (var i = 0, ii = statements.length; i < ii; i++) {
       
 20819                   value = statements[i](self, locals);
       
 20820                 }
       
 20821                 return value;
       
 20822               };
       
 20823       }
       
 20824     }
       
 20825   },
       
 20826 
       
 20827   filterChain: function() {
       
 20828     var left = this.expression();
       
 20829     var token;
       
 20830     while ((token = this.expect('|'))) {
       
 20831       left = this.filter(left);
       
 20832     }
       
 20833     return left;
       
 20834   },
       
 20835 
       
 20836   filter: function(inputFn) {
       
 20837     var token = this.expect();
       
 20838     var fn = this.$filter(token.text);
       
 20839     var argsFn;
       
 20840     var args;
       
 20841 
       
 20842     if (this.peek(':')) {
       
 20843       argsFn = [];
       
 20844       args = []; // we can safely reuse the array
       
 20845       while (this.expect(':')) {
       
 20846         argsFn.push(this.expression());
       
 20847       }
       
 20848     }
       
 20849 
       
 20850     var inputs = [inputFn].concat(argsFn || []);
       
 20851 
       
 20852     return extend(function $parseFilter(self, locals) {
       
 20853       var input = inputFn(self, locals);
       
 20854       if (args) {
       
 20855         args[0] = input;
       
 20856 
       
 20857         var i = argsFn.length;
       
 20858         while (i--) {
       
 20859           args[i + 1] = argsFn[i](self, locals);
       
 20860         }
       
 20861 
       
 20862         return fn.apply(undefined, args);
       
 20863       }
       
 20864 
       
 20865       return fn(input);
       
 20866     }, {
       
 20867       constant: !fn.$stateful && inputs.every(isConstant),
       
 20868       inputs: !fn.$stateful && inputs
       
 20869     });
       
 20870   },
       
 20871 
       
 20872   expression: function() {
       
 20873     return this.assignment();
       
 20874   },
       
 20875 
       
 20876   assignment: function() {
       
 20877     var left = this.ternary();
       
 20878     var right;
       
 20879     var token;
       
 20880     if ((token = this.expect('='))) {
       
 20881       if (!left.assign) {
       
 20882         this.throwError('implies assignment but [' +
       
 20883             this.text.substring(0, token.index) + '] can not be assigned to', token);
       
 20884       }
       
 20885       right = this.ternary();
       
 20886       return extend(function $parseAssignment(scope, locals) {
       
 20887         return left.assign(scope, right(scope, locals), locals);
       
 20888       }, {
       
 20889         inputs: [left, right]
       
 20890       });
       
 20891     }
       
 20892     return left;
       
 20893   },
       
 20894 
       
 20895   ternary: function() {
       
 20896     var left = this.logicalOR();
       
 20897     var middle;
       
 20898     var token;
       
 20899     if ((token = this.expect('?'))) {
       
 20900       middle = this.assignment();
       
 20901       if ((token = this.expect(':'))) {
       
 20902         var right = this.assignment();
       
 20903 
       
 20904         return extend(function $parseTernary(self, locals){
       
 20905           return left(self, locals) ? middle(self, locals) : right(self, locals);
       
 20906         }, {
       
 20907           constant: left.constant && middle.constant && right.constant
       
 20908         });
       
 20909 
       
 20910       } else {
       
 20911         this.throwError('expected :', token);
       
 20912       }
       
 20913     }
       
 20914 
       
 20915     return left;
       
 20916   },
       
 20917 
       
 20918   logicalOR: function() {
       
 20919     var left = this.logicalAND();
       
 20920     var token;
       
 20921     while ((token = this.expect('||'))) {
       
 20922       left = this.binaryFn(left, token.fn, this.logicalAND(), true);
       
 20923     }
       
 20924     return left;
       
 20925   },
       
 20926 
       
 20927   logicalAND: function() {
       
 20928     var left = this.equality();
       
 20929     var token;
       
 20930     if ((token = this.expect('&&'))) {
       
 20931       left = this.binaryFn(left, token.fn, this.logicalAND(), true);
       
 20932     }
       
 20933     return left;
       
 20934   },
       
 20935 
       
 20936   equality: function() {
       
 20937     var left = this.relational();
       
 20938     var token;
       
 20939     if ((token = this.expect('==','!=','===','!=='))) {
       
 20940       left = this.binaryFn(left, token.fn, this.equality());
       
 20941     }
       
 20942     return left;
       
 20943   },
       
 20944 
       
 20945   relational: function() {
       
 20946     var left = this.additive();
       
 20947     var token;
       
 20948     if ((token = this.expect('<', '>', '<=', '>='))) {
       
 20949       left = this.binaryFn(left, token.fn, this.relational());
       
 20950     }
       
 20951     return left;
       
 20952   },
       
 20953 
       
 20954   additive: function() {
       
 20955     var left = this.multiplicative();
       
 20956     var token;
       
 20957     while ((token = this.expect('+','-'))) {
       
 20958       left = this.binaryFn(left, token.fn, this.multiplicative());
       
 20959     }
       
 20960     return left;
       
 20961   },
       
 20962 
       
 20963   multiplicative: function() {
       
 20964     var left = this.unary();
       
 20965     var token;
       
 20966     while ((token = this.expect('*','/','%'))) {
       
 20967       left = this.binaryFn(left, token.fn, this.unary());
       
 20968     }
       
 20969     return left;
       
 20970   },
       
 20971 
       
 20972   unary: function() {
       
 20973     var token;
       
 20974     if (this.expect('+')) {
       
 20975       return this.primary();
       
 20976     } else if ((token = this.expect('-'))) {
       
 20977       return this.binaryFn(Parser.ZERO, token.fn, this.unary());
       
 20978     } else if ((token = this.expect('!'))) {
       
 20979       return this.unaryFn(token.fn, this.unary());
       
 20980     } else {
       
 20981       return this.primary();
       
 20982     }
       
 20983   },
       
 20984 
       
 20985   fieldAccess: function(object) {
       
 20986     var expression = this.text;
       
 20987     var field = this.expect().text;
       
 20988     var getter = getterFn(field, this.options, expression);
       
 20989 
       
 20990     return extend(function $parseFieldAccess(scope, locals, self) {
       
 20991       return getter(self || object(scope, locals));
       
 20992     }, {
       
 20993       assign: function(scope, value, locals) {
       
 20994         var o = object(scope, locals);
       
 20995         if (!o) object.assign(scope, o = {});
       
 20996         return setter(o, field, value, expression);
       
 20997       }
       
 20998     });
       
 20999   },
       
 21000 
       
 21001   objectIndex: function(obj) {
       
 21002     var expression = this.text;
       
 21003 
       
 21004     var indexFn = this.expression();
       
 21005     this.consume(']');
       
 21006 
       
 21007     return extend(function $parseObjectIndex(self, locals) {
       
 21008       var o = obj(self, locals),
       
 21009           i = indexFn(self, locals),
       
 21010           v;
       
 21011 
       
 21012       ensureSafeMemberName(i, expression);
       
 21013       if (!o) return undefined;
       
 21014       v = ensureSafeObject(o[i], expression);
       
 21015       return v;
       
 21016     }, {
       
 21017       assign: function(self, value, locals) {
       
 21018         var key = ensureSafeMemberName(indexFn(self, locals), expression);
       
 21019         // prevent overwriting of Function.constructor which would break ensureSafeObject check
       
 21020         var o = ensureSafeObject(obj(self, locals), expression);
       
 21021         if (!o) obj.assign(self, o = {});
       
 21022         return o[key] = value;
       
 21023       }
       
 21024     });
       
 21025   },
       
 21026 
       
 21027   functionCall: function(fnGetter, contextGetter) {
       
 21028     var argsFn = [];
       
 21029     if (this.peekToken().text !== ')') {
       
 21030       do {
       
 21031         argsFn.push(this.expression());
       
 21032       } while (this.expect(','));
       
 21033     }
       
 21034     this.consume(')');
       
 21035 
       
 21036     var expressionText = this.text;
       
 21037     // we can safely reuse the array across invocations
       
 21038     var args = argsFn.length ? [] : null;
       
 21039 
       
 21040     return function $parseFunctionCall(scope, locals) {
       
 21041       var context = contextGetter ? contextGetter(scope, locals) : scope;
       
 21042       var fn = fnGetter(scope, locals, context) || noop;
       
 21043 
       
 21044       if (args) {
       
 21045         var i = argsFn.length;
       
 21046         while (i--) {
       
 21047           args[i] = ensureSafeObject(argsFn[i](scope, locals), expressionText);
       
 21048         }
       
 21049       }
       
 21050 
       
 21051       ensureSafeObject(context, expressionText);
       
 21052       ensureSafeFunction(fn, expressionText);
       
 21053 
       
 21054       // IE stupidity! (IE doesn't have apply for some native functions)
       
 21055       var v = fn.apply
       
 21056             ? fn.apply(context, args)
       
 21057             : fn(args[0], args[1], args[2], args[3], args[4]);
       
 21058 
       
 21059       return ensureSafeObject(v, expressionText);
       
 21060     };
       
 21061   },
       
 21062 
       
 21063   // This is used with json array declaration
       
 21064   arrayDeclaration: function () {
       
 21065     var elementFns = [];
       
 21066     if (this.peekToken().text !== ']') {
       
 21067       do {
       
 21068         if (this.peek(']')) {
       
 21069           // Support trailing commas per ES5.1.
       
 21070           break;
       
 21071         }
       
 21072         var elementFn = this.expression();
       
 21073         elementFns.push(elementFn);
       
 21074       } while (this.expect(','));
       
 21075     }
       
 21076     this.consume(']');
       
 21077 
       
 21078     return extend(function $parseArrayLiteral(self, locals) {
       
 21079       var array = [];
       
 21080       for (var i = 0, ii = elementFns.length; i < ii; i++) {
       
 21081         array.push(elementFns[i](self, locals));
       
 21082       }
       
 21083       return array;
       
 21084     }, {
       
 21085       literal: true,
       
 21086       constant: elementFns.every(isConstant),
       
 21087       inputs: elementFns
       
 21088     });
       
 21089   },
       
 21090 
       
 21091   object: function () {
       
 21092     var keys = [], valueFns = [];
       
 21093     if (this.peekToken().text !== '}') {
       
 21094       do {
       
 21095         if (this.peek('}')) {
       
 21096           // Support trailing commas per ES5.1.
       
 21097           break;
       
 21098         }
       
 21099         var token = this.expect();
       
 21100         keys.push(token.string || token.text);
       
 21101         this.consume(':');
       
 21102         var value = this.expression();
       
 21103         valueFns.push(value);
       
 21104       } while (this.expect(','));
       
 21105     }
       
 21106     this.consume('}');
       
 21107 
       
 21108     return extend(function $parseObjectLiteral(self, locals) {
       
 21109       var object = {};
       
 21110       for (var i = 0, ii = valueFns.length; i < ii; i++) {
       
 21111         object[keys[i]] = valueFns[i](self, locals);
       
 21112       }
       
 21113       return object;
       
 21114     }, {
       
 21115       literal: true,
       
 21116       constant: valueFns.every(isConstant),
       
 21117       inputs: valueFns
       
 21118     });
       
 21119   }
       
 21120 };
       
 21121 
       
 21122 
       
 21123 //////////////////////////////////////////////////
       
 21124 // Parser helper functions
       
 21125 //////////////////////////////////////////////////
       
 21126 
       
 21127 function setter(obj, path, setValue, fullExp) {
       
 21128   ensureSafeObject(obj, fullExp);
       
 21129 
       
 21130   var element = path.split('.'), key;
       
 21131   for (var i = 0; element.length > 1; i++) {
       
 21132     key = ensureSafeMemberName(element.shift(), fullExp);
       
 21133     var propertyObj = ensureSafeObject(obj[key], fullExp);
       
 21134     if (!propertyObj) {
       
 21135       propertyObj = {};
       
 21136       obj[key] = propertyObj;
       
 21137     }
       
 21138     obj = propertyObj;
       
 21139   }
       
 21140   key = ensureSafeMemberName(element.shift(), fullExp);
       
 21141   ensureSafeObject(obj[key], fullExp);
       
 21142   obj[key] = setValue;
       
 21143   return setValue;
       
 21144 }
       
 21145 
       
 21146 var getterFnCache = createMap();
       
 21147 
       
 21148 /**
       
 21149  * Implementation of the "Black Hole" variant from:
       
 21150  * - http://jsperf.com/angularjs-parse-getter/4
       
 21151  * - http://jsperf.com/path-evaluation-simplified/7
       
 21152  */
       
 21153 function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp) {
       
 21154   ensureSafeMemberName(key0, fullExp);
       
 21155   ensureSafeMemberName(key1, fullExp);
       
 21156   ensureSafeMemberName(key2, fullExp);
       
 21157   ensureSafeMemberName(key3, fullExp);
       
 21158   ensureSafeMemberName(key4, fullExp);
       
 21159 
       
 21160   return function cspSafeGetter(scope, locals) {
       
 21161     var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope;
       
 21162 
       
 21163     if (pathVal == null) return pathVal;
       
 21164     pathVal = pathVal[key0];
       
 21165 
       
 21166     if (!key1) return pathVal;
       
 21167     if (pathVal == null) return undefined;
       
 21168     pathVal = pathVal[key1];
       
 21169 
       
 21170     if (!key2) return pathVal;
       
 21171     if (pathVal == null) return undefined;
       
 21172     pathVal = pathVal[key2];
       
 21173 
       
 21174     if (!key3) return pathVal;
       
 21175     if (pathVal == null) return undefined;
       
 21176     pathVal = pathVal[key3];
       
 21177 
       
 21178     if (!key4) return pathVal;
       
 21179     if (pathVal == null) return undefined;
       
 21180     pathVal = pathVal[key4];
       
 21181 
       
 21182     return pathVal;
       
 21183   };
       
 21184 }
       
 21185 
       
 21186 function getterFn(path, options, fullExp) {
       
 21187   var fn = getterFnCache[path];
       
 21188 
       
 21189   if (fn) return fn;
       
 21190 
       
 21191   var pathKeys = path.split('.'),
       
 21192       pathKeysLength = pathKeys.length;
       
 21193 
       
 21194   // http://jsperf.com/angularjs-parse-getter/6
       
 21195   if (options.csp) {
       
 21196     if (pathKeysLength < 6) {
       
 21197       fn = cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4], fullExp);
       
 21198     } else {
       
 21199       fn = function cspSafeGetter(scope, locals) {
       
 21200         var i = 0, val;
       
 21201         do {
       
 21202           val = cspSafeGetterFn(pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++],
       
 21203                                 pathKeys[i++], fullExp)(scope, locals);
       
 21204 
       
 21205           locals = undefined; // clear after first iteration
       
 21206           scope = val;
       
 21207         } while (i < pathKeysLength);
       
 21208         return val;
       
 21209       };
       
 21210     }
       
 21211   } else {
       
 21212     var code = '';
       
 21213     forEach(pathKeys, function(key, index) {
       
 21214       ensureSafeMemberName(key, fullExp);
       
 21215       code += 'if(s == null) return undefined;\n' +
       
 21216               's='+ (index
       
 21217                       // we simply dereference 's' on any .dot notation
       
 21218                       ? 's'
       
 21219                       // but if we are first then we check locals first, and if so read it first
       
 21220                       : '((l&&l.hasOwnProperty("' + key + '"))?l:s)') + '.' + key + ';\n';
       
 21221     });
       
 21222     code += 'return s;';
       
 21223 
       
 21224     /* jshint -W054 */
       
 21225     var evaledFnGetter = new Function('s', 'l', code); // s=scope, l=locals
       
 21226     /* jshint +W054 */
       
 21227     evaledFnGetter.toString = valueFn(code);
       
 21228 
       
 21229     fn = evaledFnGetter;
       
 21230   }
       
 21231 
       
 21232   fn.sharedGetter = true;
       
 21233   fn.assign = function(self, value) {
       
 21234     return setter(self, path, value, path);
       
 21235   };
       
 21236   getterFnCache[path] = fn;
       
 21237   return fn;
       
 21238 }
       
 21239 
       
 21240 ///////////////////////////////////
       
 21241 
       
 21242 /**
       
 21243  * @ngdoc service
       
 21244  * @name $parse
       
 21245  * @kind function
       
 21246  *
       
 21247  * @description
       
 21248  *
       
 21249  * Converts Angular {@link guide/expression expression} into a function.
       
 21250  *
       
 21251  * ```js
       
 21252  *   var getter = $parse('user.name');
       
 21253  *   var setter = getter.assign;
       
 21254  *   var context = {user:{name:'angular'}};
       
 21255  *   var locals = {user:{name:'local'}};
       
 21256  *
       
 21257  *   expect(getter(context)).toEqual('angular');
       
 21258  *   setter(context, 'newValue');
       
 21259  *   expect(context.user.name).toEqual('newValue');
       
 21260  *   expect(getter(context, locals)).toEqual('local');
       
 21261  * ```
       
 21262  *
       
 21263  *
       
 21264  * @param {string} expression String expression to compile.
       
 21265  * @returns {function(context, locals)} a function which represents the compiled expression:
       
 21266  *
       
 21267  *    * `context` – `{object}` – an object against which any expressions embedded in the strings
       
 21268  *      are evaluated against (typically a scope object).
       
 21269  *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
       
 21270  *      `context`.
       
 21271  *
       
 21272  *    The returned function also has the following properties:
       
 21273  *      * `literal` – `{boolean}` – whether the expression's top-level node is a JavaScript
       
 21274  *        literal.
       
 21275  *      * `constant` – `{boolean}` – whether the expression is made entirely of JavaScript
       
 21276  *        constant literals.
       
 21277  *      * `assign` – `{?function(context, value)}` – if the expression is assignable, this will be
       
 21278  *        set to a function to change its value on the given context.
       
 21279  *
       
 21280  */
       
 21281 
       
 21282 
       
 21283 /**
       
 21284  * @ngdoc provider
       
 21285  * @name $parseProvider
       
 21286  *
       
 21287  * @description
       
 21288  * `$parseProvider` can be used for configuring the default behavior of the {@link ng.$parse $parse}
       
 21289  *  service.
       
 21290  */
       
 21291 function $ParseProvider() {
       
 21292   var cache = createMap();
       
 21293 
       
 21294   var $parseOptions = {
       
 21295     csp: false
       
 21296   };
       
 21297 
       
 21298 
       
 21299   this.$get = ['$filter', '$sniffer', function($filter, $sniffer) {
       
 21300     $parseOptions.csp = $sniffer.csp;
       
 21301 
       
 21302     function wrapSharedExpression(exp) {
       
 21303       var wrapped = exp;
       
 21304 
       
 21305       if (exp.sharedGetter) {
       
 21306         wrapped = function $parseWrapper(self, locals) {
       
 21307           return exp(self, locals);
       
 21308         };
       
 21309         wrapped.literal = exp.literal;
       
 21310         wrapped.constant = exp.constant;
       
 21311         wrapped.assign = exp.assign;
       
 21312       }
       
 21313 
       
 21314       return wrapped;
       
 21315     }
       
 21316 
       
 21317     return function $parse(exp, interceptorFn) {
       
 21318       var parsedExpression, oneTime, cacheKey;
       
 21319 
       
 21320       switch (typeof exp) {
       
 21321         case 'string':
       
 21322           cacheKey = exp = exp.trim();
       
 21323 
       
 21324           parsedExpression = cache[cacheKey];
       
 21325 
       
 21326           if (!parsedExpression) {
       
 21327             if (exp.charAt(0) === ':' && exp.charAt(1) === ':') {
       
 21328               oneTime = true;
       
 21329               exp = exp.substring(2);
       
 21330             }
       
 21331 
       
 21332             var lexer = new Lexer($parseOptions);
       
 21333             var parser = new Parser(lexer, $filter, $parseOptions);
       
 21334             parsedExpression = parser.parse(exp);
       
 21335 
       
 21336             if (parsedExpression.constant) {
       
 21337               parsedExpression.$$watchDelegate = constantWatchDelegate;
       
 21338             } else if (oneTime) {
       
 21339               //oneTime is not part of the exp passed to the Parser so we may have to
       
 21340               //wrap the parsedExpression before adding a $$watchDelegate
       
 21341               parsedExpression = wrapSharedExpression(parsedExpression);
       
 21342               parsedExpression.$$watchDelegate = parsedExpression.literal ?
       
 21343                 oneTimeLiteralWatchDelegate : oneTimeWatchDelegate;
       
 21344             } else if (parsedExpression.inputs) {
       
 21345               parsedExpression.$$watchDelegate = inputsWatchDelegate;
       
 21346             }
       
 21347 
       
 21348             cache[cacheKey] = parsedExpression;
       
 21349           }
       
 21350           return addInterceptor(parsedExpression, interceptorFn);
       
 21351 
       
 21352         case 'function':
       
 21353           return addInterceptor(exp, interceptorFn);
       
 21354 
       
 21355         default:
       
 21356           return addInterceptor(noop, interceptorFn);
       
 21357       }
       
 21358     };
       
 21359 
       
 21360     function collectExpressionInputs(inputs, list) {
       
 21361       for (var i = 0, ii = inputs.length; i < ii; i++) {
       
 21362         var input = inputs[i];
       
 21363         if (!input.constant) {
       
 21364           if (input.inputs) {
       
 21365             collectExpressionInputs(input.inputs, list);
       
 21366           } else if (list.indexOf(input) === -1) { // TODO(perf) can we do better?
       
 21367             list.push(input);
       
 21368           }
       
 21369         }
       
 21370       }
       
 21371 
       
 21372       return list;
       
 21373     }
       
 21374 
       
 21375     function expressionInputDirtyCheck(newValue, oldValueOfValue) {
       
 21376 
       
 21377       if (newValue == null || oldValueOfValue == null) { // null/undefined
       
 21378         return newValue === oldValueOfValue;
       
 21379       }
       
 21380 
       
 21381       if (typeof newValue === 'object') {
       
 21382 
       
 21383         // attempt to convert the value to a primitive type
       
 21384         // TODO(docs): add a note to docs that by implementing valueOf even objects and arrays can
       
 21385         //             be cheaply dirty-checked
       
 21386         newValue = newValue.valueOf();
       
 21387 
       
 21388         if (typeof newValue === 'object') {
       
 21389           // objects/arrays are not supported - deep-watching them would be too expensive
       
 21390           return false;
       
 21391         }
       
 21392 
       
 21393         // fall-through to the primitive equality check
       
 21394       }
       
 21395 
       
 21396       //Primitive or NaN
       
 21397       return newValue === oldValueOfValue || (newValue !== newValue && oldValueOfValue !== oldValueOfValue);
       
 21398     }
       
 21399 
       
 21400     function inputsWatchDelegate(scope, listener, objectEquality, parsedExpression) {
       
 21401       var inputExpressions = parsedExpression.$$inputs ||
       
 21402                     (parsedExpression.$$inputs = collectExpressionInputs(parsedExpression.inputs, []));
       
 21403 
       
 21404       var lastResult;
       
 21405 
       
 21406       if (inputExpressions.length === 1) {
       
 21407         var oldInputValue = expressionInputDirtyCheck; // init to something unique so that equals check fails
       
 21408         inputExpressions = inputExpressions[0];
       
 21409         return scope.$watch(function expressionInputWatch(scope) {
       
 21410           var newInputValue = inputExpressions(scope);
       
 21411           if (!expressionInputDirtyCheck(newInputValue, oldInputValue)) {
       
 21412             lastResult = parsedExpression(scope);
       
 21413             oldInputValue = newInputValue && newInputValue.valueOf();
       
 21414           }
       
 21415           return lastResult;
       
 21416         }, listener, objectEquality);
       
 21417       }
       
 21418 
       
 21419       var oldInputValueOfValues = [];
       
 21420       for (var i = 0, ii = inputExpressions.length; i < ii; i++) {
       
 21421         oldInputValueOfValues[i] = expressionInputDirtyCheck; // init to something unique so that equals check fails
       
 21422       }
       
 21423 
       
 21424       return scope.$watch(function expressionInputsWatch(scope) {
       
 21425         var changed = false;
       
 21426 
       
 21427         for (var i = 0, ii = inputExpressions.length; i < ii; i++) {
       
 21428           var newInputValue = inputExpressions[i](scope);
       
 21429           if (changed || (changed = !expressionInputDirtyCheck(newInputValue, oldInputValueOfValues[i]))) {
       
 21430             oldInputValueOfValues[i] = newInputValue && newInputValue.valueOf();
       
 21431           }
       
 21432         }
       
 21433 
       
 21434         if (changed) {
       
 21435           lastResult = parsedExpression(scope);
       
 21436         }
       
 21437 
       
 21438         return lastResult;
       
 21439       }, listener, objectEquality);
       
 21440     }
       
 21441 
       
 21442     function oneTimeWatchDelegate(scope, listener, objectEquality, parsedExpression) {
       
 21443       var unwatch, lastValue;
       
 21444       return unwatch = scope.$watch(function oneTimeWatch(scope) {
       
 21445         return parsedExpression(scope);
       
 21446       }, function oneTimeListener(value, old, scope) {
       
 21447         lastValue = value;
       
 21448         if (isFunction(listener)) {
       
 21449           listener.apply(this, arguments);
       
 21450         }
       
 21451         if (isDefined(value)) {
       
 21452           scope.$$postDigest(function () {
       
 21453             if (isDefined(lastValue)) {
       
 21454               unwatch();
       
 21455             }
       
 21456           });
       
 21457         }
       
 21458       }, objectEquality);
       
 21459     }
       
 21460 
       
 21461     function oneTimeLiteralWatchDelegate(scope, listener, objectEquality, parsedExpression) {
       
 21462       var unwatch;
       
 21463       return unwatch = scope.$watch(function oneTimeWatch(scope) {
       
 21464         return parsedExpression(scope);
       
 21465       }, function oneTimeListener(value, old, scope) {
       
 21466         if (isFunction(listener)) {
       
 21467           listener.call(this, value, old, scope);
       
 21468         }
       
 21469         if (isAllDefined(value)) {
       
 21470           scope.$$postDigest(function () {
       
 21471             if(isAllDefined(value)) unwatch();
       
 21472           });
       
 21473         }
       
 21474       }, objectEquality);
       
 21475 
       
 21476       function isAllDefined(value) {
       
 21477         var allDefined = true;
       
 21478         forEach(value, function (val) {
       
 21479           if (!isDefined(val)) allDefined = false;
       
 21480         });
       
 21481         return allDefined;
       
 21482       }
       
 21483     }
       
 21484 
       
 21485     function constantWatchDelegate(scope, listener, objectEquality, parsedExpression) {
       
 21486       var unwatch;
       
 21487       return unwatch = scope.$watch(function constantWatch(scope) {
       
 21488         return parsedExpression(scope);
       
 21489       }, function constantListener(value, old, scope) {
       
 21490         if (isFunction(listener)) {
       
 21491           listener.apply(this, arguments);
       
 21492         }
       
 21493         unwatch();
       
 21494       }, objectEquality);
       
 21495     }
       
 21496 
       
 21497     function addInterceptor(parsedExpression, interceptorFn) {
       
 21498       if (!interceptorFn) return parsedExpression;
       
 21499 
       
 21500       var fn = function interceptedExpression(scope, locals) {
       
 21501         var value = parsedExpression(scope, locals);
       
 21502         var result = interceptorFn(value, scope, locals);
       
 21503         // we only return the interceptor's result if the
       
 21504         // initial value is defined (for bind-once)
       
 21505         return isDefined(value) ? result : value;
       
 21506       };
       
 21507 
       
 21508       // Propagate $$watchDelegates other then inputsWatchDelegate
       
 21509       if (parsedExpression.$$watchDelegate &&
       
 21510           parsedExpression.$$watchDelegate !== inputsWatchDelegate) {
       
 21511         fn.$$watchDelegate = parsedExpression.$$watchDelegate;
       
 21512       } else if (!interceptorFn.$stateful) {
       
 21513         // If there is an interceptor, but no watchDelegate then treat the interceptor like
       
 21514         // we treat filters - it is assumed to be a pure function unless flagged with $stateful
       
 21515         fn.$$watchDelegate = inputsWatchDelegate;
       
 21516         fn.inputs = [parsedExpression];
       
 21517       }
       
 21518 
       
 21519       return fn;
       
 21520     }
       
 21521   }];
       
 21522 }
       
 21523 
       
 21524 /**
       
 21525  * @ngdoc service
       
 21526  * @name $q
       
 21527  * @requires $rootScope
       
 21528  *
       
 21529  * @description
       
 21530  * A promise/deferred implementation inspired by [Kris Kowal's Q](https://github.com/kriskowal/q).
       
 21531  *
       
 21532  * $q can be used in two fashions --- one which is more similar to Kris Kowal's Q or jQuery's Deferred
       
 21533  * implementations, and the other which resembles ES6 promises to some degree.
       
 21534  *
       
 21535  * # $q constructor
       
 21536  *
       
 21537  * The streamlined ES6 style promise is essentially just using $q as a constructor which takes a `resolver`
       
 21538  * function as the first argument. This is similar to the native Promise implementation from ES6 Harmony,
       
 21539  * see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).
       
 21540  *
       
 21541  * While the constructor-style use is supported, not all of the supporting methods from ES6 Harmony promises are
       
 21542  * available yet.
       
 21543  *
       
 21544  * It can be used like so:
       
 21545  *
       
 21546  * ```js
       
 21547  * return $q(function(resolve, reject) {
       
 21548  *   // perform some asynchronous operation, resolve or reject the promise when appropriate.
       
 21549  *   setInterval(function() {
       
 21550  *     if (pollStatus > 0) {
       
 21551  *       resolve(polledValue);
       
 21552  *     } else if (pollStatus < 0) {
       
 21553  *       reject(polledValue);
       
 21554  *     } else {
       
 21555  *       pollStatus = pollAgain(function(value) {
       
 21556  *         polledValue = value;
       
 21557  *       });
       
 21558  *     }
       
 21559  *   }, 10000);
       
 21560  * }).
       
 21561  *   then(function(value) {
       
 21562  *     // handle success
       
 21563  *   }, function(reason) {
       
 21564  *     // handle failure
       
 21565  *   });
       
 21566  * ```
       
 21567  *
       
 21568  * Note: progress/notify callbacks are not currently supported via the ES6-style interface.
       
 21569  *
       
 21570  * However, the more traditional CommonJS-style usage is still available, and documented below.
       
 21571  *
       
 21572  * [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an
       
 21573  * interface for interacting with an object that represents the result of an action that is
       
 21574  * performed asynchronously, and may or may not be finished at any given point in time.
       
 21575  *
       
 21576  * From the perspective of dealing with error handling, deferred and promise APIs are to
       
 21577  * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
       
 21578  *
       
 21579  * ```js
       
 21580  *   // for the purpose of this example let's assume that variables `$q`, `scope` and `okToGreet`
       
 21581  *   // are available in the current lexical scope (they could have been injected or passed in).
       
 21582  *
       
 21583  *   function asyncGreet(name) {
       
 21584  *     var deferred = $q.defer();
       
 21585  *
       
 21586  *     setTimeout(function() {
       
 21587  *       deferred.notify('About to greet ' + name + '.');
       
 21588  *
       
 21589  *       if (okToGreet(name)) {
       
 21590  *         deferred.resolve('Hello, ' + name + '!');
       
 21591  *       } else {
       
 21592  *         deferred.reject('Greeting ' + name + ' is not allowed.');
       
 21593  *       }
       
 21594  *     }, 1000);
       
 21595  *
       
 21596  *     return deferred.promise;
       
 21597  *   }
       
 21598  *
       
 21599  *   var promise = asyncGreet('Robin Hood');
       
 21600  *   promise.then(function(greeting) {
       
 21601  *     alert('Success: ' + greeting);
       
 21602  *   }, function(reason) {
       
 21603  *     alert('Failed: ' + reason);
       
 21604  *   }, function(update) {
       
 21605  *     alert('Got notification: ' + update);
       
 21606  *   });
       
 21607  * ```
       
 21608  *
       
 21609  * At first it might not be obvious why this extra complexity is worth the trouble. The payoff
       
 21610  * comes in the way of guarantees that promise and deferred APIs make, see
       
 21611  * https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md.
       
 21612  *
       
 21613  * Additionally the promise api allows for composition that is very hard to do with the
       
 21614  * traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach.
       
 21615  * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the
       
 21616  * section on serial or parallel joining of promises.
       
 21617  *
       
 21618  * # The Deferred API
       
 21619  *
       
 21620  * A new instance of deferred is constructed by calling `$q.defer()`.
       
 21621  *
       
 21622  * The purpose of the deferred object is to expose the associated Promise instance as well as APIs
       
 21623  * that can be used for signaling the successful or unsuccessful completion, as well as the status
       
 21624  * of the task.
       
 21625  *
       
 21626  * **Methods**
       
 21627  *
       
 21628  * - `resolve(value)` – resolves the derived promise with the `value`. If the value is a rejection
       
 21629  *   constructed via `$q.reject`, the promise will be rejected instead.
       
 21630  * - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to
       
 21631  *   resolving it with a rejection constructed via `$q.reject`.
       
 21632  * - `notify(value)` - provides updates on the status of the promise's execution. This may be called
       
 21633  *   multiple times before the promise is either resolved or rejected.
       
 21634  *
       
 21635  * **Properties**
       
 21636  *
       
 21637  * - promise – `{Promise}` – promise object associated with this deferred.
       
 21638  *
       
 21639  *
       
 21640  * # The Promise API
       
 21641  *
       
 21642  * A new promise instance is created when a deferred instance is created and can be retrieved by
       
 21643  * calling `deferred.promise`.
       
 21644  *
       
 21645  * The purpose of the promise object is to allow for interested parties to get access to the result
       
 21646  * of the deferred task when it completes.
       
 21647  *
       
 21648  * **Methods**
       
 21649  *
       
 21650  * - `then(successCallback, errorCallback, notifyCallback)` – regardless of when the promise was or
       
 21651  *   will be resolved or rejected, `then` calls one of the success or error callbacks asynchronously
       
 21652  *   as soon as the result is available. The callbacks are called with a single argument: the result
       
 21653  *   or rejection reason. Additionally, the notify callback may be called zero or more times to
       
 21654  *   provide a progress indication, before the promise is resolved or rejected.
       
 21655  *
       
 21656  *   This method *returns a new promise* which is resolved or rejected via the return value of the
       
 21657  *   `successCallback`, `errorCallback`. It also notifies via the return value of the
       
 21658  *   `notifyCallback` method. The promise cannot be resolved or rejected from the notifyCallback
       
 21659  *   method.
       
 21660  *
       
 21661  * - `catch(errorCallback)` – shorthand for `promise.then(null, errorCallback)`
       
 21662  *
       
 21663  * - `finally(callback)` – allows you to observe either the fulfillment or rejection of a promise,
       
 21664  *   but to do so without modifying the final value. This is useful to release resources or do some
       
 21665  *   clean-up that needs to be done whether the promise was rejected or resolved. See the [full
       
 21666  *   specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for
       
 21667  *   more information.
       
 21668  *
       
 21669  *   Because `finally` is a reserved word in JavaScript and reserved keywords are not supported as
       
 21670  *   property names by ES3, you'll need to invoke the method like `promise['finally'](callback)` to
       
 21671  *   make your code IE8 and Android 2.x compatible.
       
 21672  *
       
 21673  * # Chaining promises
       
 21674  *
       
 21675  * Because calling the `then` method of a promise returns a new derived promise, it is easily
       
 21676  * possible to create a chain of promises:
       
 21677  *
       
 21678  * ```js
       
 21679  *   promiseB = promiseA.then(function(result) {
       
 21680  *     return result + 1;
       
 21681  *   });
       
 21682  *
       
 21683  *   // promiseB will be resolved immediately after promiseA is resolved and its value
       
 21684  *   // will be the result of promiseA incremented by 1
       
 21685  * ```
       
 21686  *
       
 21687  * It is possible to create chains of any length and since a promise can be resolved with another
       
 21688  * promise (which will defer its resolution further), it is possible to pause/defer resolution of
       
 21689  * the promises at any point in the chain. This makes it possible to implement powerful APIs like
       
 21690  * $http's response interceptors.
       
 21691  *
       
 21692  *
       
 21693  * # Differences between Kris Kowal's Q and $q
       
 21694  *
       
 21695  *  There are two main differences:
       
 21696  *
       
 21697  * - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation
       
 21698  *   mechanism in angular, which means faster propagation of resolution or rejection into your
       
 21699  *   models and avoiding unnecessary browser repaints, which would result in flickering UI.
       
 21700  * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains
       
 21701  *   all the important functionality needed for common async tasks.
       
 21702  *
       
 21703  *  # Testing
       
 21704  *
       
 21705  *  ```js
       
 21706  *    it('should simulate promise', inject(function($q, $rootScope) {
       
 21707  *      var deferred = $q.defer();
       
 21708  *      var promise = deferred.promise;
       
 21709  *      var resolvedValue;
       
 21710  *
       
 21711  *      promise.then(function(value) { resolvedValue = value; });
       
 21712  *      expect(resolvedValue).toBeUndefined();
       
 21713  *
       
 21714  *      // Simulate resolving of promise
       
 21715  *      deferred.resolve(123);
       
 21716  *      // Note that the 'then' function does not get called synchronously.
       
 21717  *      // This is because we want the promise API to always be async, whether or not
       
 21718  *      // it got called synchronously or asynchronously.
       
 21719  *      expect(resolvedValue).toBeUndefined();
       
 21720  *
       
 21721  *      // Propagate promise resolution to 'then' functions using $apply().
       
 21722  *      $rootScope.$apply();
       
 21723  *      expect(resolvedValue).toEqual(123);
       
 21724  *    }));
       
 21725  *  ```
       
 21726  *
       
 21727  * @param {function(function, function)} resolver Function which is responsible for resolving or
       
 21728  *   rejecting the newly created promise. The first parameter is a function which resolves the
       
 21729  *   promise, the second parameter is a function which rejects the promise.
       
 21730  *
       
 21731  * @returns {Promise} The newly created promise.
       
 21732  */
       
 21733 function $QProvider() {
       
 21734 
       
 21735   this.$get = ['$rootScope', '$exceptionHandler', function($rootScope, $exceptionHandler) {
       
 21736     return qFactory(function(callback) {
       
 21737       $rootScope.$evalAsync(callback);
       
 21738     }, $exceptionHandler);
       
 21739   }];
       
 21740 }
       
 21741 
       
 21742 function $$QProvider() {
       
 21743   this.$get = ['$browser', '$exceptionHandler', function($browser, $exceptionHandler) {
       
 21744     return qFactory(function(callback) {
       
 21745       $browser.defer(callback);
       
 21746     }, $exceptionHandler);
       
 21747   }];
       
 21748 }
       
 21749 
       
 21750 /**
       
 21751  * Constructs a promise manager.
       
 21752  *
       
 21753  * @param {function(function)} nextTick Function for executing functions in the next turn.
       
 21754  * @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for
       
 21755  *     debugging purposes.
       
 21756  * @returns {object} Promise manager.
       
 21757  */
       
 21758 function qFactory(nextTick, exceptionHandler) {
       
 21759   var $qMinErr = minErr('$q', TypeError);
       
 21760   function callOnce(self, resolveFn, rejectFn) {
       
 21761     var called = false;
       
 21762     function wrap(fn) {
       
 21763       return function(value) {
       
 21764         if (called) return;
       
 21765         called = true;
       
 21766         fn.call(self, value);
       
 21767       };
       
 21768     }
       
 21769 
       
 21770     return [wrap(resolveFn), wrap(rejectFn)];
       
 21771   }
       
 21772 
       
 21773   /**
       
 21774    * @ngdoc method
       
 21775    * @name ng.$q#defer
       
 21776    * @kind function
       
 21777    *
       
 21778    * @description
       
 21779    * Creates a `Deferred` object which represents a task which will finish in the future.
       
 21780    *
       
 21781    * @returns {Deferred} Returns a new instance of deferred.
       
 21782    */
       
 21783   var defer = function() {
       
 21784     return new Deferred();
       
 21785   };
       
 21786 
       
 21787   function Promise() {
       
 21788     this.$$state = { status: 0 };
       
 21789   }
       
 21790 
       
 21791   Promise.prototype = {
       
 21792     then: function(onFulfilled, onRejected, progressBack) {
       
 21793       var result = new Deferred();
       
 21794 
       
 21795       this.$$state.pending = this.$$state.pending || [];
       
 21796       this.$$state.pending.push([result, onFulfilled, onRejected, progressBack]);
       
 21797       if (this.$$state.status > 0) scheduleProcessQueue(this.$$state);
       
 21798 
       
 21799       return result.promise;
       
 21800     },
       
 21801 
       
 21802     "catch": function(callback) {
       
 21803       return this.then(null, callback);
       
 21804     },
       
 21805 
       
 21806     "finally": function(callback, progressBack) {
       
 21807       return this.then(function(value) {
       
 21808         return handleCallback(value, true, callback);
       
 21809       }, function(error) {
       
 21810         return handleCallback(error, false, callback);
       
 21811       }, progressBack);
       
 21812     }
       
 21813   };
       
 21814 
       
 21815   //Faster, more basic than angular.bind http://jsperf.com/angular-bind-vs-custom-vs-native
       
 21816   function simpleBind(context, fn) {
       
 21817     return function(value) {
       
 21818       fn.call(context, value);
       
 21819     };
       
 21820   }
       
 21821 
       
 21822   function processQueue(state) {
       
 21823     var fn, promise, pending;
       
 21824 
       
 21825     pending = state.pending;
       
 21826     state.processScheduled = false;
       
 21827     state.pending = undefined;
       
 21828     for (var i = 0, ii = pending.length; i < ii; ++i) {
       
 21829       promise = pending[i][0];
       
 21830       fn = pending[i][state.status];
       
 21831       try {
       
 21832         if (isFunction(fn)) {
       
 21833           promise.resolve(fn(state.value));
       
 21834         } else if (state.status === 1) {
       
 21835           promise.resolve(state.value);
       
 21836         } else {
       
 21837           promise.reject(state.value);
       
 21838         }
       
 21839       } catch(e) {
       
 21840         promise.reject(e);
       
 21841         exceptionHandler(e);
       
 21842       }
       
 21843     }
       
 21844   }
       
 21845 
       
 21846   function scheduleProcessQueue(state) {
       
 21847     if (state.processScheduled || !state.pending) return;
       
 21848     state.processScheduled = true;
       
 21849     nextTick(function() { processQueue(state); });
       
 21850   }
       
 21851 
       
 21852   function Deferred() {
       
 21853     this.promise = new Promise();
       
 21854     //Necessary to support unbound execution :/
       
 21855     this.resolve = simpleBind(this, this.resolve);
       
 21856     this.reject = simpleBind(this, this.reject);
       
 21857     this.notify = simpleBind(this, this.notify);
       
 21858   }
       
 21859 
       
 21860   Deferred.prototype = {
       
 21861     resolve: function(val) {
       
 21862       if (this.promise.$$state.status) return;
       
 21863       if (val === this.promise) {
       
 21864         this.$$reject($qMinErr(
       
 21865           'qcycle',
       
 21866           "Expected promise to be resolved with value other than itself '{0}'",
       
 21867           val));
       
 21868       }
       
 21869       else {
       
 21870         this.$$resolve(val);
       
 21871       }
       
 21872 
       
 21873     },
       
 21874 
       
 21875     $$resolve: function(val) {
       
 21876       var then, fns;
       
 21877 
       
 21878       fns = callOnce(this, this.$$resolve, this.$$reject);
       
 21879       try {
       
 21880         if ((isObject(val) || isFunction(val))) then = val && val.then;
       
 21881         if (isFunction(then)) {
       
 21882           this.promise.$$state.status = -1;
       
 21883           then.call(val, fns[0], fns[1], this.notify);
       
 21884         } else {
       
 21885           this.promise.$$state.value = val;
       
 21886           this.promise.$$state.status = 1;
       
 21887           scheduleProcessQueue(this.promise.$$state);
       
 21888         }
       
 21889       } catch(e) {
       
 21890         fns[1](e);
       
 21891         exceptionHandler(e);
       
 21892       }
       
 21893     },
       
 21894 
       
 21895     reject: function(reason) {
       
 21896       if (this.promise.$$state.status) return;
       
 21897       this.$$reject(reason);
       
 21898     },
       
 21899 
       
 21900     $$reject: function(reason) {
       
 21901       this.promise.$$state.value = reason;
       
 21902       this.promise.$$state.status = 2;
       
 21903       scheduleProcessQueue(this.promise.$$state);
       
 21904     },
       
 21905 
       
 21906     notify: function(progress) {
       
 21907       var callbacks = this.promise.$$state.pending;
       
 21908 
       
 21909       if ((this.promise.$$state.status <= 0) && callbacks && callbacks.length) {
       
 21910         nextTick(function() {
       
 21911           var callback, result;
       
 21912           for (var i = 0, ii = callbacks.length; i < ii; i++) {
       
 21913             result = callbacks[i][0];
       
 21914             callback = callbacks[i][3];
       
 21915             try {
       
 21916               result.notify(isFunction(callback) ? callback(progress) : progress);
       
 21917             } catch(e) {
       
 21918               exceptionHandler(e);
       
 21919             }
       
 21920           }
       
 21921         });
       
 21922       }
       
 21923     }
       
 21924   };
       
 21925 
       
 21926   /**
       
 21927    * @ngdoc method
       
 21928    * @name $q#reject
       
 21929    * @kind function
       
 21930    *
       
 21931    * @description
       
 21932    * Creates a promise that is resolved as rejected with the specified `reason`. This api should be
       
 21933    * used to forward rejection in a chain of promises. If you are dealing with the last promise in
       
 21934    * a promise chain, you don't need to worry about it.
       
 21935    *
       
 21936    * When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of
       
 21937    * `reject` as the `throw` keyword in JavaScript. This also means that if you "catch" an error via
       
 21938    * a promise error callback and you want to forward the error to the promise derived from the
       
 21939    * current promise, you have to "rethrow" the error by returning a rejection constructed via
       
 21940    * `reject`.
       
 21941    *
       
 21942    * ```js
       
 21943    *   promiseB = promiseA.then(function(result) {
       
 21944    *     // success: do something and resolve promiseB
       
 21945    *     //          with the old or a new result
       
 21946    *     return result;
       
 21947    *   }, function(reason) {
       
 21948    *     // error: handle the error if possible and
       
 21949    *     //        resolve promiseB with newPromiseOrValue,
       
 21950    *     //        otherwise forward the rejection to promiseB
       
 21951    *     if (canHandle(reason)) {
       
 21952    *      // handle the error and recover
       
 21953    *      return newPromiseOrValue;
       
 21954    *     }
       
 21955    *     return $q.reject(reason);
       
 21956    *   });
       
 21957    * ```
       
 21958    *
       
 21959    * @param {*} reason Constant, message, exception or an object representing the rejection reason.
       
 21960    * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`.
       
 21961    */
       
 21962   var reject = function(reason) {
       
 21963     var result = new Deferred();
       
 21964     result.reject(reason);
       
 21965     return result.promise;
       
 21966   };
       
 21967 
       
 21968   var makePromise = function makePromise(value, resolved) {
       
 21969     var result = new Deferred();
       
 21970     if (resolved) {
       
 21971       result.resolve(value);
       
 21972     } else {
       
 21973       result.reject(value);
       
 21974     }
       
 21975     return result.promise;
       
 21976   };
       
 21977 
       
 21978   var handleCallback = function handleCallback(value, isResolved, callback) {
       
 21979     var callbackOutput = null;
       
 21980     try {
       
 21981       if (isFunction(callback)) callbackOutput = callback();
       
 21982     } catch(e) {
       
 21983       return makePromise(e, false);
       
 21984     }
       
 21985     if (isPromiseLike(callbackOutput)) {
       
 21986       return callbackOutput.then(function() {
       
 21987         return makePromise(value, isResolved);
       
 21988       }, function(error) {
       
 21989         return makePromise(error, false);
       
 21990       });
       
 21991     } else {
       
 21992       return makePromise(value, isResolved);
       
 21993     }
       
 21994   };
       
 21995 
       
 21996   /**
       
 21997    * @ngdoc method
       
 21998    * @name $q#when
       
 21999    * @kind function
       
 22000    *
       
 22001    * @description
       
 22002    * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise.
       
 22003    * This is useful when you are dealing with an object that might or might not be a promise, or if
       
 22004    * the promise comes from a source that can't be trusted.
       
 22005    *
       
 22006    * @param {*} value Value or a promise
       
 22007    * @returns {Promise} Returns a promise of the passed value or promise
       
 22008    */
       
 22009 
       
 22010 
       
 22011   var when = function(value, callback, errback, progressBack) {
       
 22012     var result = new Deferred();
       
 22013     result.resolve(value);
       
 22014     return result.promise.then(callback, errback, progressBack);
       
 22015   };
       
 22016 
       
 22017   /**
       
 22018    * @ngdoc method
       
 22019    * @name $q#all
       
 22020    * @kind function
       
 22021    *
       
 22022    * @description
       
 22023    * Combines multiple promises into a single promise that is resolved when all of the input
       
 22024    * promises are resolved.
       
 22025    *
       
 22026    * @param {Array.<Promise>|Object.<Promise>} promises An array or hash of promises.
       
 22027    * @returns {Promise} Returns a single promise that will be resolved with an array/hash of values,
       
 22028    *   each value corresponding to the promise at the same index/key in the `promises` array/hash.
       
 22029    *   If any of the promises is resolved with a rejection, this resulting promise will be rejected
       
 22030    *   with the same rejection value.
       
 22031    */
       
 22032 
       
 22033   function all(promises) {
       
 22034     var deferred = new Deferred(),
       
 22035         counter = 0,
       
 22036         results = isArray(promises) ? [] : {};
       
 22037 
       
 22038     forEach(promises, function(promise, key) {
       
 22039       counter++;
       
 22040       when(promise).then(function(value) {
       
 22041         if (results.hasOwnProperty(key)) return;
       
 22042         results[key] = value;
       
 22043         if (!(--counter)) deferred.resolve(results);
       
 22044       }, function(reason) {
       
 22045         if (results.hasOwnProperty(key)) return;
       
 22046         deferred.reject(reason);
       
 22047       });
       
 22048     });
       
 22049 
       
 22050     if (counter === 0) {
       
 22051       deferred.resolve(results);
       
 22052     }
       
 22053 
       
 22054     return deferred.promise;
       
 22055   }
       
 22056 
       
 22057   var $Q = function Q(resolver) {
       
 22058     if (!isFunction(resolver)) {
       
 22059       throw $qMinErr('norslvr', "Expected resolverFn, got '{0}'", resolver);
       
 22060     }
       
 22061 
       
 22062     if (!(this instanceof Q)) {
       
 22063       // More useful when $Q is the Promise itself.
       
 22064       return new Q(resolver);
       
 22065     }
       
 22066 
       
 22067     var deferred = new Deferred();
       
 22068 
       
 22069     function resolveFn(value) {
       
 22070       deferred.resolve(value);
       
 22071     }
       
 22072 
       
 22073     function rejectFn(reason) {
       
 22074       deferred.reject(reason);
       
 22075     }
       
 22076 
       
 22077     resolver(resolveFn, rejectFn);
       
 22078 
       
 22079     return deferred.promise;
       
 22080   };
       
 22081 
       
 22082   $Q.defer = defer;
       
 22083   $Q.reject = reject;
       
 22084   $Q.when = when;
       
 22085   $Q.all = all;
       
 22086 
       
 22087   return $Q;
       
 22088 }
       
 22089 
       
 22090 function $$RAFProvider(){ //rAF
       
 22091   this.$get = ['$window', '$timeout', function($window, $timeout) {
       
 22092     var requestAnimationFrame = $window.requestAnimationFrame ||
       
 22093                                 $window.webkitRequestAnimationFrame ||
       
 22094                                 $window.mozRequestAnimationFrame;
       
 22095 
       
 22096     var cancelAnimationFrame = $window.cancelAnimationFrame ||
       
 22097                                $window.webkitCancelAnimationFrame ||
       
 22098                                $window.mozCancelAnimationFrame ||
       
 22099                                $window.webkitCancelRequestAnimationFrame;
       
 22100 
       
 22101     var rafSupported = !!requestAnimationFrame;
       
 22102     var raf = rafSupported
       
 22103       ? function(fn) {
       
 22104           var id = requestAnimationFrame(fn);
       
 22105           return function() {
       
 22106             cancelAnimationFrame(id);
       
 22107           };
       
 22108         }
       
 22109       : function(fn) {
       
 22110           var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666
       
 22111           return function() {
       
 22112             $timeout.cancel(timer);
       
 22113           };
       
 22114         };
       
 22115 
       
 22116     raf.supported = rafSupported;
       
 22117 
       
 22118     return raf;
       
 22119   }];
       
 22120 }
       
 22121 
       
 22122 /**
       
 22123  * DESIGN NOTES
       
 22124  *
       
 22125  * The design decisions behind the scope are heavily favored for speed and memory consumption.
       
 22126  *
       
 22127  * The typical use of scope is to watch the expressions, which most of the time return the same
       
 22128  * value as last time so we optimize the operation.
       
 22129  *
       
 22130  * Closures construction is expensive in terms of speed as well as memory:
       
 22131  *   - No closures, instead use prototypical inheritance for API
       
 22132  *   - Internal state needs to be stored on scope directly, which means that private state is
       
 22133  *     exposed as $$____ properties
       
 22134  *
       
 22135  * Loop operations are optimized by using while(count--) { ... }
       
 22136  *   - this means that in order to keep the same order of execution as addition we have to add
       
 22137  *     items to the array at the beginning (unshift) instead of at the end (push)
       
 22138  *
       
 22139  * Child scopes are created and removed often
       
 22140  *   - Using an array would be slow since inserts in middle are expensive so we use linked list
       
 22141  *
       
 22142  * There are few watches then a lot of observers. This is why you don't want the observer to be
       
 22143  * implemented in the same way as watch. Watch requires return of initialization function which
       
 22144  * are expensive to construct.
       
 22145  */
       
 22146 
       
 22147 
       
 22148 /**
       
 22149  * @ngdoc provider
       
 22150  * @name $rootScopeProvider
       
 22151  * @description
       
 22152  *
       
 22153  * Provider for the $rootScope service.
       
 22154  */
       
 22155 
       
 22156 /**
       
 22157  * @ngdoc method
       
 22158  * @name $rootScopeProvider#digestTtl
       
 22159  * @description
       
 22160  *
       
 22161  * Sets the number of `$digest` iterations the scope should attempt to execute before giving up and
       
 22162  * assuming that the model is unstable.
       
 22163  *
       
 22164  * The current default is 10 iterations.
       
 22165  *
       
 22166  * In complex applications it's possible that the dependencies between `$watch`s will result in
       
 22167  * several digest iterations. However if an application needs more than the default 10 digest
       
 22168  * iterations for its model to stabilize then you should investigate what is causing the model to
       
 22169  * continuously change during the digest.
       
 22170  *
       
 22171  * Increasing the TTL could have performance implications, so you should not change it without
       
 22172  * proper justification.
       
 22173  *
       
 22174  * @param {number} limit The number of digest iterations.
       
 22175  */
       
 22176 
       
 22177 
       
 22178 /**
       
 22179  * @ngdoc service
       
 22180  * @name $rootScope
       
 22181  * @description
       
 22182  *
       
 22183  * Every application has a single root {@link ng.$rootScope.Scope scope}.
       
 22184  * All other scopes are descendant scopes of the root scope. Scopes provide separation
       
 22185  * between the model and the view, via a mechanism for watching the model for changes.
       
 22186  * They also provide an event emission/broadcast and subscription facility. See the
       
 22187  * {@link guide/scope developer guide on scopes}.
       
 22188  */
       
 22189 function $RootScopeProvider(){
       
 22190   var TTL = 10;
       
 22191   var $rootScopeMinErr = minErr('$rootScope');
       
 22192   var lastDirtyWatch = null;
       
 22193   var applyAsyncId = null;
       
 22194 
       
 22195   this.digestTtl = function(value) {
       
 22196     if (arguments.length) {
       
 22197       TTL = value;
       
 22198     }
       
 22199     return TTL;
       
 22200   };
       
 22201 
       
 22202   this.$get = ['$injector', '$exceptionHandler', '$parse', '$browser',
       
 22203       function( $injector,   $exceptionHandler,   $parse,   $browser) {
       
 22204 
       
 22205     /**
       
 22206      * @ngdoc type
       
 22207      * @name $rootScope.Scope
       
 22208      *
       
 22209      * @description
       
 22210      * A root scope can be retrieved using the {@link ng.$rootScope $rootScope} key from the
       
 22211      * {@link auto.$injector $injector}. Child scopes are created using the
       
 22212      * {@link ng.$rootScope.Scope#$new $new()} method. (Most scopes are created automatically when
       
 22213      * compiled HTML template is executed.)
       
 22214      *
       
 22215      * Here is a simple scope snippet to show how you can interact with the scope.
       
 22216      * ```html
       
 22217      * <file src="./test/ng/rootScopeSpec.js" tag="docs1" />
       
 22218      * ```
       
 22219      *
       
 22220      * # Inheritance
       
 22221      * A scope can inherit from a parent scope, as in this example:
       
 22222      * ```js
       
 22223          var parent = $rootScope;
       
 22224          var child = parent.$new();
       
 22225 
       
 22226          parent.salutation = "Hello";
       
 22227          child.name = "World";
       
 22228          expect(child.salutation).toEqual('Hello');
       
 22229 
       
 22230          child.salutation = "Welcome";
       
 22231          expect(child.salutation).toEqual('Welcome');
       
 22232          expect(parent.salutation).toEqual('Hello');
       
 22233      * ```
       
 22234      *
       
 22235      *
       
 22236      * @param {Object.<string, function()>=} providers Map of service factory which need to be
       
 22237      *                                       provided for the current scope. Defaults to {@link ng}.
       
 22238      * @param {Object.<string, *>=} instanceCache Provides pre-instantiated services which should
       
 22239      *                              append/override services provided by `providers`. This is handy
       
 22240      *                              when unit-testing and having the need to override a default
       
 22241      *                              service.
       
 22242      * @returns {Object} Newly created scope.
       
 22243      *
       
 22244      */
       
 22245     function Scope() {
       
 22246       this.$id = nextUid();
       
 22247       this.$$phase = this.$parent = this.$$watchers =
       
 22248                      this.$$nextSibling = this.$$prevSibling =
       
 22249                      this.$$childHead = this.$$childTail = null;
       
 22250       this.$root = this;
       
 22251       this.$$destroyed = false;
       
 22252       this.$$listeners = {};
       
 22253       this.$$listenerCount = {};
       
 22254       this.$$isolateBindings = null;
       
 22255     }
       
 22256 
       
 22257     /**
       
 22258      * @ngdoc property
       
 22259      * @name $rootScope.Scope#$id
       
 22260      *
       
 22261      * @description
       
 22262      * Unique scope ID (monotonically increasing) useful for debugging.
       
 22263      */
       
 22264 
       
 22265      /**
       
 22266       * @ngdoc property
       
 22267       * @name $rootScope.Scope#$parent
       
 22268       *
       
 22269       * @description
       
 22270       * Reference to the parent scope.
       
 22271       */
       
 22272 
       
 22273       /**
       
 22274        * @ngdoc property
       
 22275        * @name $rootScope.Scope#$root
       
 22276        *
       
 22277        * @description
       
 22278        * Reference to the root scope.
       
 22279        */
       
 22280 
       
 22281     Scope.prototype = {
       
 22282       constructor: Scope,
       
 22283       /**
       
 22284        * @ngdoc method
       
 22285        * @name $rootScope.Scope#$new
       
 22286        * @kind function
       
 22287        *
       
 22288        * @description
       
 22289        * Creates a new child {@link ng.$rootScope.Scope scope}.
       
 22290        *
       
 22291        * The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} event.
       
 22292        * The scope can be removed from the scope hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}.
       
 22293        *
       
 22294        * {@link ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is
       
 22295        * desired for the scope and its child scopes to be permanently detached from the parent and
       
 22296        * thus stop participating in model change detection and listener notification by invoking.
       
 22297        *
       
 22298        * @param {boolean} isolate If true, then the scope does not prototypically inherit from the
       
 22299        *         parent scope. The scope is isolated, as it can not see parent scope properties.
       
 22300        *         When creating widgets, it is useful for the widget to not accidentally read parent
       
 22301        *         state.
       
 22302        *
       
 22303        * @param {Scope} [parent=this] The {@link ng.$rootScope.Scope `Scope`} that will be the `$parent`
       
 22304        *                              of the newly created scope. Defaults to `this` scope if not provided.
       
 22305        *                              This is used when creating a transclude scope to correctly place it
       
 22306        *                              in the scope hierarchy while maintaining the correct prototypical
       
 22307        *                              inheritance.
       
 22308        *
       
 22309        * @returns {Object} The newly created child scope.
       
 22310        *
       
 22311        */
       
 22312       $new: function(isolate, parent) {
       
 22313         var child;
       
 22314 
       
 22315         parent = parent || this;
       
 22316 
       
 22317         if (isolate) {
       
 22318           child = new Scope();
       
 22319           child.$root = this.$root;
       
 22320         } else {
       
 22321           // Only create a child scope class if somebody asks for one,
       
 22322           // but cache it to allow the VM to optimize lookups.
       
 22323           if (!this.$$ChildScope) {
       
 22324             this.$$ChildScope = function ChildScope() {
       
 22325               this.$$watchers = this.$$nextSibling =
       
 22326                   this.$$childHead = this.$$childTail = null;
       
 22327               this.$$listeners = {};
       
 22328               this.$$listenerCount = {};
       
 22329               this.$id = nextUid();
       
 22330               this.$$ChildScope = null;
       
 22331             };
       
 22332             this.$$ChildScope.prototype = this;
       
 22333           }
       
 22334           child = new this.$$ChildScope();
       
 22335         }
       
 22336         child.$parent = parent;
       
 22337         child.$$prevSibling = parent.$$childTail;
       
 22338         if (parent.$$childHead) {
       
 22339           parent.$$childTail.$$nextSibling = child;
       
 22340           parent.$$childTail = child;
       
 22341         } else {
       
 22342           parent.$$childHead = parent.$$childTail = child;
       
 22343         }
       
 22344 
       
 22345         // When the new scope is not isolated or we inherit from `this`, and
       
 22346         // the parent scope is destroyed, the property `$$destroyed` is inherited
       
 22347         // prototypically. In all other cases, this property needs to be set
       
 22348         // when the parent scope is destroyed.
       
 22349         // The listener needs to be added after the parent is set
       
 22350         if (isolate || parent != this) child.$on('$destroy', destroyChild);
       
 22351 
       
 22352         return child;
       
 22353 
       
 22354         function destroyChild() {
       
 22355           child.$$destroyed = true;
       
 22356         }
       
 22357       },
       
 22358 
       
 22359       /**
       
 22360        * @ngdoc method
       
 22361        * @name $rootScope.Scope#$watch
       
 22362        * @kind function
       
 22363        *
       
 22364        * @description
       
 22365        * Registers a `listener` callback to be executed whenever the `watchExpression` changes.
       
 22366        *
       
 22367        * - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#$digest
       
 22368        *   $digest()} and should return the value that will be watched. (Since
       
 22369        *   {@link ng.$rootScope.Scope#$digest $digest()} reruns when it detects changes the
       
 22370        *   `watchExpression` can execute multiple times per
       
 22371        *   {@link ng.$rootScope.Scope#$digest $digest()} and should be idempotent.)
       
 22372        * - The `listener` is called only when the value from the current `watchExpression` and the
       
 22373        *   previous call to `watchExpression` are not equal (with the exception of the initial run,
       
 22374        *   see below). Inequality is determined according to reference inequality,
       
 22375        *   [strict comparison](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators)
       
 22376        *    via the `!==` Javascript operator, unless `objectEquality == true`
       
 22377        *   (see next point)
       
 22378        * - When `objectEquality == true`, inequality of the `watchExpression` is determined
       
 22379        *   according to the {@link angular.equals} function. To save the value of the object for
       
 22380        *   later comparison, the {@link angular.copy} function is used. This therefore means that
       
 22381        *   watching complex objects will have adverse memory and performance implications.
       
 22382        * - The watch `listener` may change the model, which may trigger other `listener`s to fire.
       
 22383        *   This is achieved by rerunning the watchers until no changes are detected. The rerun
       
 22384        *   iteration limit is 10 to prevent an infinite loop deadlock.
       
 22385        *
       
 22386        *
       
 22387        * If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called,
       
 22388        * you can register a `watchExpression` function with no `listener`. (Since `watchExpression`
       
 22389        * can execute multiple times per {@link ng.$rootScope.Scope#$digest $digest} cycle when a
       
 22390        * change is detected, be prepared for multiple calls to your listener.)
       
 22391        *
       
 22392        * After a watcher is registered with the scope, the `listener` fn is called asynchronously
       
 22393        * (via {@link ng.$rootScope.Scope#$evalAsync $evalAsync}) to initialize the
       
 22394        * watcher. In rare cases, this is undesirable because the listener is called when the result
       
 22395        * of `watchExpression` didn't change. To detect this scenario within the `listener` fn, you
       
 22396        * can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the
       
 22397        * listener was called due to initialization.
       
 22398        *
       
 22399        *
       
 22400        *
       
 22401        * # Example
       
 22402        * ```js
       
 22403            // let's assume that scope was dependency injected as the $rootScope
       
 22404            var scope = $rootScope;
       
 22405            scope.name = 'misko';
       
 22406            scope.counter = 0;
       
 22407 
       
 22408            expect(scope.counter).toEqual(0);
       
 22409            scope.$watch('name', function(newValue, oldValue) {
       
 22410              scope.counter = scope.counter + 1;
       
 22411            });
       
 22412            expect(scope.counter).toEqual(0);
       
 22413 
       
 22414            scope.$digest();
       
 22415            // the listener is always called during the first $digest loop after it was registered
       
 22416            expect(scope.counter).toEqual(1);
       
 22417 
       
 22418            scope.$digest();
       
 22419            // but now it will not be called unless the value changes
       
 22420            expect(scope.counter).toEqual(1);
       
 22421 
       
 22422            scope.name = 'adam';
       
 22423            scope.$digest();
       
 22424            expect(scope.counter).toEqual(2);
       
 22425 
       
 22426 
       
 22427 
       
 22428            // Using a function as a watchExpression
       
 22429            var food;
       
 22430            scope.foodCounter = 0;
       
 22431            expect(scope.foodCounter).toEqual(0);
       
 22432            scope.$watch(
       
 22433              // This function returns the value being watched. It is called for each turn of the $digest loop
       
 22434              function() { return food; },
       
 22435              // This is the change listener, called when the value returned from the above function changes
       
 22436              function(newValue, oldValue) {
       
 22437                if ( newValue !== oldValue ) {
       
 22438                  // Only increment the counter if the value changed
       
 22439                  scope.foodCounter = scope.foodCounter + 1;
       
 22440                }
       
 22441              }
       
 22442            );
       
 22443            // No digest has been run so the counter will be zero
       
 22444            expect(scope.foodCounter).toEqual(0);
       
 22445 
       
 22446            // Run the digest but since food has not changed count will still be zero
       
 22447            scope.$digest();
       
 22448            expect(scope.foodCounter).toEqual(0);
       
 22449 
       
 22450            // Update food and run digest.  Now the counter will increment
       
 22451            food = 'cheeseburger';
       
 22452            scope.$digest();
       
 22453            expect(scope.foodCounter).toEqual(1);
       
 22454 
       
 22455        * ```
       
 22456        *
       
 22457        *
       
 22458        *
       
 22459        * @param {(function()|string)} watchExpression Expression that is evaluated on each
       
 22460        *    {@link ng.$rootScope.Scope#$digest $digest} cycle. A change in the return value triggers
       
 22461        *    a call to the `listener`.
       
 22462        *
       
 22463        *    - `string`: Evaluated as {@link guide/expression expression}
       
 22464        *    - `function(scope)`: called with current `scope` as a parameter.
       
 22465        * @param {function(newVal, oldVal, scope)} listener Callback called whenever the value
       
 22466        *    of `watchExpression` changes.
       
 22467        *
       
 22468        *    - `newVal` contains the current value of the `watchExpression`
       
 22469        *    - `oldVal` contains the previous value of the `watchExpression`
       
 22470        *    - `scope` refers to the current scope
       
 22471        * @param {boolean=} objectEquality Compare for object equality using {@link angular.equals} instead of
       
 22472        *     comparing for reference equality.
       
 22473        * @returns {function()} Returns a deregistration function for this listener.
       
 22474        */
       
 22475       $watch: function(watchExp, listener, objectEquality) {
       
 22476         var get = $parse(watchExp);
       
 22477 
       
 22478         if (get.$$watchDelegate) {
       
 22479           return get.$$watchDelegate(this, listener, objectEquality, get);
       
 22480         }
       
 22481         var scope = this,
       
 22482             array = scope.$$watchers,
       
 22483             watcher = {
       
 22484               fn: listener,
       
 22485               last: initWatchVal,
       
 22486               get: get,
       
 22487               exp: watchExp,
       
 22488               eq: !!objectEquality
       
 22489             };
       
 22490 
       
 22491         lastDirtyWatch = null;
       
 22492 
       
 22493         if (!isFunction(listener)) {
       
 22494           watcher.fn = noop;
       
 22495         }
       
 22496 
       
 22497         if (!array) {
       
 22498           array = scope.$$watchers = [];
       
 22499         }
       
 22500         // we use unshift since we use a while loop in $digest for speed.
       
 22501         // the while loop reads in reverse order.
       
 22502         array.unshift(watcher);
       
 22503 
       
 22504         return function deregisterWatch() {
       
 22505           arrayRemove(array, watcher);
       
 22506           lastDirtyWatch = null;
       
 22507         };
       
 22508       },
       
 22509 
       
 22510       /**
       
 22511        * @ngdoc method
       
 22512        * @name $rootScope.Scope#$watchGroup
       
 22513        * @kind function
       
 22514        *
       
 22515        * @description
       
 22516        * A variant of {@link ng.$rootScope.Scope#$watch $watch()} where it watches an array of `watchExpressions`.
       
 22517        * If any one expression in the collection changes the `listener` is executed.
       
 22518        *
       
 22519        * - The items in the `watchExpressions` array are observed via standard $watch operation and are examined on every
       
 22520        *   call to $digest() to see if any items changes.
       
 22521        * - The `listener` is called whenever any expression in the `watchExpressions` array changes.
       
 22522        *
       
 22523        * @param {Array.<string|Function(scope)>} watchExpressions Array of expressions that will be individually
       
 22524        * watched using {@link ng.$rootScope.Scope#$watch $watch()}
       
 22525        *
       
 22526        * @param {function(newValues, oldValues, scope)} listener Callback called whenever the return value of any
       
 22527        *    expression in `watchExpressions` changes
       
 22528        *    The `newValues` array contains the current values of the `watchExpressions`, with the indexes matching
       
 22529        *    those of `watchExpression`
       
 22530        *    and the `oldValues` array contains the previous values of the `watchExpressions`, with the indexes matching
       
 22531        *    those of `watchExpression`
       
 22532        *    The `scope` refers to the current scope.
       
 22533        * @returns {function()} Returns a de-registration function for all listeners.
       
 22534        */
       
 22535       $watchGroup: function(watchExpressions, listener) {
       
 22536         var oldValues = new Array(watchExpressions.length);
       
 22537         var newValues = new Array(watchExpressions.length);
       
 22538         var deregisterFns = [];
       
 22539         var self = this;
       
 22540         var changeReactionScheduled = false;
       
 22541         var firstRun = true;
       
 22542 
       
 22543         if (!watchExpressions.length) {
       
 22544           // No expressions means we call the listener ASAP
       
 22545           var shouldCall = true;
       
 22546           self.$evalAsync(function () {
       
 22547             if (shouldCall) listener(newValues, newValues, self);
       
 22548           });
       
 22549           return function deregisterWatchGroup() {
       
 22550             shouldCall = false;
       
 22551           };
       
 22552         }
       
 22553 
       
 22554         if (watchExpressions.length === 1) {
       
 22555           // Special case size of one
       
 22556           return this.$watch(watchExpressions[0], function watchGroupAction(value, oldValue, scope) {
       
 22557             newValues[0] = value;
       
 22558             oldValues[0] = oldValue;
       
 22559             listener(newValues, (value === oldValue) ? newValues : oldValues, scope);
       
 22560           });
       
 22561         }
       
 22562 
       
 22563         forEach(watchExpressions, function (expr, i) {
       
 22564           var unwatchFn = self.$watch(expr, function watchGroupSubAction(value, oldValue) {
       
 22565             newValues[i] = value;
       
 22566             oldValues[i] = oldValue;
       
 22567             if (!changeReactionScheduled) {
       
 22568               changeReactionScheduled = true;
       
 22569               self.$evalAsync(watchGroupAction);
       
 22570             }
       
 22571           });
       
 22572           deregisterFns.push(unwatchFn);
       
 22573         });
       
 22574 
       
 22575         function watchGroupAction() {
       
 22576           changeReactionScheduled = false;
       
 22577 
       
 22578           if (firstRun) {
       
 22579             firstRun = false;
       
 22580             listener(newValues, newValues, self);
       
 22581           } else {
       
 22582             listener(newValues, oldValues, self);
       
 22583           }
       
 22584         }
       
 22585 
       
 22586         return function deregisterWatchGroup() {
       
 22587           while (deregisterFns.length) {
       
 22588             deregisterFns.shift()();
       
 22589           }
       
 22590         };
       
 22591       },
       
 22592 
       
 22593 
       
 22594       /**
       
 22595        * @ngdoc method
       
 22596        * @name $rootScope.Scope#$watchCollection
       
 22597        * @kind function
       
 22598        *
       
 22599        * @description
       
 22600        * Shallow watches the properties of an object and fires whenever any of the properties change
       
 22601        * (for arrays, this implies watching the array items; for object maps, this implies watching
       
 22602        * the properties). If a change is detected, the `listener` callback is fired.
       
 22603        *
       
 22604        * - The `obj` collection is observed via standard $watch operation and is examined on every
       
 22605        *   call to $digest() to see if any items have been added, removed, or moved.
       
 22606        * - The `listener` is called whenever anything within the `obj` has changed. Examples include
       
 22607        *   adding, removing, and moving items belonging to an object or array.
       
 22608        *
       
 22609        *
       
 22610        * # Example
       
 22611        * ```js
       
 22612           $scope.names = ['igor', 'matias', 'misko', 'james'];
       
 22613           $scope.dataCount = 4;
       
 22614 
       
 22615           $scope.$watchCollection('names', function(newNames, oldNames) {
       
 22616             $scope.dataCount = newNames.length;
       
 22617           });
       
 22618 
       
 22619           expect($scope.dataCount).toEqual(4);
       
 22620           $scope.$digest();
       
 22621 
       
 22622           //still at 4 ... no changes
       
 22623           expect($scope.dataCount).toEqual(4);
       
 22624 
       
 22625           $scope.names.pop();
       
 22626           $scope.$digest();
       
 22627 
       
 22628           //now there's been a change
       
 22629           expect($scope.dataCount).toEqual(3);
       
 22630        * ```
       
 22631        *
       
 22632        *
       
 22633        * @param {string|function(scope)} obj Evaluated as {@link guide/expression expression}. The
       
 22634        *    expression value should evaluate to an object or an array which is observed on each
       
 22635        *    {@link ng.$rootScope.Scope#$digest $digest} cycle. Any shallow change within the
       
 22636        *    collection will trigger a call to the `listener`.
       
 22637        *
       
 22638        * @param {function(newCollection, oldCollection, scope)} listener a callback function called
       
 22639        *    when a change is detected.
       
 22640        *    - The `newCollection` object is the newly modified data obtained from the `obj` expression
       
 22641        *    - The `oldCollection` object is a copy of the former collection data.
       
 22642        *      Due to performance considerations, the`oldCollection` value is computed only if the
       
 22643        *      `listener` function declares two or more arguments.
       
 22644        *    - The `scope` argument refers to the current scope.
       
 22645        *
       
 22646        * @returns {function()} Returns a de-registration function for this listener. When the
       
 22647        *    de-registration function is executed, the internal watch operation is terminated.
       
 22648        */
       
 22649       $watchCollection: function(obj, listener) {
       
 22650         $watchCollectionInterceptor.$stateful = true;
       
 22651 
       
 22652         var self = this;
       
 22653         // the current value, updated on each dirty-check run
       
 22654         var newValue;
       
 22655         // a shallow copy of the newValue from the last dirty-check run,
       
 22656         // updated to match newValue during dirty-check run
       
 22657         var oldValue;
       
 22658         // a shallow copy of the newValue from when the last change happened
       
 22659         var veryOldValue;
       
 22660         // only track veryOldValue if the listener is asking for it
       
 22661         var trackVeryOldValue = (listener.length > 1);
       
 22662         var changeDetected = 0;
       
 22663         var changeDetector = $parse(obj, $watchCollectionInterceptor);
       
 22664         var internalArray = [];
       
 22665         var internalObject = {};
       
 22666         var initRun = true;
       
 22667         var oldLength = 0;
       
 22668 
       
 22669         function $watchCollectionInterceptor(_value) {
       
 22670           newValue = _value;
       
 22671           var newLength, key, bothNaN, newItem, oldItem;
       
 22672 
       
 22673           if (!isObject(newValue)) { // if primitive
       
 22674             if (oldValue !== newValue) {
       
 22675               oldValue = newValue;
       
 22676               changeDetected++;
       
 22677             }
       
 22678           } else if (isArrayLike(newValue)) {
       
 22679             if (oldValue !== internalArray) {
       
 22680               // we are transitioning from something which was not an array into array.
       
 22681               oldValue = internalArray;
       
 22682               oldLength = oldValue.length = 0;
       
 22683               changeDetected++;
       
 22684             }
       
 22685 
       
 22686             newLength = newValue.length;
       
 22687 
       
 22688             if (oldLength !== newLength) {
       
 22689               // if lengths do not match we need to trigger change notification
       
 22690               changeDetected++;
       
 22691               oldValue.length = oldLength = newLength;
       
 22692             }
       
 22693             // copy the items to oldValue and look for changes.
       
 22694             for (var i = 0; i < newLength; i++) {
       
 22695               oldItem = oldValue[i];
       
 22696               newItem = newValue[i];
       
 22697 
       
 22698               bothNaN = (oldItem !== oldItem) && (newItem !== newItem);
       
 22699               if (!bothNaN && (oldItem !== newItem)) {
       
 22700                 changeDetected++;
       
 22701                 oldValue[i] = newItem;
       
 22702               }
       
 22703             }
       
 22704           } else {
       
 22705             if (oldValue !== internalObject) {
       
 22706               // we are transitioning from something which was not an object into object.
       
 22707               oldValue = internalObject = {};
       
 22708               oldLength = 0;
       
 22709               changeDetected++;
       
 22710             }
       
 22711             // copy the items to oldValue and look for changes.
       
 22712             newLength = 0;
       
 22713             for (key in newValue) {
       
 22714               if (newValue.hasOwnProperty(key)) {
       
 22715                 newLength++;
       
 22716                 newItem = newValue[key];
       
 22717                 oldItem = oldValue[key];
       
 22718 
       
 22719                 if (key in oldValue) {
       
 22720                   bothNaN = (oldItem !== oldItem) && (newItem !== newItem);
       
 22721                   if (!bothNaN && (oldItem !== newItem)) {
       
 22722                     changeDetected++;
       
 22723                     oldValue[key] = newItem;
       
 22724                   }
       
 22725                 } else {
       
 22726                   oldLength++;
       
 22727                   oldValue[key] = newItem;
       
 22728                   changeDetected++;
       
 22729                 }
       
 22730               }
       
 22731             }
       
 22732             if (oldLength > newLength) {
       
 22733               // we used to have more keys, need to find them and destroy them.
       
 22734               changeDetected++;
       
 22735               for(key in oldValue) {
       
 22736                 if (!newValue.hasOwnProperty(key)) {
       
 22737                   oldLength--;
       
 22738                   delete oldValue[key];
       
 22739                 }
       
 22740               }
       
 22741             }
       
 22742           }
       
 22743           return changeDetected;
       
 22744         }
       
 22745 
       
 22746         function $watchCollectionAction() {
       
 22747           if (initRun) {
       
 22748             initRun = false;
       
 22749             listener(newValue, newValue, self);
       
 22750           } else {
       
 22751             listener(newValue, veryOldValue, self);
       
 22752           }
       
 22753 
       
 22754           // make a copy for the next time a collection is changed
       
 22755           if (trackVeryOldValue) {
       
 22756             if (!isObject(newValue)) {
       
 22757               //primitive
       
 22758               veryOldValue = newValue;
       
 22759             } else if (isArrayLike(newValue)) {
       
 22760               veryOldValue = new Array(newValue.length);
       
 22761               for (var i = 0; i < newValue.length; i++) {
       
 22762                 veryOldValue[i] = newValue[i];
       
 22763               }
       
 22764             } else { // if object
       
 22765               veryOldValue = {};
       
 22766               for (var key in newValue) {
       
 22767                 if (hasOwnProperty.call(newValue, key)) {
       
 22768                   veryOldValue[key] = newValue[key];
       
 22769                 }
       
 22770               }
       
 22771             }
       
 22772           }
       
 22773         }
       
 22774 
       
 22775         return this.$watch(changeDetector, $watchCollectionAction);
       
 22776       },
       
 22777 
       
 22778       /**
       
 22779        * @ngdoc method
       
 22780        * @name $rootScope.Scope#$digest
       
 22781        * @kind function
       
 22782        *
       
 22783        * @description
       
 22784        * Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and
       
 22785        * its children. Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change
       
 22786        * the model, the `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers}
       
 22787        * until no more listeners are firing. This means that it is possible to get into an infinite
       
 22788        * loop. This function will throw `'Maximum iteration limit exceeded.'` if the number of
       
 22789        * iterations exceeds 10.
       
 22790        *
       
 22791        * Usually, you don't call `$digest()` directly in
       
 22792        * {@link ng.directive:ngController controllers} or in
       
 22793        * {@link ng.$compileProvider#directive directives}.
       
 22794        * Instead, you should call {@link ng.$rootScope.Scope#$apply $apply()} (typically from within
       
 22795        * a {@link ng.$compileProvider#directive directive}), which will force a `$digest()`.
       
 22796        *
       
 22797        * If you want to be notified whenever `$digest()` is called,
       
 22798        * you can register a `watchExpression` function with
       
 22799        * {@link ng.$rootScope.Scope#$watch $watch()} with no `listener`.
       
 22800        *
       
 22801        * In unit tests, you may need to call `$digest()` to simulate the scope life cycle.
       
 22802        *
       
 22803        * # Example
       
 22804        * ```js
       
 22805            var scope = ...;
       
 22806            scope.name = 'misko';
       
 22807            scope.counter = 0;
       
 22808 
       
 22809            expect(scope.counter).toEqual(0);
       
 22810            scope.$watch('name', function(newValue, oldValue) {
       
 22811              scope.counter = scope.counter + 1;
       
 22812            });
       
 22813            expect(scope.counter).toEqual(0);
       
 22814 
       
 22815            scope.$digest();
       
 22816            // the listener is always called during the first $digest loop after it was registered
       
 22817            expect(scope.counter).toEqual(1);
       
 22818 
       
 22819            scope.$digest();
       
 22820            // but now it will not be called unless the value changes
       
 22821            expect(scope.counter).toEqual(1);
       
 22822 
       
 22823            scope.name = 'adam';
       
 22824            scope.$digest();
       
 22825            expect(scope.counter).toEqual(2);
       
 22826        * ```
       
 22827        *
       
 22828        */
       
 22829       $digest: function() {
       
 22830         var watch, value, last,
       
 22831             watchers,
       
 22832             length,
       
 22833             dirty, ttl = TTL,
       
 22834             next, current, target = this,
       
 22835             watchLog = [],
       
 22836             logIdx, logMsg, asyncTask;
       
 22837 
       
 22838         beginPhase('$digest');
       
 22839         // Check for changes to browser url that happened in sync before the call to $digest
       
 22840         $browser.$$checkUrlChange();
       
 22841 
       
 22842         if (this === $rootScope && applyAsyncId !== null) {
       
 22843           // If this is the root scope, and $applyAsync has scheduled a deferred $apply(), then
       
 22844           // cancel the scheduled $apply and flush the queue of expressions to be evaluated.
       
 22845           $browser.defer.cancel(applyAsyncId);
       
 22846           flushApplyAsync();
       
 22847         }
       
 22848 
       
 22849         lastDirtyWatch = null;
       
 22850 
       
 22851         do { // "while dirty" loop
       
 22852           dirty = false;
       
 22853           current = target;
       
 22854 
       
 22855           while(asyncQueue.length) {
       
 22856             try {
       
 22857               asyncTask = asyncQueue.shift();
       
 22858               asyncTask.scope.$eval(asyncTask.expression);
       
 22859             } catch (e) {
       
 22860               $exceptionHandler(e);
       
 22861             }
       
 22862             lastDirtyWatch = null;
       
 22863           }
       
 22864 
       
 22865           traverseScopesLoop:
       
 22866           do { // "traverse the scopes" loop
       
 22867             if ((watchers = current.$$watchers)) {
       
 22868               // process our watches
       
 22869               length = watchers.length;
       
 22870               while (length--) {
       
 22871                 try {
       
 22872                   watch = watchers[length];
       
 22873                   // Most common watches are on primitives, in which case we can short
       
 22874                   // circuit it with === operator, only when === fails do we use .equals
       
 22875                   if (watch) {
       
 22876                     if ((value = watch.get(current)) !== (last = watch.last) &&
       
 22877                         !(watch.eq
       
 22878                             ? equals(value, last)
       
 22879                             : (typeof value === 'number' && typeof last === 'number'
       
 22880                                && isNaN(value) && isNaN(last)))) {
       
 22881                       dirty = true;
       
 22882                       lastDirtyWatch = watch;
       
 22883                       watch.last = watch.eq ? copy(value, null) : value;
       
 22884                       watch.fn(value, ((last === initWatchVal) ? value : last), current);
       
 22885                       if (ttl < 5) {
       
 22886                         logIdx = 4 - ttl;
       
 22887                         if (!watchLog[logIdx]) watchLog[logIdx] = [];
       
 22888                         logMsg = (isFunction(watch.exp))
       
 22889                             ? 'fn: ' + (watch.exp.name || watch.exp.toString())
       
 22890                             : watch.exp;
       
 22891                         logMsg += '; newVal: ' + toJson(value) + '; oldVal: ' + toJson(last);
       
 22892                         watchLog[logIdx].push(logMsg);
       
 22893                       }
       
 22894                     } else if (watch === lastDirtyWatch) {
       
 22895                       // If the most recently dirty watcher is now clean, short circuit since the remaining watchers
       
 22896                       // have already been tested.
       
 22897                       dirty = false;
       
 22898                       break traverseScopesLoop;
       
 22899                     }
       
 22900                   }
       
 22901                 } catch (e) {
       
 22902                   $exceptionHandler(e);
       
 22903                 }
       
 22904               }
       
 22905             }
       
 22906 
       
 22907             // Insanity Warning: scope depth-first traversal
       
 22908             // yes, this code is a bit crazy, but it works and we have tests to prove it!
       
 22909             // this piece should be kept in sync with the traversal in $broadcast
       
 22910             if (!(next = (current.$$childHead ||
       
 22911                 (current !== target && current.$$nextSibling)))) {
       
 22912               while(current !== target && !(next = current.$$nextSibling)) {
       
 22913                 current = current.$parent;
       
 22914               }
       
 22915             }
       
 22916           } while ((current = next));
       
 22917 
       
 22918           // `break traverseScopesLoop;` takes us to here
       
 22919 
       
 22920           if((dirty || asyncQueue.length) && !(ttl--)) {
       
 22921             clearPhase();
       
 22922             throw $rootScopeMinErr('infdig',
       
 22923                 '{0} $digest() iterations reached. Aborting!\n' +
       
 22924                 'Watchers fired in the last 5 iterations: {1}',
       
 22925                 TTL, toJson(watchLog));
       
 22926           }
       
 22927 
       
 22928         } while (dirty || asyncQueue.length);
       
 22929 
       
 22930         clearPhase();
       
 22931 
       
 22932         while(postDigestQueue.length) {
       
 22933           try {
       
 22934             postDigestQueue.shift()();
       
 22935           } catch (e) {
       
 22936             $exceptionHandler(e);
       
 22937           }
       
 22938         }
       
 22939       },
       
 22940 
       
 22941 
       
 22942       /**
       
 22943        * @ngdoc event
       
 22944        * @name $rootScope.Scope#$destroy
       
 22945        * @eventType broadcast on scope being destroyed
       
 22946        *
       
 22947        * @description
       
 22948        * Broadcasted when a scope and its children are being destroyed.
       
 22949        *
       
 22950        * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
       
 22951        * clean up DOM bindings before an element is removed from the DOM.
       
 22952        */
       
 22953 
       
 22954       /**
       
 22955        * @ngdoc method
       
 22956        * @name $rootScope.Scope#$destroy
       
 22957        * @kind function
       
 22958        *
       
 22959        * @description
       
 22960        * Removes the current scope (and all of its children) from the parent scope. Removal implies
       
 22961        * that calls to {@link ng.$rootScope.Scope#$digest $digest()} will no longer
       
 22962        * propagate to the current scope and its children. Removal also implies that the current
       
 22963        * scope is eligible for garbage collection.
       
 22964        *
       
 22965        * The `$destroy()` is usually used by directives such as
       
 22966        * {@link ng.directive:ngRepeat ngRepeat} for managing the
       
 22967        * unrolling of the loop.
       
 22968        *
       
 22969        * Just before a scope is destroyed, a `$destroy` event is broadcasted on this scope.
       
 22970        * Application code can register a `$destroy` event handler that will give it a chance to
       
 22971        * perform any necessary cleanup.
       
 22972        *
       
 22973        * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
       
 22974        * clean up DOM bindings before an element is removed from the DOM.
       
 22975        */
       
 22976       $destroy: function() {
       
 22977         // we can't destroy the root scope or a scope that has been already destroyed
       
 22978         if (this.$$destroyed) return;
       
 22979         var parent = this.$parent;
       
 22980 
       
 22981         this.$broadcast('$destroy');
       
 22982         this.$$destroyed = true;
       
 22983         if (this === $rootScope) return;
       
 22984 
       
 22985         for (var eventName in this.$$listenerCount) {
       
 22986           decrementListenerCount(this, this.$$listenerCount[eventName], eventName);
       
 22987         }
       
 22988 
       
 22989         // sever all the references to parent scopes (after this cleanup, the current scope should
       
 22990         // not be retained by any of our references and should be eligible for garbage collection)
       
 22991         if (parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
       
 22992         if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
       
 22993         if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
       
 22994         if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;
       
 22995 
       
 22996         // Disable listeners, watchers and apply/digest methods
       
 22997         this.$destroy = this.$digest = this.$apply = this.$evalAsync = this.$applyAsync = noop;
       
 22998         this.$on = this.$watch = this.$watchGroup = function() { return noop; };
       
 22999         this.$$listeners = {};
       
 23000 
       
 23001         // All of the code below is bogus code that works around V8's memory leak via optimized code
       
 23002         // and inline caches.
       
 23003         //
       
 23004         // see:
       
 23005         // - https://code.google.com/p/v8/issues/detail?id=2073#c26
       
 23006         // - https://github.com/angular/angular.js/issues/6794#issuecomment-38648909
       
 23007         // - https://github.com/angular/angular.js/issues/1313#issuecomment-10378451
       
 23008 
       
 23009         this.$parent = this.$$nextSibling = this.$$prevSibling = this.$$childHead =
       
 23010             this.$$childTail = this.$root = this.$$watchers = null;
       
 23011       },
       
 23012 
       
 23013       /**
       
 23014        * @ngdoc method
       
 23015        * @name $rootScope.Scope#$eval
       
 23016        * @kind function
       
 23017        *
       
 23018        * @description
       
 23019        * Executes the `expression` on the current scope and returns the result. Any exceptions in
       
 23020        * the expression are propagated (uncaught). This is useful when evaluating Angular
       
 23021        * expressions.
       
 23022        *
       
 23023        * # Example
       
 23024        * ```js
       
 23025            var scope = ng.$rootScope.Scope();
       
 23026            scope.a = 1;
       
 23027            scope.b = 2;
       
 23028 
       
 23029            expect(scope.$eval('a+b')).toEqual(3);
       
 23030            expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3);
       
 23031        * ```
       
 23032        *
       
 23033        * @param {(string|function())=} expression An angular expression to be executed.
       
 23034        *
       
 23035        *    - `string`: execute using the rules as defined in  {@link guide/expression expression}.
       
 23036        *    - `function(scope)`: execute the function with the current `scope` parameter.
       
 23037        *
       
 23038        * @param {(object)=} locals Local variables object, useful for overriding values in scope.
       
 23039        * @returns {*} The result of evaluating the expression.
       
 23040        */
       
 23041       $eval: function(expr, locals) {
       
 23042         return $parse(expr)(this, locals);
       
 23043       },
       
 23044 
       
 23045       /**
       
 23046        * @ngdoc method
       
 23047        * @name $rootScope.Scope#$evalAsync
       
 23048        * @kind function
       
 23049        *
       
 23050        * @description
       
 23051        * Executes the expression on the current scope at a later point in time.
       
 23052        *
       
 23053        * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only
       
 23054        * that:
       
 23055        *
       
 23056        *   - it will execute after the function that scheduled the evaluation (preferably before DOM
       
 23057        *     rendering).
       
 23058        *   - at least one {@link ng.$rootScope.Scope#$digest $digest cycle} will be performed after
       
 23059        *     `expression` execution.
       
 23060        *
       
 23061        * Any exceptions from the execution of the expression are forwarded to the
       
 23062        * {@link ng.$exceptionHandler $exceptionHandler} service.
       
 23063        *
       
 23064        * __Note:__ if this function is called outside of a `$digest` cycle, a new `$digest` cycle
       
 23065        * will be scheduled. However, it is encouraged to always call code that changes the model
       
 23066        * from within an `$apply` call. That includes code evaluated via `$evalAsync`.
       
 23067        *
       
 23068        * @param {(string|function())=} expression An angular expression to be executed.
       
 23069        *
       
 23070        *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
       
 23071        *    - `function(scope)`: execute the function with the current `scope` parameter.
       
 23072        *
       
 23073        */
       
 23074       $evalAsync: function(expr) {
       
 23075         // if we are outside of an $digest loop and this is the first time we are scheduling async
       
 23076         // task also schedule async auto-flush
       
 23077         if (!$rootScope.$$phase && !asyncQueue.length) {
       
 23078           $browser.defer(function() {
       
 23079             if (asyncQueue.length) {
       
 23080               $rootScope.$digest();
       
 23081             }
       
 23082           });
       
 23083         }
       
 23084 
       
 23085         asyncQueue.push({scope: this, expression: expr});
       
 23086       },
       
 23087 
       
 23088       $$postDigest : function(fn) {
       
 23089         postDigestQueue.push(fn);
       
 23090       },
       
 23091 
       
 23092       /**
       
 23093        * @ngdoc method
       
 23094        * @name $rootScope.Scope#$apply
       
 23095        * @kind function
       
 23096        *
       
 23097        * @description
       
 23098        * `$apply()` is used to execute an expression in angular from outside of the angular
       
 23099        * framework. (For example from browser DOM events, setTimeout, XHR or third party libraries).
       
 23100        * Because we are calling into the angular framework we need to perform proper scope life
       
 23101        * cycle of {@link ng.$exceptionHandler exception handling},
       
 23102        * {@link ng.$rootScope.Scope#$digest executing watches}.
       
 23103        *
       
 23104        * ## Life cycle
       
 23105        *
       
 23106        * # Pseudo-Code of `$apply()`
       
 23107        * ```js
       
 23108            function $apply(expr) {
       
 23109              try {
       
 23110                return $eval(expr);
       
 23111              } catch (e) {
       
 23112                $exceptionHandler(e);
       
 23113              } finally {
       
 23114                $root.$digest();
       
 23115              }
       
 23116            }
       
 23117        * ```
       
 23118        *
       
 23119        *
       
 23120        * Scope's `$apply()` method transitions through the following stages:
       
 23121        *
       
 23122        * 1. The {@link guide/expression expression} is executed using the
       
 23123        *    {@link ng.$rootScope.Scope#$eval $eval()} method.
       
 23124        * 2. Any exceptions from the execution of the expression are forwarded to the
       
 23125        *    {@link ng.$exceptionHandler $exceptionHandler} service.
       
 23126        * 3. The {@link ng.$rootScope.Scope#$watch watch} listeners are fired immediately after the
       
 23127        *    expression was executed using the {@link ng.$rootScope.Scope#$digest $digest()} method.
       
 23128        *
       
 23129        *
       
 23130        * @param {(string|function())=} exp An angular expression to be executed.
       
 23131        *
       
 23132        *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
       
 23133        *    - `function(scope)`: execute the function with current `scope` parameter.
       
 23134        *
       
 23135        * @returns {*} The result of evaluating the expression.
       
 23136        */
       
 23137       $apply: function(expr) {
       
 23138         try {
       
 23139           beginPhase('$apply');
       
 23140           return this.$eval(expr);
       
 23141         } catch (e) {
       
 23142           $exceptionHandler(e);
       
 23143         } finally {
       
 23144           clearPhase();
       
 23145           try {
       
 23146             $rootScope.$digest();
       
 23147           } catch (e) {
       
 23148             $exceptionHandler(e);
       
 23149             throw e;
       
 23150           }
       
 23151         }
       
 23152       },
       
 23153 
       
 23154       /**
       
 23155        * @ngdoc method
       
 23156        * @name $rootScope.Scope#$applyAsync
       
 23157        * @kind function
       
 23158        *
       
 23159        * @description
       
 23160        * Schedule the invokation of $apply to occur at a later time. The actual time difference
       
 23161        * varies across browsers, but is typically around ~10 milliseconds.
       
 23162        *
       
 23163        * This can be used to queue up multiple expressions which need to be evaluated in the same
       
 23164        * digest.
       
 23165        *
       
 23166        * @param {(string|function())=} exp An angular expression to be executed.
       
 23167        *
       
 23168        *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
       
 23169        *    - `function(scope)`: execute the function with current `scope` parameter.
       
 23170        */
       
 23171       $applyAsync: function(expr) {
       
 23172         var scope = this;
       
 23173         expr && applyAsyncQueue.push($applyAsyncExpression);
       
 23174         scheduleApplyAsync();
       
 23175 
       
 23176         function $applyAsyncExpression() {
       
 23177           scope.$eval(expr);
       
 23178         }
       
 23179       },
       
 23180 
       
 23181       /**
       
 23182        * @ngdoc method
       
 23183        * @name $rootScope.Scope#$on
       
 23184        * @kind function
       
 23185        *
       
 23186        * @description
       
 23187        * Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for
       
 23188        * discussion of event life cycle.
       
 23189        *
       
 23190        * The event listener function format is: `function(event, args...)`. The `event` object
       
 23191        * passed into the listener has the following attributes:
       
 23192        *
       
 23193        *   - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or
       
 23194        *     `$broadcast`-ed.
       
 23195        *   - `currentScope` - `{Scope}`: the scope that is currently handling the event. Once the
       
 23196        *     event propagates through the scope hierarchy, this property is set to null.
       
 23197        *   - `name` - `{string}`: name of the event.
       
 23198        *   - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel
       
 23199        *     further event propagation (available only for events that were `$emit`-ed).
       
 23200        *   - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag
       
 23201        *     to true.
       
 23202        *   - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.
       
 23203        *
       
 23204        * @param {string} name Event name to listen on.
       
 23205        * @param {function(event, ...args)} listener Function to call when the event is emitted.
       
 23206        * @returns {function()} Returns a deregistration function for this listener.
       
 23207        */
       
 23208       $on: function(name, listener) {
       
 23209         var namedListeners = this.$$listeners[name];
       
 23210         if (!namedListeners) {
       
 23211           this.$$listeners[name] = namedListeners = [];
       
 23212         }
       
 23213         namedListeners.push(listener);
       
 23214 
       
 23215         var current = this;
       
 23216         do {
       
 23217           if (!current.$$listenerCount[name]) {
       
 23218             current.$$listenerCount[name] = 0;
       
 23219           }
       
 23220           current.$$listenerCount[name]++;
       
 23221         } while ((current = current.$parent));
       
 23222 
       
 23223         var self = this;
       
 23224         return function() {
       
 23225           namedListeners[namedListeners.indexOf(listener)] = null;
       
 23226           decrementListenerCount(self, 1, name);
       
 23227         };
       
 23228       },
       
 23229 
       
 23230 
       
 23231       /**
       
 23232        * @ngdoc method
       
 23233        * @name $rootScope.Scope#$emit
       
 23234        * @kind function
       
 23235        *
       
 23236        * @description
       
 23237        * Dispatches an event `name` upwards through the scope hierarchy notifying the
       
 23238        * registered {@link ng.$rootScope.Scope#$on} listeners.
       
 23239        *
       
 23240        * The event life cycle starts at the scope on which `$emit` was called. All
       
 23241        * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
       
 23242        * notified. Afterwards, the event traverses upwards toward the root scope and calls all
       
 23243        * registered listeners along the way. The event will stop propagating if one of the listeners
       
 23244        * cancels it.
       
 23245        *
       
 23246        * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
       
 23247        * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
       
 23248        *
       
 23249        * @param {string} name Event name to emit.
       
 23250        * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
       
 23251        * @return {Object} Event object (see {@link ng.$rootScope.Scope#$on}).
       
 23252        */
       
 23253       $emit: function(name, args) {
       
 23254         var empty = [],
       
 23255             namedListeners,
       
 23256             scope = this,
       
 23257             stopPropagation = false,
       
 23258             event = {
       
 23259               name: name,
       
 23260               targetScope: scope,
       
 23261               stopPropagation: function() {stopPropagation = true;},
       
 23262               preventDefault: function() {
       
 23263                 event.defaultPrevented = true;
       
 23264               },
       
 23265               defaultPrevented: false
       
 23266             },
       
 23267             listenerArgs = concat([event], arguments, 1),
       
 23268             i, length;
       
 23269 
       
 23270         do {
       
 23271           namedListeners = scope.$$listeners[name] || empty;
       
 23272           event.currentScope = scope;
       
 23273           for (i=0, length=namedListeners.length; i<length; i++) {
       
 23274 
       
 23275             // if listeners were deregistered, defragment the array
       
 23276             if (!namedListeners[i]) {
       
 23277               namedListeners.splice(i, 1);
       
 23278               i--;
       
 23279               length--;
       
 23280               continue;
       
 23281             }
       
 23282             try {
       
 23283               //allow all listeners attached to the current scope to run
       
 23284               namedListeners[i].apply(null, listenerArgs);
       
 23285             } catch (e) {
       
 23286               $exceptionHandler(e);
       
 23287             }
       
 23288           }
       
 23289           //if any listener on the current scope stops propagation, prevent bubbling
       
 23290           if (stopPropagation) {
       
 23291             event.currentScope = null;
       
 23292             return event;
       
 23293           }
       
 23294           //traverse upwards
       
 23295           scope = scope.$parent;
       
 23296         } while (scope);
       
 23297 
       
 23298         event.currentScope = null;
       
 23299 
       
 23300         return event;
       
 23301       },
       
 23302 
       
 23303 
       
 23304       /**
       
 23305        * @ngdoc method
       
 23306        * @name $rootScope.Scope#$broadcast
       
 23307        * @kind function
       
 23308        *
       
 23309        * @description
       
 23310        * Dispatches an event `name` downwards to all child scopes (and their children) notifying the
       
 23311        * registered {@link ng.$rootScope.Scope#$on} listeners.
       
 23312        *
       
 23313        * The event life cycle starts at the scope on which `$broadcast` was called. All
       
 23314        * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
       
 23315        * notified. Afterwards, the event propagates to all direct and indirect scopes of the current
       
 23316        * scope and calls all registered listeners along the way. The event cannot be canceled.
       
 23317        *
       
 23318        * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
       
 23319        * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
       
 23320        *
       
 23321        * @param {string} name Event name to broadcast.
       
 23322        * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
       
 23323        * @return {Object} Event object, see {@link ng.$rootScope.Scope#$on}
       
 23324        */
       
 23325       $broadcast: function(name, args) {
       
 23326         var target = this,
       
 23327             current = target,
       
 23328             next = target,
       
 23329             event = {
       
 23330               name: name,
       
 23331               targetScope: target,
       
 23332               preventDefault: function() {
       
 23333                 event.defaultPrevented = true;
       
 23334               },
       
 23335               defaultPrevented: false
       
 23336             };
       
 23337 
       
 23338         if (!target.$$listenerCount[name]) return event;
       
 23339 
       
 23340         var listenerArgs = concat([event], arguments, 1),
       
 23341             listeners, i, length;
       
 23342 
       
 23343         //down while you can, then up and next sibling or up and next sibling until back at root
       
 23344         while ((current = next)) {
       
 23345           event.currentScope = current;
       
 23346           listeners = current.$$listeners[name] || [];
       
 23347           for (i=0, length = listeners.length; i<length; i++) {
       
 23348             // if listeners were deregistered, defragment the array
       
 23349             if (!listeners[i]) {
       
 23350               listeners.splice(i, 1);
       
 23351               i--;
       
 23352               length--;
       
 23353               continue;
       
 23354             }
       
 23355 
       
 23356             try {
       
 23357               listeners[i].apply(null, listenerArgs);
       
 23358             } catch(e) {
       
 23359               $exceptionHandler(e);
       
 23360             }
       
 23361           }
       
 23362 
       
 23363           // Insanity Warning: scope depth-first traversal
       
 23364           // yes, this code is a bit crazy, but it works and we have tests to prove it!
       
 23365           // this piece should be kept in sync with the traversal in $digest
       
 23366           // (though it differs due to having the extra check for $$listenerCount)
       
 23367           if (!(next = ((current.$$listenerCount[name] && current.$$childHead) ||
       
 23368               (current !== target && current.$$nextSibling)))) {
       
 23369             while(current !== target && !(next = current.$$nextSibling)) {
       
 23370               current = current.$parent;
       
 23371             }
       
 23372           }
       
 23373         }
       
 23374 
       
 23375         event.currentScope = null;
       
 23376         return event;
       
 23377       }
       
 23378     };
       
 23379 
       
 23380     var $rootScope = new Scope();
       
 23381 
       
 23382     //The internal queues. Expose them on the $rootScope for debugging/testing purposes.
       
 23383     var asyncQueue = $rootScope.$$asyncQueue = [];
       
 23384     var postDigestQueue = $rootScope.$$postDigestQueue = [];
       
 23385     var applyAsyncQueue = $rootScope.$$applyAsyncQueue = [];
       
 23386 
       
 23387     return $rootScope;
       
 23388 
       
 23389 
       
 23390     function beginPhase(phase) {
       
 23391       if ($rootScope.$$phase) {
       
 23392         throw $rootScopeMinErr('inprog', '{0} already in progress', $rootScope.$$phase);
       
 23393       }
       
 23394 
       
 23395       $rootScope.$$phase = phase;
       
 23396     }
       
 23397 
       
 23398     function clearPhase() {
       
 23399       $rootScope.$$phase = null;
       
 23400     }
       
 23401 
       
 23402 
       
 23403     function decrementListenerCount(current, count, name) {
       
 23404       do {
       
 23405         current.$$listenerCount[name] -= count;
       
 23406 
       
 23407         if (current.$$listenerCount[name] === 0) {
       
 23408           delete current.$$listenerCount[name];
       
 23409         }
       
 23410       } while ((current = current.$parent));
       
 23411     }
       
 23412 
       
 23413     /**
       
 23414      * function used as an initial value for watchers.
       
 23415      * because it's unique we can easily tell it apart from other values
       
 23416      */
       
 23417     function initWatchVal() {}
       
 23418 
       
 23419     function flushApplyAsync() {
       
 23420       while (applyAsyncQueue.length) {
       
 23421         try {
       
 23422           applyAsyncQueue.shift()();
       
 23423         } catch(e) {
       
 23424           $exceptionHandler(e);
       
 23425         }
       
 23426       }
       
 23427       applyAsyncId = null;
       
 23428     }
       
 23429 
       
 23430     function scheduleApplyAsync() {
       
 23431       if (applyAsyncId === null) {
       
 23432         applyAsyncId = $browser.defer(function() {
       
 23433           $rootScope.$apply(flushApplyAsync);
       
 23434         });
       
 23435       }
       
 23436     }
       
 23437   }];
       
 23438 }
       
 23439 
       
 23440 /**
       
 23441  * @description
       
 23442  * Private service to sanitize uris for links and images. Used by $compile and $sanitize.
       
 23443  */
       
 23444 function $$SanitizeUriProvider() {
       
 23445   var aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/,
       
 23446     imgSrcSanitizationWhitelist = /^\s*((https?|ftp|file|blob):|data:image\/)/;
       
 23447 
       
 23448   /**
       
 23449    * @description
       
 23450    * Retrieves or overrides the default regular expression that is used for whitelisting of safe
       
 23451    * urls during a[href] sanitization.
       
 23452    *
       
 23453    * The sanitization is a security measure aimed at prevent XSS attacks via html links.
       
 23454    *
       
 23455    * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
       
 23456    * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
       
 23457    * regular expression. If a match is found, the original url is written into the dom. Otherwise,
       
 23458    * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
       
 23459    *
       
 23460    * @param {RegExp=} regexp New regexp to whitelist urls with.
       
 23461    * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
       
 23462    *    chaining otherwise.
       
 23463    */
       
 23464   this.aHrefSanitizationWhitelist = function(regexp) {
       
 23465     if (isDefined(regexp)) {
       
 23466       aHrefSanitizationWhitelist = regexp;
       
 23467       return this;
       
 23468     }
       
 23469     return aHrefSanitizationWhitelist;
       
 23470   };
       
 23471 
       
 23472 
       
 23473   /**
       
 23474    * @description
       
 23475    * Retrieves or overrides the default regular expression that is used for whitelisting of safe
       
 23476    * urls during img[src] sanitization.
       
 23477    *
       
 23478    * The sanitization is a security measure aimed at prevent XSS attacks via html links.
       
 23479    *
       
 23480    * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
       
 23481    * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
       
 23482    * regular expression. If a match is found, the original url is written into the dom. Otherwise,
       
 23483    * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
       
 23484    *
       
 23485    * @param {RegExp=} regexp New regexp to whitelist urls with.
       
 23486    * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
       
 23487    *    chaining otherwise.
       
 23488    */
       
 23489   this.imgSrcSanitizationWhitelist = function(regexp) {
       
 23490     if (isDefined(regexp)) {
       
 23491       imgSrcSanitizationWhitelist = regexp;
       
 23492       return this;
       
 23493     }
       
 23494     return imgSrcSanitizationWhitelist;
       
 23495   };
       
 23496 
       
 23497   this.$get = function() {
       
 23498     return function sanitizeUri(uri, isImage) {
       
 23499       var regex = isImage ? imgSrcSanitizationWhitelist : aHrefSanitizationWhitelist;
       
 23500       var normalizedVal;
       
 23501       normalizedVal = urlResolve(uri).href;
       
 23502       if (normalizedVal !== '' && !normalizedVal.match(regex)) {
       
 23503         return 'unsafe:'+normalizedVal;
       
 23504       }
       
 23505       return uri;
       
 23506     };
       
 23507   };
       
 23508 }
       
 23509 
       
 23510 var $sceMinErr = minErr('$sce');
       
 23511 
       
 23512 var SCE_CONTEXTS = {
       
 23513   HTML: 'html',
       
 23514   CSS: 'css',
       
 23515   URL: 'url',
       
 23516   // RESOURCE_URL is a subtype of URL used in contexts where a privileged resource is sourced from a
       
 23517   // url.  (e.g. ng-include, script src, templateUrl)
       
 23518   RESOURCE_URL: 'resourceUrl',
       
 23519   JS: 'js'
       
 23520 };
       
 23521 
       
 23522 // Helper functions follow.
       
 23523 
       
 23524 // Copied from:
       
 23525 // http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962
       
 23526 // Prereq: s is a string.
       
 23527 function escapeForRegexp(s) {
       
 23528   return s.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g, '\\$1').
       
 23529            replace(/\x08/g, '\\x08');
       
 23530 }
       
 23531 
       
 23532 
       
 23533 function adjustMatcher(matcher) {
       
 23534   if (matcher === 'self') {
       
 23535     return matcher;
       
 23536   } else if (isString(matcher)) {
       
 23537     // Strings match exactly except for 2 wildcards - '*' and '**'.
       
 23538     // '*' matches any character except those from the set ':/.?&'.
       
 23539     // '**' matches any character (like .* in a RegExp).
       
 23540     // More than 2 *'s raises an error as it's ill defined.
       
 23541     if (matcher.indexOf('***') > -1) {
       
 23542       throw $sceMinErr('iwcard',
       
 23543           'Illegal sequence *** in string matcher.  String: {0}', matcher);
       
 23544     }
       
 23545     matcher = escapeForRegexp(matcher).
       
 23546                   replace('\\*\\*', '.*').
       
 23547                   replace('\\*', '[^:/.?&;]*');
       
 23548     return new RegExp('^' + matcher + '$');
       
 23549   } else if (isRegExp(matcher)) {
       
 23550     // The only other type of matcher allowed is a Regexp.
       
 23551     // Match entire URL / disallow partial matches.
       
 23552     // Flags are reset (i.e. no global, ignoreCase or multiline)
       
 23553     return new RegExp('^' + matcher.source + '$');
       
 23554   } else {
       
 23555     throw $sceMinErr('imatcher',
       
 23556         'Matchers may only be "self", string patterns or RegExp objects');
       
 23557   }
       
 23558 }
       
 23559 
       
 23560 
       
 23561 function adjustMatchers(matchers) {
       
 23562   var adjustedMatchers = [];
       
 23563   if (isDefined(matchers)) {
       
 23564     forEach(matchers, function(matcher) {
       
 23565       adjustedMatchers.push(adjustMatcher(matcher));
       
 23566     });
       
 23567   }
       
 23568   return adjustedMatchers;
       
 23569 }
       
 23570 
       
 23571 
       
 23572 /**
       
 23573  * @ngdoc service
       
 23574  * @name $sceDelegate
       
 23575  * @kind function
       
 23576  *
       
 23577  * @description
       
 23578  *
       
 23579  * `$sceDelegate` is a service that is used by the `$sce` service to provide {@link ng.$sce Strict
       
 23580  * Contextual Escaping (SCE)} services to AngularJS.
       
 23581  *
       
 23582  * Typically, you would configure or override the {@link ng.$sceDelegate $sceDelegate} instead of
       
 23583  * the `$sce` service to customize the way Strict Contextual Escaping works in AngularJS.  This is
       
 23584  * because, while the `$sce` provides numerous shorthand methods, etc., you really only need to
       
 23585  * override 3 core functions (`trustAs`, `getTrusted` and `valueOf`) to replace the way things
       
 23586  * work because `$sce` delegates to `$sceDelegate` for these operations.
       
 23587  *
       
 23588  * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} to configure this service.
       
 23589  *
       
 23590  * The default instance of `$sceDelegate` should work out of the box with little pain.  While you
       
 23591  * can override it completely to change the behavior of `$sce`, the common case would
       
 23592  * involve configuring the {@link ng.$sceDelegateProvider $sceDelegateProvider} instead by setting
       
 23593  * your own whitelists and blacklists for trusting URLs used for loading AngularJS resources such as
       
 23594  * templates.  Refer {@link ng.$sceDelegateProvider#resourceUrlWhitelist
       
 23595  * $sceDelegateProvider.resourceUrlWhitelist} and {@link
       
 23596  * ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
       
 23597  */
       
 23598 
       
 23599 /**
       
 23600  * @ngdoc provider
       
 23601  * @name $sceDelegateProvider
       
 23602  * @description
       
 23603  *
       
 23604  * The `$sceDelegateProvider` provider allows developers to configure the {@link ng.$sceDelegate
       
 23605  * $sceDelegate} service.  This allows one to get/set the whitelists and blacklists used to ensure
       
 23606  * that the URLs used for sourcing Angular templates are safe.  Refer {@link
       
 23607  * ng.$sceDelegateProvider#resourceUrlWhitelist $sceDelegateProvider.resourceUrlWhitelist} and
       
 23608  * {@link ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
       
 23609  *
       
 23610  * For the general details about this service in Angular, read the main page for {@link ng.$sce
       
 23611  * Strict Contextual Escaping (SCE)}.
       
 23612  *
       
 23613  * **Example**:  Consider the following case. <a name="example"></a>
       
 23614  *
       
 23615  * - your app is hosted at url `http://myapp.example.com/`
       
 23616  * - but some of your templates are hosted on other domains you control such as
       
 23617  *   `http://srv01.assets.example.com/`,  `http://srv02.assets.example.com/`, etc.
       
 23618  * - and you have an open redirect at `http://myapp.example.com/clickThru?...`.
       
 23619  *
       
 23620  * Here is what a secure configuration for this scenario might look like:
       
 23621  *
       
 23622  * ```
       
 23623  *  angular.module('myApp', []).config(function($sceDelegateProvider) {
       
 23624  *    $sceDelegateProvider.resourceUrlWhitelist([
       
 23625  *      // Allow same origin resource loads.
       
 23626  *      'self',
       
 23627  *      // Allow loading from our assets domain.  Notice the difference between * and **.
       
 23628  *      'http://srv*.assets.example.com/**'
       
 23629  *    ]);
       
 23630  *
       
 23631  *    // The blacklist overrides the whitelist so the open redirect here is blocked.
       
 23632  *    $sceDelegateProvider.resourceUrlBlacklist([
       
 23633  *      'http://myapp.example.com/clickThru**'
       
 23634  *    ]);
       
 23635  *  });
       
 23636  * ```
       
 23637  */
       
 23638 
       
 23639 function $SceDelegateProvider() {
       
 23640   this.SCE_CONTEXTS = SCE_CONTEXTS;
       
 23641 
       
 23642   // Resource URLs can also be trusted by policy.
       
 23643   var resourceUrlWhitelist = ['self'],
       
 23644       resourceUrlBlacklist = [];
       
 23645 
       
 23646   /**
       
 23647    * @ngdoc method
       
 23648    * @name $sceDelegateProvider#resourceUrlWhitelist
       
 23649    * @kind function
       
 23650    *
       
 23651    * @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value
       
 23652    *     provided.  This must be an array or null.  A snapshot of this array is used so further
       
 23653    *     changes to the array are ignored.
       
 23654    *
       
 23655    *     Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
       
 23656    *     allowed in this array.
       
 23657    *
       
 23658    *     Note: **an empty whitelist array will block all URLs**!
       
 23659    *
       
 23660    * @return {Array} the currently set whitelist array.
       
 23661    *
       
 23662    * The **default value** when no whitelist has been explicitly set is `['self']` allowing only
       
 23663    * same origin resource requests.
       
 23664    *
       
 23665    * @description
       
 23666    * Sets/Gets the whitelist of trusted resource URLs.
       
 23667    */
       
 23668   this.resourceUrlWhitelist = function (value) {
       
 23669     if (arguments.length) {
       
 23670       resourceUrlWhitelist = adjustMatchers(value);
       
 23671     }
       
 23672     return resourceUrlWhitelist;
       
 23673   };
       
 23674 
       
 23675   /**
       
 23676    * @ngdoc method
       
 23677    * @name $sceDelegateProvider#resourceUrlBlacklist
       
 23678    * @kind function
       
 23679    *
       
 23680    * @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value
       
 23681    *     provided.  This must be an array or null.  A snapshot of this array is used so further
       
 23682    *     changes to the array are ignored.
       
 23683    *
       
 23684    *     Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
       
 23685    *     allowed in this array.
       
 23686    *
       
 23687    *     The typical usage for the blacklist is to **block
       
 23688    *     [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as
       
 23689    *     these would otherwise be trusted but actually return content from the redirected domain.
       
 23690    *
       
 23691    *     Finally, **the blacklist overrides the whitelist** and has the final say.
       
 23692    *
       
 23693    * @return {Array} the currently set blacklist array.
       
 23694    *
       
 23695    * The **default value** when no whitelist has been explicitly set is the empty array (i.e. there
       
 23696    * is no blacklist.)
       
 23697    *
       
 23698    * @description
       
 23699    * Sets/Gets the blacklist of trusted resource URLs.
       
 23700    */
       
 23701 
       
 23702   this.resourceUrlBlacklist = function (value) {
       
 23703     if (arguments.length) {
       
 23704       resourceUrlBlacklist = adjustMatchers(value);
       
 23705     }
       
 23706     return resourceUrlBlacklist;
       
 23707   };
       
 23708 
       
 23709   this.$get = ['$injector', function($injector) {
       
 23710 
       
 23711     var htmlSanitizer = function htmlSanitizer(html) {
       
 23712       throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
       
 23713     };
       
 23714 
       
 23715     if ($injector.has('$sanitize')) {
       
 23716       htmlSanitizer = $injector.get('$sanitize');
       
 23717     }
       
 23718 
       
 23719 
       
 23720     function matchUrl(matcher, parsedUrl) {
       
 23721       if (matcher === 'self') {
       
 23722         return urlIsSameOrigin(parsedUrl);
       
 23723       } else {
       
 23724         // definitely a regex.  See adjustMatchers()
       
 23725         return !!matcher.exec(parsedUrl.href);
       
 23726       }
       
 23727     }
       
 23728 
       
 23729     function isResourceUrlAllowedByPolicy(url) {
       
 23730       var parsedUrl = urlResolve(url.toString());
       
 23731       var i, n, allowed = false;
       
 23732       // Ensure that at least one item from the whitelist allows this url.
       
 23733       for (i = 0, n = resourceUrlWhitelist.length; i < n; i++) {
       
 23734         if (matchUrl(resourceUrlWhitelist[i], parsedUrl)) {
       
 23735           allowed = true;
       
 23736           break;
       
 23737         }
       
 23738       }
       
 23739       if (allowed) {
       
 23740         // Ensure that no item from the blacklist blocked this url.
       
 23741         for (i = 0, n = resourceUrlBlacklist.length; i < n; i++) {
       
 23742           if (matchUrl(resourceUrlBlacklist[i], parsedUrl)) {
       
 23743             allowed = false;
       
 23744             break;
       
 23745           }
       
 23746         }
       
 23747       }
       
 23748       return allowed;
       
 23749     }
       
 23750 
       
 23751     function generateHolderType(Base) {
       
 23752       var holderType = function TrustedValueHolderType(trustedValue) {
       
 23753         this.$$unwrapTrustedValue = function() {
       
 23754           return trustedValue;
       
 23755         };
       
 23756       };
       
 23757       if (Base) {
       
 23758         holderType.prototype = new Base();
       
 23759       }
       
 23760       holderType.prototype.valueOf = function sceValueOf() {
       
 23761         return this.$$unwrapTrustedValue();
       
 23762       };
       
 23763       holderType.prototype.toString = function sceToString() {
       
 23764         return this.$$unwrapTrustedValue().toString();
       
 23765       };
       
 23766       return holderType;
       
 23767     }
       
 23768 
       
 23769     var trustedValueHolderBase = generateHolderType(),
       
 23770         byType = {};
       
 23771 
       
 23772     byType[SCE_CONTEXTS.HTML] = generateHolderType(trustedValueHolderBase);
       
 23773     byType[SCE_CONTEXTS.CSS] = generateHolderType(trustedValueHolderBase);
       
 23774     byType[SCE_CONTEXTS.URL] = generateHolderType(trustedValueHolderBase);
       
 23775     byType[SCE_CONTEXTS.JS] = generateHolderType(trustedValueHolderBase);
       
 23776     byType[SCE_CONTEXTS.RESOURCE_URL] = generateHolderType(byType[SCE_CONTEXTS.URL]);
       
 23777 
       
 23778     /**
       
 23779      * @ngdoc method
       
 23780      * @name $sceDelegate#trustAs
       
 23781      *
       
 23782      * @description
       
 23783      * Returns an object that is trusted by angular for use in specified strict
       
 23784      * contextual escaping contexts (such as ng-bind-html, ng-include, any src
       
 23785      * attribute interpolation, any dom event binding attribute interpolation
       
 23786      * such as for onclick,  etc.) that uses the provided value.
       
 23787      * See {@link ng.$sce $sce} for enabling strict contextual escaping.
       
 23788      *
       
 23789      * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
       
 23790      *   resourceUrl, html, js and css.
       
 23791      * @param {*} value The value that that should be considered trusted/safe.
       
 23792      * @returns {*} A value that can be used to stand in for the provided `value` in places
       
 23793      * where Angular expects a $sce.trustAs() return value.
       
 23794      */
       
 23795     function trustAs(type, trustedValue) {
       
 23796       var Constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
       
 23797       if (!Constructor) {
       
 23798         throw $sceMinErr('icontext',
       
 23799             'Attempted to trust a value in invalid context. Context: {0}; Value: {1}',
       
 23800             type, trustedValue);
       
 23801       }
       
 23802       if (trustedValue === null || trustedValue === undefined || trustedValue === '') {
       
 23803         return trustedValue;
       
 23804       }
       
 23805       // All the current contexts in SCE_CONTEXTS happen to be strings.  In order to avoid trusting
       
 23806       // mutable objects, we ensure here that the value passed in is actually a string.
       
 23807       if (typeof trustedValue !== 'string') {
       
 23808         throw $sceMinErr('itype',
       
 23809             'Attempted to trust a non-string value in a content requiring a string: Context: {0}',
       
 23810             type);
       
 23811       }
       
 23812       return new Constructor(trustedValue);
       
 23813     }
       
 23814 
       
 23815     /**
       
 23816      * @ngdoc method
       
 23817      * @name $sceDelegate#valueOf
       
 23818      *
       
 23819      * @description
       
 23820      * If the passed parameter had been returned by a prior call to {@link ng.$sceDelegate#trustAs
       
 23821      * `$sceDelegate.trustAs`}, returns the value that had been passed to {@link
       
 23822      * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.
       
 23823      *
       
 23824      * If the passed parameter is not a value that had been returned by {@link
       
 23825      * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}, returns it as-is.
       
 23826      *
       
 23827      * @param {*} value The result of a prior {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}
       
 23828      *      call or anything else.
       
 23829      * @returns {*} The `value` that was originally provided to {@link ng.$sceDelegate#trustAs
       
 23830      *     `$sceDelegate.trustAs`} if `value` is the result of such a call.  Otherwise, returns
       
 23831      *     `value` unchanged.
       
 23832      */
       
 23833     function valueOf(maybeTrusted) {
       
 23834       if (maybeTrusted instanceof trustedValueHolderBase) {
       
 23835         return maybeTrusted.$$unwrapTrustedValue();
       
 23836       } else {
       
 23837         return maybeTrusted;
       
 23838       }
       
 23839     }
       
 23840 
       
 23841     /**
       
 23842      * @ngdoc method
       
 23843      * @name $sceDelegate#getTrusted
       
 23844      *
       
 23845      * @description
       
 23846      * Takes the result of a {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`} call and
       
 23847      * returns the originally supplied value if the queried context type is a supertype of the
       
 23848      * created type.  If this condition isn't satisfied, throws an exception.
       
 23849      *
       
 23850      * @param {string} type The kind of context in which this value is to be used.
       
 23851      * @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#trustAs
       
 23852      *     `$sceDelegate.trustAs`} call.
       
 23853      * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#trustAs
       
 23854      *     `$sceDelegate.trustAs`} if valid in this context.  Otherwise, throws an exception.
       
 23855      */
       
 23856     function getTrusted(type, maybeTrusted) {
       
 23857       if (maybeTrusted === null || maybeTrusted === undefined || maybeTrusted === '') {
       
 23858         return maybeTrusted;
       
 23859       }
       
 23860       var constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
       
 23861       if (constructor && maybeTrusted instanceof constructor) {
       
 23862         return maybeTrusted.$$unwrapTrustedValue();
       
 23863       }
       
 23864       // If we get here, then we may only take one of two actions.
       
 23865       // 1. sanitize the value for the requested type, or
       
 23866       // 2. throw an exception.
       
 23867       if (type === SCE_CONTEXTS.RESOURCE_URL) {
       
 23868         if (isResourceUrlAllowedByPolicy(maybeTrusted)) {
       
 23869           return maybeTrusted;
       
 23870         } else {
       
 23871           throw $sceMinErr('insecurl',
       
 23872               'Blocked loading resource from url not allowed by $sceDelegate policy.  URL: {0}',
       
 23873               maybeTrusted.toString());
       
 23874         }
       
 23875       } else if (type === SCE_CONTEXTS.HTML) {
       
 23876         return htmlSanitizer(maybeTrusted);
       
 23877       }
       
 23878       throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
       
 23879     }
       
 23880 
       
 23881     return { trustAs: trustAs,
       
 23882              getTrusted: getTrusted,
       
 23883              valueOf: valueOf };
       
 23884   }];
       
 23885 }
       
 23886 
       
 23887 
       
 23888 /**
       
 23889  * @ngdoc provider
       
 23890  * @name $sceProvider
       
 23891  * @description
       
 23892  *
       
 23893  * The $sceProvider provider allows developers to configure the {@link ng.$sce $sce} service.
       
 23894  * -   enable/disable Strict Contextual Escaping (SCE) in a module
       
 23895  * -   override the default implementation with a custom delegate
       
 23896  *
       
 23897  * Read more about {@link ng.$sce Strict Contextual Escaping (SCE)}.
       
 23898  */
       
 23899 
       
 23900 /* jshint maxlen: false*/
       
 23901 
       
 23902 /**
       
 23903  * @ngdoc service
       
 23904  * @name $sce
       
 23905  * @kind function
       
 23906  *
       
 23907  * @description
       
 23908  *
       
 23909  * `$sce` is a service that provides Strict Contextual Escaping services to AngularJS.
       
 23910  *
       
 23911  * # Strict Contextual Escaping
       
 23912  *
       
 23913  * Strict Contextual Escaping (SCE) is a mode in which AngularJS requires bindings in certain
       
 23914  * contexts to result in a value that is marked as safe to use for that context.  One example of
       
 23915  * such a context is binding arbitrary html controlled by the user via `ng-bind-html`.  We refer
       
 23916  * to these contexts as privileged or SCE contexts.
       
 23917  *
       
 23918  * As of version 1.2, Angular ships with SCE enabled by default.
       
 23919  *
       
 23920  * Note:  When enabled (the default), IE8 in quirks mode is not supported.  In this mode, IE8 allows
       
 23921  * one to execute arbitrary javascript by the use of the expression() syntax.  Refer
       
 23922  * <http://blogs.msdn.com/b/ie/archive/2008/10/16/ending-expressions.aspx> to learn more about them.
       
 23923  * You can ensure your document is in standards mode and not quirks mode by adding `<!doctype html>`
       
 23924  * to the top of your HTML document.
       
 23925  *
       
 23926  * SCE assists in writing code in way that (a) is secure by default and (b) makes auditing for
       
 23927  * security vulnerabilities such as XSS, clickjacking, etc. a lot easier.
       
 23928  *
       
 23929  * Here's an example of a binding in a privileged context:
       
 23930  *
       
 23931  * ```
       
 23932  * <input ng-model="userHtml">
       
 23933  * <div ng-bind-html="userHtml"></div>
       
 23934  * ```
       
 23935  *
       
 23936  * Notice that `ng-bind-html` is bound to `userHtml` controlled by the user.  With SCE
       
 23937  * disabled, this application allows the user to render arbitrary HTML into the DIV.
       
 23938  * In a more realistic example, one may be rendering user comments, blog articles, etc. via
       
 23939  * bindings.  (HTML is just one example of a context where rendering user controlled input creates
       
 23940  * security vulnerabilities.)
       
 23941  *
       
 23942  * For the case of HTML, you might use a library, either on the client side, or on the server side,
       
 23943  * to sanitize unsafe HTML before binding to the value and rendering it in the document.
       
 23944  *
       
 23945  * How would you ensure that every place that used these types of bindings was bound to a value that
       
 23946  * was sanitized by your library (or returned as safe for rendering by your server?)  How can you
       
 23947  * ensure that you didn't accidentally delete the line that sanitized the value, or renamed some
       
 23948  * properties/fields and forgot to update the binding to the sanitized value?
       
 23949  *
       
 23950  * To be secure by default, you want to ensure that any such bindings are disallowed unless you can
       
 23951  * determine that something explicitly says it's safe to use a value for binding in that
       
 23952  * context.  You can then audit your code (a simple grep would do) to ensure that this is only done
       
 23953  * for those values that you can easily tell are safe - because they were received from your server,
       
 23954  * sanitized by your library, etc.  You can organize your codebase to help with this - perhaps
       
 23955  * allowing only the files in a specific directory to do this.  Ensuring that the internal API
       
 23956  * exposed by that code doesn't markup arbitrary values as safe then becomes a more manageable task.
       
 23957  *
       
 23958  * In the case of AngularJS' SCE service, one uses {@link ng.$sce#trustAs $sce.trustAs}
       
 23959  * (and shorthand methods such as {@link ng.$sce#trustAsHtml $sce.trustAsHtml}, etc.) to
       
 23960  * obtain values that will be accepted by SCE / privileged contexts.
       
 23961  *
       
 23962  *
       
 23963  * ## How does it work?
       
 23964  *
       
 23965  * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#getTrusted
       
 23966  * $sce.getTrusted(context, value)} rather than to the value directly.  Directives use {@link
       
 23967  * ng.$sce#parse $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the
       
 23968  * {@link ng.$sce#getTrusted $sce.getTrusted} behind the scenes on non-constant literals.
       
 23969  *
       
 23970  * As an example, {@link ng.directive:ngBindHtml ngBindHtml} uses {@link
       
 23971  * ng.$sce#parseAsHtml $sce.parseAsHtml(binding expression)}.  Here's the actual code (slightly
       
 23972  * simplified):
       
 23973  *
       
 23974  * ```
       
 23975  * var ngBindHtmlDirective = ['$sce', function($sce) {
       
 23976  *   return function(scope, element, attr) {
       
 23977  *     scope.$watch($sce.parseAsHtml(attr.ngBindHtml), function(value) {
       
 23978  *       element.html(value || '');
       
 23979  *     });
       
 23980  *   };
       
 23981  * }];
       
 23982  * ```
       
 23983  *
       
 23984  * ## Impact on loading templates
       
 23985  *
       
 23986  * This applies both to the {@link ng.directive:ngInclude `ng-include`} directive as well as
       
 23987  * `templateUrl`'s specified by {@link guide/directive directives}.
       
 23988  *
       
 23989  * By default, Angular only loads templates from the same domain and protocol as the application
       
 23990  * document.  This is done by calling {@link ng.$sce#getTrustedResourceUrl
       
 23991  * $sce.getTrustedResourceUrl} on the template URL.  To load templates from other domains and/or
       
 23992  * protocols, you may either either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist
       
 23993  * them} or {@link ng.$sce#trustAsResourceUrl wrap it} into a trusted value.
       
 23994  *
       
 23995  * *Please note*:
       
 23996  * The browser's
       
 23997  * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
       
 23998  * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
       
 23999  * policy apply in addition to this and may further restrict whether the template is successfully
       
 24000  * loaded.  This means that without the right CORS policy, loading templates from a different domain
       
 24001  * won't work on all browsers.  Also, loading templates from `file://` URL does not work on some
       
 24002  * browsers.
       
 24003  *
       
 24004  * ## This feels like too much overhead
       
 24005  *
       
 24006  * It's important to remember that SCE only applies to interpolation expressions.
       
 24007  *
       
 24008  * If your expressions are constant literals, they're automatically trusted and you don't need to
       
 24009  * call `$sce.trustAs` on them (remember to include the `ngSanitize` module) (e.g.
       
 24010  * `<div ng-bind-html="'<b>implicitly trusted</b>'"></div>`) just works.
       
 24011  *
       
 24012  * Additionally, `a[href]` and `img[src]` automatically sanitize their URLs and do not pass them
       
 24013  * through {@link ng.$sce#getTrusted $sce.getTrusted}.  SCE doesn't play a role here.
       
 24014  *
       
 24015  * The included {@link ng.$sceDelegate $sceDelegate} comes with sane defaults to allow you to load
       
 24016  * templates in `ng-include` from your application's domain without having to even know about SCE.
       
 24017  * It blocks loading templates from other domains or loading templates over http from an https
       
 24018  * served document.  You can change these by setting your own custom {@link
       
 24019  * ng.$sceDelegateProvider#resourceUrlWhitelist whitelists} and {@link
       
 24020  * ng.$sceDelegateProvider#resourceUrlBlacklist blacklists} for matching such URLs.
       
 24021  *
       
 24022  * This significantly reduces the overhead.  It is far easier to pay the small overhead and have an
       
 24023  * application that's secure and can be audited to verify that with much more ease than bolting
       
 24024  * security onto an application later.
       
 24025  *
       
 24026  * <a name="contexts"></a>
       
 24027  * ## What trusted context types are supported?
       
 24028  *
       
 24029  * | Context             | Notes          |
       
 24030  * |---------------------|----------------|
       
 24031  * | `$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. |
       
 24032  * | `$sce.CSS`          | For CSS that's safe to source into the application.  Currently unused.  Feel free to use it in your own directives. |
       
 24033  * | `$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. |
       
 24034  * | `$sce.RESOURCE_URL` | For URLs that are not only safe to follow as links, but whose contents are also safe to include in your application.  Examples include `ng-include`, `src` / `ngSrc` bindings for tags other than `IMG` (e.g. `IFRAME`, `OBJECT`, etc.)  <br><br>Note that `$sce.RESOURCE_URL` makes a stronger statement about the URL than `$sce.URL` does and therefore contexts requiring values trusted for `$sce.RESOURCE_URL` can be used anywhere that values trusted for `$sce.URL` are required. |
       
 24035  * | `$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. |
       
 24036  *
       
 24037  * ## Format of items in {@link ng.$sceDelegateProvider#resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#resourceUrlBlacklist Blacklist} <a name="resourceUrlPatternItem"></a>
       
 24038  *
       
 24039  *  Each element in these arrays must be one of the following:
       
 24040  *
       
 24041  *  - **'self'**
       
 24042  *    - The special **string**, `'self'`, can be used to match against all URLs of the **same
       
 24043  *      domain** as the application document using the **same protocol**.
       
 24044  *  - **String** (except the special value `'self'`)
       
 24045  *    - The string is matched against the full *normalized / absolute URL* of the resource
       
 24046  *      being tested (substring matches are not good enough.)
       
 24047  *    - There are exactly **two wildcard sequences** - `*` and `**`.  All other characters
       
 24048  *      match themselves.
       
 24049  *    - `*`: matches zero or more occurrences of any character other than one of the following 6
       
 24050  *      characters: '`:`', '`/`', '`.`', '`?`', '`&`' and ';'.  It's a useful wildcard for use
       
 24051  *      in a whitelist.
       
 24052  *    - `**`: matches zero or more occurrences of *any* character.  As such, it's not
       
 24053  *      not appropriate to use in for a scheme, domain, etc. as it would match too much.  (e.g.
       
 24054  *      http://**.example.com/ would match http://evil.com/?ignore=.example.com/ and that might
       
 24055  *      not have been the intention.)  Its usage at the very end of the path is ok.  (e.g.
       
 24056  *      http://foo.example.com/templates/**).
       
 24057  *  - **RegExp** (*see caveat below*)
       
 24058  *    - *Caveat*:  While regular expressions are powerful and offer great flexibility,  their syntax
       
 24059  *      (and all the inevitable escaping) makes them *harder to maintain*.  It's easy to
       
 24060  *      accidentally introduce a bug when one updates a complex expression (imho, all regexes should
       
 24061  *      have good test coverage.).  For instance, the use of `.` in the regex is correct only in a
       
 24062  *      small number of cases.  A `.` character in the regex used when matching the scheme or a
       
 24063  *      subdomain could be matched against a `:` or literal `.` that was likely not intended.   It
       
 24064  *      is highly recommended to use the string patterns and only fall back to regular expressions
       
 24065  *      if they as a last resort.
       
 24066  *    - The regular expression must be an instance of RegExp (i.e. not a string.)  It is
       
 24067  *      matched against the **entire** *normalized / absolute URL* of the resource being tested
       
 24068  *      (even when the RegExp did not have the `^` and `$` codes.)  In addition, any flags
       
 24069  *      present on the RegExp (such as multiline, global, ignoreCase) are ignored.
       
 24070  *    - If you are generating your JavaScript from some other templating engine (not
       
 24071  *      recommended, e.g. in issue [#4006](https://github.com/angular/angular.js/issues/4006)),
       
 24072  *      remember to escape your regular expression (and be aware that you might need more than
       
 24073  *      one level of escaping depending on your templating engine and the way you interpolated
       
 24074  *      the value.)  Do make use of your platform's escaping mechanism as it might be good
       
 24075  *      enough before coding your own.  e.g. Ruby has
       
 24076  *      [Regexp.escape(str)](http://www.ruby-doc.org/core-2.0.0/Regexp.html#method-c-escape)
       
 24077  *      and Python has [re.escape](http://docs.python.org/library/re.html#re.escape).
       
 24078  *      Javascript lacks a similar built in function for escaping.  Take a look at Google
       
 24079  *      Closure library's [goog.string.regExpEscape(s)](
       
 24080  *      http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962).
       
 24081  *
       
 24082  * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} for an example.
       
 24083  *
       
 24084  * ## Show me an example using SCE.
       
 24085  *
       
 24086  * <example module="mySceApp" deps="angular-sanitize.js">
       
 24087  * <file name="index.html">
       
 24088  *   <div ng-controller="AppController as myCtrl">
       
 24089  *     <i ng-bind-html="myCtrl.explicitlyTrustedHtml" id="explicitlyTrustedHtml"></i><br><br>
       
 24090  *     <b>User comments</b><br>
       
 24091  *     By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when
       
 24092  *     $sanitize is available.  If $sanitize isn't available, this results in an error instead of an
       
 24093  *     exploit.
       
 24094  *     <div class="well">
       
 24095  *       <div ng-repeat="userComment in myCtrl.userComments">
       
 24096  *         <b>{{userComment.name}}</b>:
       
 24097  *         <span ng-bind-html="userComment.htmlComment" class="htmlComment"></span>
       
 24098  *         <br>
       
 24099  *       </div>
       
 24100  *     </div>
       
 24101  *   </div>
       
 24102  * </file>
       
 24103  *
       
 24104  * <file name="script.js">
       
 24105  *   angular.module('mySceApp', ['ngSanitize'])
       
 24106  *     .controller('AppController', ['$http', '$templateCache', '$sce',
       
 24107  *       function($http, $templateCache, $sce) {
       
 24108  *         var self = this;
       
 24109  *         $http.get("test_data.json", {cache: $templateCache}).success(function(userComments) {
       
 24110  *           self.userComments = userComments;
       
 24111  *         });
       
 24112  *         self.explicitlyTrustedHtml = $sce.trustAsHtml(
       
 24113  *             '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
       
 24114  *             'sanitization.&quot;">Hover over this text.</span>');
       
 24115  *       }]);
       
 24116  * </file>
       
 24117  *
       
 24118  * <file name="test_data.json">
       
 24119  * [
       
 24120  *   { "name": "Alice",
       
 24121  *     "htmlComment":
       
 24122  *         "<span onmouseover='this.textContent=\"PWN3D!\"'>Is <i>anyone</i> reading this?</span>"
       
 24123  *   },
       
 24124  *   { "name": "Bob",
       
 24125  *     "htmlComment": "<i>Yes!</i>  Am I the only other one?"
       
 24126  *   }
       
 24127  * ]
       
 24128  * </file>
       
 24129  *
       
 24130  * <file name="protractor.js" type="protractor">
       
 24131  *   describe('SCE doc demo', function() {
       
 24132  *     it('should sanitize untrusted values', function() {
       
 24133  *       expect(element.all(by.css('.htmlComment')).first().getInnerHtml())
       
 24134  *           .toBe('<span>Is <i>anyone</i> reading this?</span>');
       
 24135  *     });
       
 24136  *
       
 24137  *     it('should NOT sanitize explicitly trusted values', function() {
       
 24138  *       expect(element(by.id('explicitlyTrustedHtml')).getInnerHtml()).toBe(
       
 24139  *           '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
       
 24140  *           'sanitization.&quot;">Hover over this text.</span>');
       
 24141  *     });
       
 24142  *   });
       
 24143  * </file>
       
 24144  * </example>
       
 24145  *
       
 24146  *
       
 24147  *
       
 24148  * ## Can I disable SCE completely?
       
 24149  *
       
 24150  * Yes, you can.  However, this is strongly discouraged.  SCE gives you a lot of security benefits
       
 24151  * for little coding overhead.  It will be much harder to take an SCE disabled application and
       
 24152  * either secure it on your own or enable SCE at a later stage.  It might make sense to disable SCE
       
 24153  * for cases where you have a lot of existing code that was written before SCE was introduced and
       
 24154  * you're migrating them a module at a time.
       
 24155  *
       
 24156  * That said, here's how you can completely disable SCE:
       
 24157  *
       
 24158  * ```
       
 24159  * angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) {
       
 24160  *   // Completely disable SCE.  For demonstration purposes only!
       
 24161  *   // Do not use in new projects.
       
 24162  *   $sceProvider.enabled(false);
       
 24163  * });
       
 24164  * ```
       
 24165  *
       
 24166  */
       
 24167 /* jshint maxlen: 100 */
       
 24168 
       
 24169 function $SceProvider() {
       
 24170   var enabled = true;
       
 24171 
       
 24172   /**
       
 24173    * @ngdoc method
       
 24174    * @name $sceProvider#enabled
       
 24175    * @kind function
       
 24176    *
       
 24177    * @param {boolean=} value If provided, then enables/disables SCE.
       
 24178    * @return {boolean} true if SCE is enabled, false otherwise.
       
 24179    *
       
 24180    * @description
       
 24181    * Enables/disables SCE and returns the current value.
       
 24182    */
       
 24183   this.enabled = function (value) {
       
 24184     if (arguments.length) {
       
 24185       enabled = !!value;
       
 24186     }
       
 24187     return enabled;
       
 24188   };
       
 24189 
       
 24190 
       
 24191   /* Design notes on the default implementation for SCE.
       
 24192    *
       
 24193    * The API contract for the SCE delegate
       
 24194    * -------------------------------------
       
 24195    * The SCE delegate object must provide the following 3 methods:
       
 24196    *
       
 24197    * - trustAs(contextEnum, value)
       
 24198    *     This method is used to tell the SCE service that the provided value is OK to use in the
       
 24199    *     contexts specified by contextEnum.  It must return an object that will be accepted by
       
 24200    *     getTrusted() for a compatible contextEnum and return this value.
       
 24201    *
       
 24202    * - valueOf(value)
       
 24203    *     For values that were not produced by trustAs(), return them as is.  For values that were
       
 24204    *     produced by trustAs(), return the corresponding input value to trustAs.  Basically, if
       
 24205    *     trustAs is wrapping the given values into some type, this operation unwraps it when given
       
 24206    *     such a value.
       
 24207    *
       
 24208    * - getTrusted(contextEnum, value)
       
 24209    *     This function should return the a value that is safe to use in the context specified by
       
 24210    *     contextEnum or throw and exception otherwise.
       
 24211    *
       
 24212    * NOTE: This contract deliberately does NOT state that values returned by trustAs() must be
       
 24213    * opaque or wrapped in some holder object.  That happens to be an implementation detail.  For
       
 24214    * instance, an implementation could maintain a registry of all trusted objects by context.  In
       
 24215    * such a case, trustAs() would return the same object that was passed in.  getTrusted() would
       
 24216    * return the same object passed in if it was found in the registry under a compatible context or
       
 24217    * throw an exception otherwise.  An implementation might only wrap values some of the time based
       
 24218    * on some criteria.  getTrusted() might return a value and not throw an exception for special
       
 24219    * constants or objects even if not wrapped.  All such implementations fulfill this contract.
       
 24220    *
       
 24221    *
       
 24222    * A note on the inheritance model for SCE contexts
       
 24223    * ------------------------------------------------
       
 24224    * I've used inheritance and made RESOURCE_URL wrapped types a subtype of URL wrapped types.  This
       
 24225    * is purely an implementation details.
       
 24226    *
       
 24227    * The contract is simply this:
       
 24228    *
       
 24229    *     getTrusted($sce.RESOURCE_URL, value) succeeding implies that getTrusted($sce.URL, value)
       
 24230    *     will also succeed.
       
 24231    *
       
 24232    * Inheritance happens to capture this in a natural way.  In some future, we
       
 24233    * may not use inheritance anymore.  That is OK because no code outside of
       
 24234    * sce.js and sceSpecs.js would need to be aware of this detail.
       
 24235    */
       
 24236 
       
 24237   this.$get = ['$parse', '$sniffer', '$sceDelegate', function(
       
 24238                 $parse,   $sniffer,   $sceDelegate) {
       
 24239     // Prereq: Ensure that we're not running in IE8 quirks mode.  In that mode, IE allows
       
 24240     // the "expression(javascript expression)" syntax which is insecure.
       
 24241     if (enabled && $sniffer.msie && $sniffer.msieDocumentMode < 8) {
       
 24242       throw $sceMinErr('iequirks',
       
 24243         'Strict Contextual Escaping does not support Internet Explorer version < 9 in quirks ' +
       
 24244         'mode.  You can fix this by adding the text <!doctype html> to the top of your HTML ' +
       
 24245         'document.  See http://docs.angularjs.org/api/ng.$sce for more information.');
       
 24246     }
       
 24247 
       
 24248     var sce = shallowCopy(SCE_CONTEXTS);
       
 24249 
       
 24250     /**
       
 24251      * @ngdoc method
       
 24252      * @name $sce#isEnabled
       
 24253      * @kind function
       
 24254      *
       
 24255      * @return {Boolean} true if SCE is enabled, false otherwise.  If you want to set the value, you
       
 24256      * have to do it at module config time on {@link ng.$sceProvider $sceProvider}.
       
 24257      *
       
 24258      * @description
       
 24259      * Returns a boolean indicating if SCE is enabled.
       
 24260      */
       
 24261     sce.isEnabled = function () {
       
 24262       return enabled;
       
 24263     };
       
 24264     sce.trustAs = $sceDelegate.trustAs;
       
 24265     sce.getTrusted = $sceDelegate.getTrusted;
       
 24266     sce.valueOf = $sceDelegate.valueOf;
       
 24267 
       
 24268     if (!enabled) {
       
 24269       sce.trustAs = sce.getTrusted = function(type, value) { return value; };
       
 24270       sce.valueOf = identity;
       
 24271     }
       
 24272 
       
 24273     /**
       
 24274      * @ngdoc method
       
 24275      * @name $sce#parseAs
       
 24276      *
       
 24277      * @description
       
 24278      * Converts Angular {@link guide/expression expression} into a function.  This is like {@link
       
 24279      * ng.$parse $parse} and is identical when the expression is a literal constant.  Otherwise, it
       
 24280      * wraps the expression in a call to {@link ng.$sce#getTrusted $sce.getTrusted(*type*,
       
 24281      * *result*)}
       
 24282      *
       
 24283      * @param {string} type The kind of SCE context in which this result will be used.
       
 24284      * @param {string} expression String expression to compile.
       
 24285      * @returns {function(context, locals)} a function which represents the compiled expression:
       
 24286      *
       
 24287      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
       
 24288      *      are evaluated against (typically a scope object).
       
 24289      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
       
 24290      *      `context`.
       
 24291      */
       
 24292     sce.parseAs = function sceParseAs(type, expr) {
       
 24293       var parsed = $parse(expr);
       
 24294       if (parsed.literal && parsed.constant) {
       
 24295         return parsed;
       
 24296       } else {
       
 24297         return $parse(expr, function (value) {
       
 24298           return sce.getTrusted(type, value);
       
 24299         });
       
 24300       }
       
 24301     };
       
 24302 
       
 24303     /**
       
 24304      * @ngdoc method
       
 24305      * @name $sce#trustAs
       
 24306      *
       
 24307      * @description
       
 24308      * Delegates to {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.  As such,
       
 24309      * returns an object that is trusted by angular for use in specified strict contextual
       
 24310      * escaping contexts (such as ng-bind-html, ng-include, any src attribute
       
 24311      * interpolation, any dom event binding attribute interpolation such as for onclick,  etc.)
       
 24312      * that uses the provided value.  See * {@link ng.$sce $sce} for enabling strict contextual
       
 24313      * escaping.
       
 24314      *
       
 24315      * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
       
 24316      *   resource_url, html, js and css.
       
 24317      * @param {*} value The value that that should be considered trusted/safe.
       
 24318      * @returns {*} A value that can be used to stand in for the provided `value` in places
       
 24319      * where Angular expects a $sce.trustAs() return value.
       
 24320      */
       
 24321 
       
 24322     /**
       
 24323      * @ngdoc method
       
 24324      * @name $sce#trustAsHtml
       
 24325      *
       
 24326      * @description
       
 24327      * Shorthand method.  `$sce.trustAsHtml(value)` →
       
 24328      *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.HTML, value)`}
       
 24329      *
       
 24330      * @param {*} value The value to trustAs.
       
 24331      * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedHtml
       
 24332      *     $sce.getTrustedHtml(value)} to obtain the original value.  (privileged directives
       
 24333      *     only accept expressions that are either literal constants or are the
       
 24334      *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
       
 24335      */
       
 24336 
       
 24337     /**
       
 24338      * @ngdoc method
       
 24339      * @name $sce#trustAsUrl
       
 24340      *
       
 24341      * @description
       
 24342      * Shorthand method.  `$sce.trustAsUrl(value)` →
       
 24343      *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.URL, value)`}
       
 24344      *
       
 24345      * @param {*} value The value to trustAs.
       
 24346      * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedUrl
       
 24347      *     $sce.getTrustedUrl(value)} to obtain the original value.  (privileged directives
       
 24348      *     only accept expressions that are either literal constants or are the
       
 24349      *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
       
 24350      */
       
 24351 
       
 24352     /**
       
 24353      * @ngdoc method
       
 24354      * @name $sce#trustAsResourceUrl
       
 24355      *
       
 24356      * @description
       
 24357      * Shorthand method.  `$sce.trustAsResourceUrl(value)` →
       
 24358      *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.RESOURCE_URL, value)`}
       
 24359      *
       
 24360      * @param {*} value The value to trustAs.
       
 24361      * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedResourceUrl
       
 24362      *     $sce.getTrustedResourceUrl(value)} to obtain the original value.  (privileged directives
       
 24363      *     only accept expressions that are either literal constants or are the return
       
 24364      *     value of {@link ng.$sce#trustAs $sce.trustAs}.)
       
 24365      */
       
 24366 
       
 24367     /**
       
 24368      * @ngdoc method
       
 24369      * @name $sce#trustAsJs
       
 24370      *
       
 24371      * @description
       
 24372      * Shorthand method.  `$sce.trustAsJs(value)` →
       
 24373      *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.JS, value)`}
       
 24374      *
       
 24375      * @param {*} value The value to trustAs.
       
 24376      * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedJs
       
 24377      *     $sce.getTrustedJs(value)} to obtain the original value.  (privileged directives
       
 24378      *     only accept expressions that are either literal constants or are the
       
 24379      *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
       
 24380      */
       
 24381 
       
 24382     /**
       
 24383      * @ngdoc method
       
 24384      * @name $sce#getTrusted
       
 24385      *
       
 24386      * @description
       
 24387      * Delegates to {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted`}.  As such,
       
 24388      * takes the result of a {@link ng.$sce#trustAs `$sce.trustAs`}() call and returns the
       
 24389      * originally supplied value if the queried context type is a supertype of the created type.
       
 24390      * If this condition isn't satisfied, throws an exception.
       
 24391      *
       
 24392      * @param {string} type The kind of context in which this value is to be used.
       
 24393      * @param {*} maybeTrusted The result of a prior {@link ng.$sce#trustAs `$sce.trustAs`}
       
 24394      *                         call.
       
 24395      * @returns {*} The value the was originally provided to
       
 24396      *              {@link ng.$sce#trustAs `$sce.trustAs`} if valid in this context.
       
 24397      *              Otherwise, throws an exception.
       
 24398      */
       
 24399 
       
 24400     /**
       
 24401      * @ngdoc method
       
 24402      * @name $sce#getTrustedHtml
       
 24403      *
       
 24404      * @description
       
 24405      * Shorthand method.  `$sce.getTrustedHtml(value)` →
       
 24406      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.HTML, value)`}
       
 24407      *
       
 24408      * @param {*} value The value to pass to `$sce.getTrusted`.
       
 24409      * @returns {*} The return value of `$sce.getTrusted($sce.HTML, value)`
       
 24410      */
       
 24411 
       
 24412     /**
       
 24413      * @ngdoc method
       
 24414      * @name $sce#getTrustedCss
       
 24415      *
       
 24416      * @description
       
 24417      * Shorthand method.  `$sce.getTrustedCss(value)` →
       
 24418      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.CSS, value)`}
       
 24419      *
       
 24420      * @param {*} value The value to pass to `$sce.getTrusted`.
       
 24421      * @returns {*} The return value of `$sce.getTrusted($sce.CSS, value)`
       
 24422      */
       
 24423 
       
 24424     /**
       
 24425      * @ngdoc method
       
 24426      * @name $sce#getTrustedUrl
       
 24427      *
       
 24428      * @description
       
 24429      * Shorthand method.  `$sce.getTrustedUrl(value)` →
       
 24430      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.URL, value)`}
       
 24431      *
       
 24432      * @param {*} value The value to pass to `$sce.getTrusted`.
       
 24433      * @returns {*} The return value of `$sce.getTrusted($sce.URL, value)`
       
 24434      */
       
 24435 
       
 24436     /**
       
 24437      * @ngdoc method
       
 24438      * @name $sce#getTrustedResourceUrl
       
 24439      *
       
 24440      * @description
       
 24441      * Shorthand method.  `$sce.getTrustedResourceUrl(value)` →
       
 24442      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.RESOURCE_URL, value)`}
       
 24443      *
       
 24444      * @param {*} value The value to pass to `$sceDelegate.getTrusted`.
       
 24445      * @returns {*} The return value of `$sce.getTrusted($sce.RESOURCE_URL, value)`
       
 24446      */
       
 24447 
       
 24448     /**
       
 24449      * @ngdoc method
       
 24450      * @name $sce#getTrustedJs
       
 24451      *
       
 24452      * @description
       
 24453      * Shorthand method.  `$sce.getTrustedJs(value)` →
       
 24454      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.JS, value)`}
       
 24455      *
       
 24456      * @param {*} value The value to pass to `$sce.getTrusted`.
       
 24457      * @returns {*} The return value of `$sce.getTrusted($sce.JS, value)`
       
 24458      */
       
 24459 
       
 24460     /**
       
 24461      * @ngdoc method
       
 24462      * @name $sce#parseAsHtml
       
 24463      *
       
 24464      * @description
       
 24465      * Shorthand method.  `$sce.parseAsHtml(expression string)` →
       
 24466      *     {@link ng.$sce#parse `$sce.parseAs($sce.HTML, value)`}
       
 24467      *
       
 24468      * @param {string} expression String expression to compile.
       
 24469      * @returns {function(context, locals)} a function which represents the compiled expression:
       
 24470      *
       
 24471      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
       
 24472      *      are evaluated against (typically a scope object).
       
 24473      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
       
 24474      *      `context`.
       
 24475      */
       
 24476 
       
 24477     /**
       
 24478      * @ngdoc method
       
 24479      * @name $sce#parseAsCss
       
 24480      *
       
 24481      * @description
       
 24482      * Shorthand method.  `$sce.parseAsCss(value)` →
       
 24483      *     {@link ng.$sce#parse `$sce.parseAs($sce.CSS, value)`}
       
 24484      *
       
 24485      * @param {string} expression String expression to compile.
       
 24486      * @returns {function(context, locals)} a function which represents the compiled expression:
       
 24487      *
       
 24488      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
       
 24489      *      are evaluated against (typically a scope object).
       
 24490      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
       
 24491      *      `context`.
       
 24492      */
       
 24493 
       
 24494     /**
       
 24495      * @ngdoc method
       
 24496      * @name $sce#parseAsUrl
       
 24497      *
       
 24498      * @description
       
 24499      * Shorthand method.  `$sce.parseAsUrl(value)` →
       
 24500      *     {@link ng.$sce#parse `$sce.parseAs($sce.URL, value)`}
       
 24501      *
       
 24502      * @param {string} expression String expression to compile.
       
 24503      * @returns {function(context, locals)} a function which represents the compiled expression:
       
 24504      *
       
 24505      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
       
 24506      *      are evaluated against (typically a scope object).
       
 24507      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
       
 24508      *      `context`.
       
 24509      */
       
 24510 
       
 24511     /**
       
 24512      * @ngdoc method
       
 24513      * @name $sce#parseAsResourceUrl
       
 24514      *
       
 24515      * @description
       
 24516      * Shorthand method.  `$sce.parseAsResourceUrl(value)` →
       
 24517      *     {@link ng.$sce#parse `$sce.parseAs($sce.RESOURCE_URL, value)`}
       
 24518      *
       
 24519      * @param {string} expression String expression to compile.
       
 24520      * @returns {function(context, locals)} a function which represents the compiled expression:
       
 24521      *
       
 24522      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
       
 24523      *      are evaluated against (typically a scope object).
       
 24524      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
       
 24525      *      `context`.
       
 24526      */
       
 24527 
       
 24528     /**
       
 24529      * @ngdoc method
       
 24530      * @name $sce#parseAsJs
       
 24531      *
       
 24532      * @description
       
 24533      * Shorthand method.  `$sce.parseAsJs(value)` →
       
 24534      *     {@link ng.$sce#parse `$sce.parseAs($sce.JS, value)`}
       
 24535      *
       
 24536      * @param {string} expression String expression to compile.
       
 24537      * @returns {function(context, locals)} a function which represents the compiled expression:
       
 24538      *
       
 24539      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
       
 24540      *      are evaluated against (typically a scope object).
       
 24541      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
       
 24542      *      `context`.
       
 24543      */
       
 24544 
       
 24545     // Shorthand delegations.
       
 24546     var parse = sce.parseAs,
       
 24547         getTrusted = sce.getTrusted,
       
 24548         trustAs = sce.trustAs;
       
 24549 
       
 24550     forEach(SCE_CONTEXTS, function (enumValue, name) {
       
 24551       var lName = lowercase(name);
       
 24552       sce[camelCase("parse_as_" + lName)] = function (expr) {
       
 24553         return parse(enumValue, expr);
       
 24554       };
       
 24555       sce[camelCase("get_trusted_" + lName)] = function (value) {
       
 24556         return getTrusted(enumValue, value);
       
 24557       };
       
 24558       sce[camelCase("trust_as_" + lName)] = function (value) {
       
 24559         return trustAs(enumValue, value);
       
 24560       };
       
 24561     });
       
 24562 
       
 24563     return sce;
       
 24564   }];
       
 24565 }
       
 24566 
       
 24567 /**
       
 24568  * !!! This is an undocumented "private" service !!!
       
 24569  *
       
 24570  * @name $sniffer
       
 24571  * @requires $window
       
 24572  * @requires $document
       
 24573  *
       
 24574  * @property {boolean} history Does the browser support html5 history api ?
       
 24575  * @property {boolean} transitions Does the browser support CSS transition events ?
       
 24576  * @property {boolean} animations Does the browser support CSS animation events ?
       
 24577  *
       
 24578  * @description
       
 24579  * This is very simple implementation of testing browser's features.
       
 24580  */
       
 24581 function $SnifferProvider() {
       
 24582   this.$get = ['$window', '$document', function($window, $document) {
       
 24583     var eventSupport = {},
       
 24584         android =
       
 24585           int((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]),
       
 24586         boxee = /Boxee/i.test(($window.navigator || {}).userAgent),
       
 24587         document = $document[0] || {},
       
 24588         documentMode = document.documentMode,
       
 24589         vendorPrefix,
       
 24590         vendorRegex = /^(Moz|webkit|O|ms)(?=[A-Z])/,
       
 24591         bodyStyle = document.body && document.body.style,
       
 24592         transitions = false,
       
 24593         animations = false,
       
 24594         match;
       
 24595 
       
 24596     if (bodyStyle) {
       
 24597       for(var prop in bodyStyle) {
       
 24598         if(match = vendorRegex.exec(prop)) {
       
 24599           vendorPrefix = match[0];
       
 24600           vendorPrefix = vendorPrefix.substr(0, 1).toUpperCase() + vendorPrefix.substr(1);
       
 24601           break;
       
 24602         }
       
 24603       }
       
 24604 
       
 24605       if(!vendorPrefix) {
       
 24606         vendorPrefix = ('WebkitOpacity' in bodyStyle) && 'webkit';
       
 24607       }
       
 24608 
       
 24609       transitions = !!(('transition' in bodyStyle) || (vendorPrefix + 'Transition' in bodyStyle));
       
 24610       animations  = !!(('animation' in bodyStyle) || (vendorPrefix + 'Animation' in bodyStyle));
       
 24611 
       
 24612       if (android && (!transitions||!animations)) {
       
 24613         transitions = isString(document.body.style.webkitTransition);
       
 24614         animations = isString(document.body.style.webkitAnimation);
       
 24615       }
       
 24616     }
       
 24617 
       
 24618 
       
 24619     return {
       
 24620       // Android has history.pushState, but it does not update location correctly
       
 24621       // so let's not use the history API at all.
       
 24622       // http://code.google.com/p/android/issues/detail?id=17471
       
 24623       // https://github.com/angular/angular.js/issues/904
       
 24624 
       
 24625       // older webkit browser (533.9) on Boxee box has exactly the same problem as Android has
       
 24626       // so let's not use the history API also
       
 24627       // We are purposefully using `!(android < 4)` to cover the case when `android` is undefined
       
 24628       // jshint -W018
       
 24629       history: !!($window.history && $window.history.pushState && !(android < 4) && !boxee),
       
 24630       // jshint +W018
       
 24631       hasEvent: function(event) {
       
 24632         // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
       
 24633         // it. In particular the event is not fired when backspace or delete key are pressed or
       
 24634         // when cut operation is performed.
       
 24635         if (event == 'input' && msie == 9) return false;
       
 24636 
       
 24637         if (isUndefined(eventSupport[event])) {
       
 24638           var divElm = document.createElement('div');
       
 24639           eventSupport[event] = 'on' + event in divElm;
       
 24640         }
       
 24641 
       
 24642         return eventSupport[event];
       
 24643       },
       
 24644       csp: csp(),
       
 24645       vendorPrefix: vendorPrefix,
       
 24646       transitions : transitions,
       
 24647       animations : animations,
       
 24648       android: android,
       
 24649       msie : msie,
       
 24650       msieDocumentMode: documentMode
       
 24651     };
       
 24652   }];
       
 24653 }
       
 24654 
       
 24655 var $compileMinErr = minErr('$compile');
       
 24656 
       
 24657 /**
       
 24658  * @ngdoc service
       
 24659  * @name $templateRequest
       
 24660  *
       
 24661  * @description
       
 24662  * The `$templateRequest` service downloads the provided template using `$http` and, upon success,
       
 24663  * stores the contents inside of `$templateCache`. If the HTTP request fails or the response data
       
 24664  * of the HTTP request is empty then a `$compile` error will be thrown (the exception can be thwarted
       
 24665  * by setting the 2nd parameter of the function to true).
       
 24666  *
       
 24667  * @param {string} tpl The HTTP request template URL
       
 24668  * @param {boolean=} ignoreRequestError Whether or not to ignore the exception when the request fails or the template is empty
       
 24669  *
       
 24670  * @return {Promise} the HTTP Promise for the given.
       
 24671  *
       
 24672  * @property {number} totalPendingRequests total amount of pending template requests being downloaded.
       
 24673  */
       
 24674 function $TemplateRequestProvider() {
       
 24675   this.$get = ['$templateCache', '$http', '$q', function($templateCache, $http, $q) {
       
 24676     function handleRequestFn(tpl, ignoreRequestError) {
       
 24677       var self = handleRequestFn;
       
 24678       self.totalPendingRequests++;
       
 24679 
       
 24680       return $http.get(tpl, { cache : $templateCache })
       
 24681         .then(function(response) {
       
 24682           var html = response.data;
       
 24683           if(!html || html.length === 0) {
       
 24684             return handleError();
       
 24685           }
       
 24686 
       
 24687           self.totalPendingRequests--;
       
 24688           $templateCache.put(tpl, html);
       
 24689           return html;
       
 24690         }, handleError);
       
 24691 
       
 24692       function handleError() {
       
 24693         self.totalPendingRequests--;
       
 24694         if (!ignoreRequestError) {
       
 24695           throw $compileMinErr('tpload', 'Failed to load template: {0}', tpl);
       
 24696         }
       
 24697         return $q.reject();
       
 24698       }
       
 24699     }
       
 24700 
       
 24701     handleRequestFn.totalPendingRequests = 0;
       
 24702 
       
 24703     return handleRequestFn;
       
 24704   }];
       
 24705 }
       
 24706 
       
 24707 function $$TestabilityProvider() {
       
 24708   this.$get = ['$rootScope', '$browser', '$location',
       
 24709        function($rootScope,   $browser,   $location) {
       
 24710 
       
 24711     /**
       
 24712      * @name $testability
       
 24713      *
       
 24714      * @description
       
 24715      * The private $$testability service provides a collection of methods for use when debugging
       
 24716      * or by automated test and debugging tools.
       
 24717      */
       
 24718     var testability = {};
       
 24719 
       
 24720     /**
       
 24721      * @name $$testability#findBindings
       
 24722      *
       
 24723      * @description
       
 24724      * Returns an array of elements that are bound (via ng-bind or {{}})
       
 24725      * to expressions matching the input.
       
 24726      *
       
 24727      * @param {Element} element The element root to search from.
       
 24728      * @param {string} expression The binding expression to match.
       
 24729      * @param {boolean} opt_exactMatch If true, only returns exact matches
       
 24730      *     for the expression. Filters and whitespace are ignored.
       
 24731      */
       
 24732     testability.findBindings = function(element, expression, opt_exactMatch) {
       
 24733       var bindings = element.getElementsByClassName('ng-binding');
       
 24734       var matches = [];
       
 24735       forEach(bindings, function(binding) {
       
 24736         var dataBinding = angular.element(binding).data('$binding');
       
 24737         if (dataBinding) {
       
 24738           forEach(dataBinding, function(bindingName) {
       
 24739             if (opt_exactMatch) {
       
 24740               var matcher = new RegExp('(^|\\s)' + expression + '(\\s|\\||$)');
       
 24741               if (matcher.test(bindingName)) {
       
 24742                 matches.push(binding);
       
 24743               }
       
 24744             } else {
       
 24745               if (bindingName.indexOf(expression) != -1) {
       
 24746                 matches.push(binding);
       
 24747               }
       
 24748             }
       
 24749           });
       
 24750         }
       
 24751       });
       
 24752       return matches;
       
 24753     };
       
 24754 
       
 24755     /**
       
 24756      * @name $$testability#findModels
       
 24757      *
       
 24758      * @description
       
 24759      * Returns an array of elements that are two-way found via ng-model to
       
 24760      * expressions matching the input.
       
 24761      *
       
 24762      * @param {Element} element The element root to search from.
       
 24763      * @param {string} expression The model expression to match.
       
 24764      * @param {boolean} opt_exactMatch If true, only returns exact matches
       
 24765      *     for the expression.
       
 24766      */
       
 24767     testability.findModels = function(element, expression, opt_exactMatch) {
       
 24768       var prefixes = ['ng-', 'data-ng-', 'ng\\:'];
       
 24769       for (var p = 0; p < prefixes.length; ++p) {
       
 24770         var attributeEquals = opt_exactMatch ? '=' : '*=';
       
 24771         var selector = '[' + prefixes[p] + 'model' + attributeEquals + '"' + expression + '"]';
       
 24772         var elements = element.querySelectorAll(selector);
       
 24773         if (elements.length) {
       
 24774           return elements;
       
 24775         }
       
 24776       }
       
 24777     };
       
 24778 
       
 24779     /**
       
 24780      * @name $$testability#getLocation
       
 24781      *
       
 24782      * @description
       
 24783      * Shortcut for getting the location in a browser agnostic way. Returns
       
 24784      *     the path, search, and hash. (e.g. /path?a=b#hash)
       
 24785      */
       
 24786     testability.getLocation = function() {
       
 24787       return $location.url();
       
 24788     };
       
 24789 
       
 24790     /**
       
 24791      * @name $$testability#setLocation
       
 24792      *
       
 24793      * @description
       
 24794      * Shortcut for navigating to a location without doing a full page reload.
       
 24795      *
       
 24796      * @param {string} url The location url (path, search and hash,
       
 24797      *     e.g. /path?a=b#hash) to go to.
       
 24798      */
       
 24799     testability.setLocation = function(url) {
       
 24800       if (url !== $location.url()) {
       
 24801         $location.url(url);
       
 24802         $rootScope.$digest();
       
 24803       }
       
 24804     };
       
 24805 
       
 24806     /**
       
 24807      * @name $$testability#whenStable
       
 24808      *
       
 24809      * @description
       
 24810      * Calls the callback when $timeout and $http requests are completed.
       
 24811      *
       
 24812      * @param {function} callback
       
 24813      */
       
 24814     testability.whenStable = function(callback) {
       
 24815       $browser.notifyWhenNoOutstandingRequests(callback);
       
 24816     };
       
 24817 
       
 24818     return testability;
       
 24819   }];
       
 24820 }
       
 24821 
       
 24822 function $TimeoutProvider() {
       
 24823   this.$get = ['$rootScope', '$browser', '$q', '$$q', '$exceptionHandler',
       
 24824        function($rootScope,   $browser,   $q,   $$q,   $exceptionHandler) {
       
 24825     var deferreds = {};
       
 24826 
       
 24827 
       
 24828      /**
       
 24829       * @ngdoc service
       
 24830       * @name $timeout
       
 24831       *
       
 24832       * @description
       
 24833       * Angular's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch
       
 24834       * block and delegates any exceptions to
       
 24835       * {@link ng.$exceptionHandler $exceptionHandler} service.
       
 24836       *
       
 24837       * The return value of registering a timeout function is a promise, which will be resolved when
       
 24838       * the timeout is reached and the timeout function is executed.
       
 24839       *
       
 24840       * To cancel a timeout request, call `$timeout.cancel(promise)`.
       
 24841       *
       
 24842       * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to
       
 24843       * synchronously flush the queue of deferred functions.
       
 24844       *
       
 24845       * @param {function()} fn A function, whose execution should be delayed.
       
 24846       * @param {number=} [delay=0] Delay in milliseconds.
       
 24847       * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
       
 24848       *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
       
 24849       * @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
       
 24850       *   promise will be resolved with is the return value of the `fn` function.
       
 24851       *
       
 24852       */
       
 24853     function timeout(fn, delay, invokeApply) {
       
 24854       var skipApply = (isDefined(invokeApply) && !invokeApply),
       
 24855           deferred = (skipApply ? $$q : $q).defer(),
       
 24856           promise = deferred.promise,
       
 24857           timeoutId;
       
 24858 
       
 24859       timeoutId = $browser.defer(function() {
       
 24860         try {
       
 24861           deferred.resolve(fn());
       
 24862         } catch(e) {
       
 24863           deferred.reject(e);
       
 24864           $exceptionHandler(e);
       
 24865         }
       
 24866         finally {
       
 24867           delete deferreds[promise.$$timeoutId];
       
 24868         }
       
 24869 
       
 24870         if (!skipApply) $rootScope.$apply();
       
 24871       }, delay);
       
 24872 
       
 24873       promise.$$timeoutId = timeoutId;
       
 24874       deferreds[timeoutId] = deferred;
       
 24875 
       
 24876       return promise;
       
 24877     }
       
 24878 
       
 24879 
       
 24880      /**
       
 24881       * @ngdoc method
       
 24882       * @name $timeout#cancel
       
 24883       *
       
 24884       * @description
       
 24885       * Cancels a task associated with the `promise`. As a result of this, the promise will be
       
 24886       * resolved with a rejection.
       
 24887       *
       
 24888       * @param {Promise=} promise Promise returned by the `$timeout` function.
       
 24889       * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
       
 24890       *   canceled.
       
 24891       */
       
 24892     timeout.cancel = function(promise) {
       
 24893       if (promise && promise.$$timeoutId in deferreds) {
       
 24894         deferreds[promise.$$timeoutId].reject('canceled');
       
 24895         delete deferreds[promise.$$timeoutId];
       
 24896         return $browser.defer.cancel(promise.$$timeoutId);
       
 24897       }
       
 24898       return false;
       
 24899     };
       
 24900 
       
 24901     return timeout;
       
 24902   }];
       
 24903 }
       
 24904 
       
 24905 // NOTE:  The usage of window and document instead of $window and $document here is
       
 24906 // deliberate.  This service depends on the specific behavior of anchor nodes created by the
       
 24907 // browser (resolving and parsing URLs) that is unlikely to be provided by mock objects and
       
 24908 // cause us to break tests.  In addition, when the browser resolves a URL for XHR, it
       
 24909 // doesn't know about mocked locations and resolves URLs to the real document - which is
       
 24910 // exactly the behavior needed here.  There is little value is mocking these out for this
       
 24911 // service.
       
 24912 var urlParsingNode = document.createElement("a");
       
 24913 var originUrl = urlResolve(window.location.href, true);
       
 24914 
       
 24915 
       
 24916 /**
       
 24917  *
       
 24918  * Implementation Notes for non-IE browsers
       
 24919  * ----------------------------------------
       
 24920  * Assigning a URL to the href property of an anchor DOM node, even one attached to the DOM,
       
 24921  * results both in the normalizing and parsing of the URL.  Normalizing means that a relative
       
 24922  * URL will be resolved into an absolute URL in the context of the application document.
       
 24923  * Parsing means that the anchor node's host, hostname, protocol, port, pathname and related
       
 24924  * properties are all populated to reflect the normalized URL.  This approach has wide
       
 24925  * compatibility - Safari 1+, Mozilla 1+, Opera 7+,e etc.  See
       
 24926  * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
       
 24927  *
       
 24928  * Implementation Notes for IE
       
 24929  * ---------------------------
       
 24930  * IE >= 8 and <= 10 normalizes the URL when assigned to the anchor node similar to the other
       
 24931  * browsers.  However, the parsed components will not be set if the URL assigned did not specify
       
 24932  * them.  (e.g. if you assign a.href = "foo", then a.protocol, a.host, etc. will be empty.)  We
       
 24933  * work around that by performing the parsing in a 2nd step by taking a previously normalized
       
 24934  * URL (e.g. by assigning to a.href) and assigning it a.href again.  This correctly populates the
       
 24935  * properties such as protocol, hostname, port, etc.
       
 24936  *
       
 24937  * IE7 does not normalize the URL when assigned to an anchor node.  (Apparently, it does, if one
       
 24938  * uses the inner HTML approach to assign the URL as part of an HTML snippet -
       
 24939  * http://stackoverflow.com/a/472729)  However, setting img[src] does normalize the URL.
       
 24940  * Unfortunately, setting img[src] to something like "javascript:foo" on IE throws an exception.
       
 24941  * Since the primary usage for normalizing URLs is to sanitize such URLs, we can't use that
       
 24942  * method and IE < 8 is unsupported.
       
 24943  *
       
 24944  * References:
       
 24945  *   http://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement
       
 24946  *   http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
       
 24947  *   http://url.spec.whatwg.org/#urlutils
       
 24948  *   https://github.com/angular/angular.js/pull/2902
       
 24949  *   http://james.padolsey.com/javascript/parsing-urls-with-the-dom/
       
 24950  *
       
 24951  * @kind function
       
 24952  * @param {string} url The URL to be parsed.
       
 24953  * @description Normalizes and parses a URL.
       
 24954  * @returns {object} Returns the normalized URL as a dictionary.
       
 24955  *
       
 24956  *   | member name   | Description    |
       
 24957  *   |---------------|----------------|
       
 24958  *   | href          | A normalized version of the provided URL if it was not an absolute URL |
       
 24959  *   | protocol      | The protocol including the trailing colon                              |
       
 24960  *   | host          | The host and port (if the port is non-default) of the normalizedUrl    |
       
 24961  *   | search        | The search params, minus the question mark                             |
       
 24962  *   | hash          | The hash string, minus the hash symbol
       
 24963  *   | hostname      | The hostname
       
 24964  *   | port          | The port, without ":"
       
 24965  *   | pathname      | The pathname, beginning with "/"
       
 24966  *
       
 24967  */
       
 24968 function urlResolve(url, base) {
       
 24969   var href = url;
       
 24970 
       
 24971   if (msie) {
       
 24972     // Normalize before parse.  Refer Implementation Notes on why this is
       
 24973     // done in two steps on IE.
       
 24974     urlParsingNode.setAttribute("href", href);
       
 24975     href = urlParsingNode.href;
       
 24976   }
       
 24977 
       
 24978   urlParsingNode.setAttribute('href', href);
       
 24979 
       
 24980   // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
       
 24981   return {
       
 24982     href: urlParsingNode.href,
       
 24983     protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '',
       
 24984     host: urlParsingNode.host,
       
 24985     search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '',
       
 24986     hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',
       
 24987     hostname: urlParsingNode.hostname,
       
 24988     port: urlParsingNode.port,
       
 24989     pathname: (urlParsingNode.pathname.charAt(0) === '/')
       
 24990       ? urlParsingNode.pathname
       
 24991       : '/' + urlParsingNode.pathname
       
 24992   };
       
 24993 }
       
 24994 
       
 24995 /**
       
 24996  * Parse a request URL and determine whether this is a same-origin request as the application document.
       
 24997  *
       
 24998  * @param {string|object} requestUrl The url of the request as a string that will be resolved
       
 24999  * or a parsed URL object.
       
 25000  * @returns {boolean} Whether the request is for the same origin as the application document.
       
 25001  */
       
 25002 function urlIsSameOrigin(requestUrl) {
       
 25003   var parsed = (isString(requestUrl)) ? urlResolve(requestUrl) : requestUrl;
       
 25004   return (parsed.protocol === originUrl.protocol &&
       
 25005           parsed.host === originUrl.host);
       
 25006 }
       
 25007 
       
 25008 /**
       
 25009  * @ngdoc service
       
 25010  * @name $window
       
 25011  *
       
 25012  * @description
       
 25013  * A reference to the browser's `window` object. While `window`
       
 25014  * is globally available in JavaScript, it causes testability problems, because
       
 25015  * it is a global variable. In angular we always refer to it through the
       
 25016  * `$window` service, so it may be overridden, removed or mocked for testing.
       
 25017  *
       
 25018  * Expressions, like the one defined for the `ngClick` directive in the example
       
 25019  * below, are evaluated with respect to the current scope.  Therefore, there is
       
 25020  * no risk of inadvertently coding in a dependency on a global value in such an
       
 25021  * expression.
       
 25022  *
       
 25023  * @example
       
 25024    <example module="windowExample">
       
 25025      <file name="index.html">
       
 25026        <script>
       
 25027          angular.module('windowExample', [])
       
 25028            .controller('ExampleController', ['$scope', '$window', function ($scope, $window) {
       
 25029              $scope.greeting = 'Hello, World!';
       
 25030              $scope.doGreeting = function(greeting) {
       
 25031                $window.alert(greeting);
       
 25032              };
       
 25033            }]);
       
 25034        </script>
       
 25035        <div ng-controller="ExampleController">
       
 25036          <input type="text" ng-model="greeting" />
       
 25037          <button ng-click="doGreeting(greeting)">ALERT</button>
       
 25038        </div>
       
 25039      </file>
       
 25040      <file name="protractor.js" type="protractor">
       
 25041       it('should display the greeting in the input box', function() {
       
 25042        element(by.model('greeting')).sendKeys('Hello, E2E Tests');
       
 25043        // If we click the button it will block the test runner
       
 25044        // element(':button').click();
       
 25045       });
       
 25046      </file>
       
 25047    </example>
       
 25048  */
       
 25049 function $WindowProvider(){
       
 25050   this.$get = valueFn(window);
       
 25051 }
       
 25052 
       
 25053 /* global currencyFilter: true,
       
 25054  dateFilter: true,
       
 25055  filterFilter: true,
       
 25056  jsonFilter: true,
       
 25057  limitToFilter: true,
       
 25058  lowercaseFilter: true,
       
 25059  numberFilter: true,
       
 25060  orderByFilter: true,
       
 25061  uppercaseFilter: true,
       
 25062  */
       
 25063 
       
 25064 /**
       
 25065  * @ngdoc provider
       
 25066  * @name $filterProvider
       
 25067  * @description
       
 25068  *
       
 25069  * Filters are just functions which transform input to an output. However filters need to be
       
 25070  * Dependency Injected. To achieve this a filter definition consists of a factory function which is
       
 25071  * annotated with dependencies and is responsible for creating a filter function.
       
 25072  *
       
 25073  * ```js
       
 25074  *   // Filter registration
       
 25075  *   function MyModule($provide, $filterProvider) {
       
 25076  *     // create a service to demonstrate injection (not always needed)
       
 25077  *     $provide.value('greet', function(name){
       
 25078  *       return 'Hello ' + name + '!';
       
 25079  *     });
       
 25080  *
       
 25081  *     // register a filter factory which uses the
       
 25082  *     // greet service to demonstrate DI.
       
 25083  *     $filterProvider.register('greet', function(greet){
       
 25084  *       // return the filter function which uses the greet service
       
 25085  *       // to generate salutation
       
 25086  *       return function(text) {
       
 25087  *         // filters need to be forgiving so check input validity
       
 25088  *         return text && greet(text) || text;
       
 25089  *       };
       
 25090  *     });
       
 25091  *   }
       
 25092  * ```
       
 25093  *
       
 25094  * The filter function is registered with the `$injector` under the filter name suffix with
       
 25095  * `Filter`.
       
 25096  *
       
 25097  * ```js
       
 25098  *   it('should be the same instance', inject(
       
 25099  *     function($filterProvider) {
       
 25100  *       $filterProvider.register('reverse', function(){
       
 25101  *         return ...;
       
 25102  *       });
       
 25103  *     },
       
 25104  *     function($filter, reverseFilter) {
       
 25105  *       expect($filter('reverse')).toBe(reverseFilter);
       
 25106  *     });
       
 25107  * ```
       
 25108  *
       
 25109  *
       
 25110  * For more information about how angular filters work, and how to create your own filters, see
       
 25111  * {@link guide/filter Filters} in the Angular Developer Guide.
       
 25112  */
       
 25113 
       
 25114 /**
       
 25115  * @ngdoc service
       
 25116  * @name $filter
       
 25117  * @kind function
       
 25118  * @description
       
 25119  * Filters are used for formatting data displayed to the user.
       
 25120  *
       
 25121  * The general syntax in templates is as follows:
       
 25122  *
       
 25123  *         {{ expression [| filter_name[:parameter_value] ... ] }}
       
 25124  *
       
 25125  * @param {String} name Name of the filter function to retrieve
       
 25126  * @return {Function} the filter function
       
 25127  * @example
       
 25128    <example name="$filter" module="filterExample">
       
 25129      <file name="index.html">
       
 25130        <div ng-controller="MainCtrl">
       
 25131         <h3>{{ originalText }}</h3>
       
 25132         <h3>{{ filteredText }}</h3>
       
 25133        </div>
       
 25134      </file>
       
 25135 
       
 25136      <file name="script.js">
       
 25137       angular.module('filterExample', [])
       
 25138       .controller('MainCtrl', function($scope, $filter) {
       
 25139         $scope.originalText = 'hello';
       
 25140         $scope.filteredText = $filter('uppercase')($scope.originalText);
       
 25141       });
       
 25142      </file>
       
 25143    </example>
       
 25144   */
       
 25145 $FilterProvider.$inject = ['$provide'];
       
 25146 function $FilterProvider($provide) {
       
 25147   var suffix = 'Filter';
       
 25148 
       
 25149   /**
       
 25150    * @ngdoc method
       
 25151    * @name $filterProvider#register
       
 25152    * @param {string|Object} name Name of the filter function, or an object map of filters where
       
 25153    *    the keys are the filter names and the values are the filter factories.
       
 25154    * @returns {Object} Registered filter instance, or if a map of filters was provided then a map
       
 25155    *    of the registered filter instances.
       
 25156    */
       
 25157   function register(name, factory) {
       
 25158     if(isObject(name)) {
       
 25159       var filters = {};
       
 25160       forEach(name, function(filter, key) {
       
 25161         filters[key] = register(key, filter);
       
 25162       });
       
 25163       return filters;
       
 25164     } else {
       
 25165       return $provide.factory(name + suffix, factory);
       
 25166     }
       
 25167   }
       
 25168   this.register = register;
       
 25169 
       
 25170   this.$get = ['$injector', function($injector) {
       
 25171     return function(name) {
       
 25172       return $injector.get(name + suffix);
       
 25173     };
       
 25174   }];
       
 25175 
       
 25176   ////////////////////////////////////////
       
 25177 
       
 25178   /* global
       
 25179     currencyFilter: false,
       
 25180     dateFilter: false,
       
 25181     filterFilter: false,
       
 25182     jsonFilter: false,
       
 25183     limitToFilter: false,
       
 25184     lowercaseFilter: false,
       
 25185     numberFilter: false,
       
 25186     orderByFilter: false,
       
 25187     uppercaseFilter: false,
       
 25188   */
       
 25189 
       
 25190   register('currency', currencyFilter);
       
 25191   register('date', dateFilter);
       
 25192   register('filter', filterFilter);
       
 25193   register('json', jsonFilter);
       
 25194   register('limitTo', limitToFilter);
       
 25195   register('lowercase', lowercaseFilter);
       
 25196   register('number', numberFilter);
       
 25197   register('orderBy', orderByFilter);
       
 25198   register('uppercase', uppercaseFilter);
       
 25199 }
       
 25200 
       
 25201 /**
       
 25202  * @ngdoc filter
       
 25203  * @name filter
       
 25204  * @kind function
       
 25205  *
       
 25206  * @description
       
 25207  * Selects a subset of items from `array` and returns it as a new array.
       
 25208  *
       
 25209  * @param {Array} array The source array.
       
 25210  * @param {string|Object|function()} expression The predicate to be used for selecting items from
       
 25211  *   `array`.
       
 25212  *
       
 25213  *   Can be one of:
       
 25214  *
       
 25215  *   - `string`: The string is evaluated as an expression and the resulting value is used for substring match against
       
 25216  *     the contents of the `array`. All strings or objects with string properties in `array` that contain this string
       
 25217  *     will be returned. The predicate can be negated by prefixing the string with `!`.
       
 25218  *
       
 25219  *   - `Object`: A pattern object can be used to filter specific properties on objects contained
       
 25220  *     by `array`. For example `{name:"M", phone:"1"}` predicate will return an array of items
       
 25221  *     which have property `name` containing "M" and property `phone` containing "1". A special
       
 25222  *     property name `$` can be used (as in `{$:"text"}`) to accept a match against any
       
 25223  *     property of the object. That's equivalent to the simple substring match with a `string`
       
 25224  *     as described above. The predicate can be negated by prefixing the string with `!`.
       
 25225  *     For Example `{name: "!M"}` predicate will return an array of items which have property `name`
       
 25226  *     not containing "M".
       
 25227  *
       
 25228  *   - `function(value, index)`: A predicate function can be used to write arbitrary filters. The
       
 25229  *     function is called for each element of `array`. The final result is an array of those
       
 25230  *     elements that the predicate returned true for.
       
 25231  *
       
 25232  * @param {function(actual, expected)|true|undefined} comparator Comparator which is used in
       
 25233  *     determining if the expected value (from the filter expression) and actual value (from
       
 25234  *     the object in the array) should be considered a match.
       
 25235  *
       
 25236  *   Can be one of:
       
 25237  *
       
 25238  *   - `function(actual, expected)`:
       
 25239  *     The function will be given the object value and the predicate value to compare and
       
 25240  *     should return true if the item should be included in filtered result.
       
 25241  *
       
 25242  *   - `true`: A shorthand for `function(actual, expected) { return angular.equals(expected, actual)}`.
       
 25243  *     this is essentially strict comparison of expected and actual.
       
 25244  *
       
 25245  *   - `false|undefined`: A short hand for a function which will look for a substring match in case
       
 25246  *     insensitive way.
       
 25247  *
       
 25248  * @example
       
 25249    <example>
       
 25250      <file name="index.html">
       
 25251        <div ng-init="friends = [{name:'John', phone:'555-1276'},
       
 25252                                 {name:'Mary', phone:'800-BIG-MARY'},
       
 25253                                 {name:'Mike', phone:'555-4321'},
       
 25254                                 {name:'Adam', phone:'555-5678'},
       
 25255                                 {name:'Julie', phone:'555-8765'},
       
 25256                                 {name:'Juliette', phone:'555-5678'}]"></div>
       
 25257 
       
 25258        Search: <input ng-model="searchText">
       
 25259        <table id="searchTextResults">
       
 25260          <tr><th>Name</th><th>Phone</th></tr>
       
 25261          <tr ng-repeat="friend in friends | filter:searchText">
       
 25262            <td>{{friend.name}}</td>
       
 25263            <td>{{friend.phone}}</td>
       
 25264          </tr>
       
 25265        </table>
       
 25266        <hr>
       
 25267        Any: <input ng-model="search.$"> <br>
       
 25268        Name only <input ng-model="search.name"><br>
       
 25269        Phone only <input ng-model="search.phone"><br>
       
 25270        Equality <input type="checkbox" ng-model="strict"><br>
       
 25271        <table id="searchObjResults">
       
 25272          <tr><th>Name</th><th>Phone</th></tr>
       
 25273          <tr ng-repeat="friendObj in friends | filter:search:strict">
       
 25274            <td>{{friendObj.name}}</td>
       
 25275            <td>{{friendObj.phone}}</td>
       
 25276          </tr>
       
 25277        </table>
       
 25278      </file>
       
 25279      <file name="protractor.js" type="protractor">
       
 25280        var expectFriendNames = function(expectedNames, key) {
       
 25281          element.all(by.repeater(key + ' in friends').column(key + '.name')).then(function(arr) {
       
 25282            arr.forEach(function(wd, i) {
       
 25283              expect(wd.getText()).toMatch(expectedNames[i]);
       
 25284            });
       
 25285          });
       
 25286        };
       
 25287 
       
 25288        it('should search across all fields when filtering with a string', function() {
       
 25289          var searchText = element(by.model('searchText'));
       
 25290          searchText.clear();
       
 25291          searchText.sendKeys('m');
       
 25292          expectFriendNames(['Mary', 'Mike', 'Adam'], 'friend');
       
 25293 
       
 25294          searchText.clear();
       
 25295          searchText.sendKeys('76');
       
 25296          expectFriendNames(['John', 'Julie'], 'friend');
       
 25297        });
       
 25298 
       
 25299        it('should search in specific fields when filtering with a predicate object', function() {
       
 25300          var searchAny = element(by.model('search.$'));
       
 25301          searchAny.clear();
       
 25302          searchAny.sendKeys('i');
       
 25303          expectFriendNames(['Mary', 'Mike', 'Julie', 'Juliette'], 'friendObj');
       
 25304        });
       
 25305        it('should use a equal comparison when comparator is true', function() {
       
 25306          var searchName = element(by.model('search.name'));
       
 25307          var strict = element(by.model('strict'));
       
 25308          searchName.clear();
       
 25309          searchName.sendKeys('Julie');
       
 25310          strict.click();
       
 25311          expectFriendNames(['Julie'], 'friendObj');
       
 25312        });
       
 25313      </file>
       
 25314    </example>
       
 25315  */
       
 25316 function filterFilter() {
       
 25317   return function(array, expression, comparator) {
       
 25318     if (!isArray(array)) return array;
       
 25319 
       
 25320     var comparatorType = typeof(comparator),
       
 25321         predicates = [];
       
 25322 
       
 25323     predicates.check = function(value, index) {
       
 25324       for (var j = 0; j < predicates.length; j++) {
       
 25325         if(!predicates[j](value, index)) {
       
 25326           return false;
       
 25327         }
       
 25328       }
       
 25329       return true;
       
 25330     };
       
 25331 
       
 25332     if (comparatorType !== 'function') {
       
 25333       if (comparatorType === 'boolean' && comparator) {
       
 25334         comparator = function(obj, text) {
       
 25335           return angular.equals(obj, text);
       
 25336         };
       
 25337       } else {
       
 25338         comparator = function(obj, text) {
       
 25339           if (obj && text && typeof obj === 'object' && typeof text === 'object') {
       
 25340             for (var objKey in obj) {
       
 25341               if (objKey.charAt(0) !== '$' && hasOwnProperty.call(obj, objKey) &&
       
 25342                   comparator(obj[objKey], text[objKey])) {
       
 25343                 return true;
       
 25344               }
       
 25345             }
       
 25346             return false;
       
 25347           }
       
 25348           text = (''+text).toLowerCase();
       
 25349           return (''+obj).toLowerCase().indexOf(text) > -1;
       
 25350         };
       
 25351       }
       
 25352     }
       
 25353 
       
 25354     var search = function(obj, text){
       
 25355       if (typeof text == 'string' && text.charAt(0) === '!') {
       
 25356         return !search(obj, text.substr(1));
       
 25357       }
       
 25358       switch (typeof obj) {
       
 25359         case "boolean":
       
 25360         case "number":
       
 25361         case "string":
       
 25362           return comparator(obj, text);
       
 25363         case "object":
       
 25364           switch (typeof text) {
       
 25365             case "object":
       
 25366               return comparator(obj, text);
       
 25367             default:
       
 25368               for ( var objKey in obj) {
       
 25369                 if (objKey.charAt(0) !== '$' && search(obj[objKey], text)) {
       
 25370                   return true;
       
 25371                 }
       
 25372               }
       
 25373               break;
       
 25374           }
       
 25375           return false;
       
 25376         case "array":
       
 25377           for ( var i = 0; i < obj.length; i++) {
       
 25378             if (search(obj[i], text)) {
       
 25379               return true;
       
 25380             }
       
 25381           }
       
 25382           return false;
       
 25383         default:
       
 25384           return false;
       
 25385       }
       
 25386     };
       
 25387     switch (typeof expression) {
       
 25388       case "boolean":
       
 25389       case "number":
       
 25390       case "string":
       
 25391         // Set up expression object and fall through
       
 25392         expression = {$:expression};
       
 25393         // jshint -W086
       
 25394       case "object":
       
 25395         // jshint +W086
       
 25396         for (var key in expression) {
       
 25397           (function(path) {
       
 25398             if (typeof expression[path] === 'undefined') return;
       
 25399             predicates.push(function(value) {
       
 25400               return search(path == '$' ? value : (value && value[path]), expression[path]);
       
 25401             });
       
 25402           })(key);
       
 25403         }
       
 25404         break;
       
 25405       case 'function':
       
 25406         predicates.push(expression);
       
 25407         break;
       
 25408       default:
       
 25409         return array;
       
 25410     }
       
 25411     var filtered = [];
       
 25412     for ( var j = 0; j < array.length; j++) {
       
 25413       var value = array[j];
       
 25414       if (predicates.check(value, j)) {
       
 25415         filtered.push(value);
       
 25416       }
       
 25417     }
       
 25418     return filtered;
       
 25419   };
       
 25420 }
       
 25421 
       
 25422 /**
       
 25423  * @ngdoc filter
       
 25424  * @name currency
       
 25425  * @kind function
       
 25426  *
       
 25427  * @description
       
 25428  * Formats a number as a currency (ie $1,234.56). When no currency symbol is provided, default
       
 25429  * symbol for current locale is used.
       
 25430  *
       
 25431  * @param {number} amount Input to filter.
       
 25432  * @param {string=} symbol Currency symbol or identifier to be displayed.
       
 25433  * @returns {string} Formatted number.
       
 25434  *
       
 25435  *
       
 25436  * @example
       
 25437    <example module="currencyExample">
       
 25438      <file name="index.html">
       
 25439        <script>
       
 25440          angular.module('currencyExample', [])
       
 25441            .controller('ExampleController', ['$scope', function($scope) {
       
 25442              $scope.amount = 1234.56;
       
 25443            }]);
       
 25444        </script>
       
 25445        <div ng-controller="ExampleController">
       
 25446          <input type="number" ng-model="amount"> <br>
       
 25447          default currency symbol ($): <span id="currency-default">{{amount | currency}}</span><br>
       
 25448          custom currency identifier (USD$): <span>{{amount | currency:"USD$"}}</span>
       
 25449        </div>
       
 25450      </file>
       
 25451      <file name="protractor.js" type="protractor">
       
 25452        it('should init with 1234.56', function() {
       
 25453          expect(element(by.id('currency-default')).getText()).toBe('$1,234.56');
       
 25454          expect(element(by.binding('amount | currency:"USD$"')).getText()).toBe('USD$1,234.56');
       
 25455        });
       
 25456        it('should update', function() {
       
 25457          if (browser.params.browser == 'safari') {
       
 25458            // Safari does not understand the minus key. See
       
 25459            // https://github.com/angular/protractor/issues/481
       
 25460            return;
       
 25461          }
       
 25462          element(by.model('amount')).clear();
       
 25463          element(by.model('amount')).sendKeys('-1234');
       
 25464          expect(element(by.id('currency-default')).getText()).toBe('($1,234.00)');
       
 25465          expect(element(by.binding('amount | currency:"USD$"')).getText()).toBe('(USD$1,234.00)');
       
 25466        });
       
 25467      </file>
       
 25468    </example>
       
 25469  */
       
 25470 currencyFilter.$inject = ['$locale'];
       
 25471 function currencyFilter($locale) {
       
 25472   var formats = $locale.NUMBER_FORMATS;
       
 25473   return function(amount, currencySymbol){
       
 25474     if (isUndefined(currencySymbol)) currencySymbol = formats.CURRENCY_SYM;
       
 25475 
       
 25476     // if null or undefined pass it through
       
 25477     return (amount == null)
       
 25478         ? amount
       
 25479         : formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, 2).
       
 25480             replace(/\u00A4/g, currencySymbol);
       
 25481   };
       
 25482 }
       
 25483 
       
 25484 /**
       
 25485  * @ngdoc filter
       
 25486  * @name number
       
 25487  * @kind function
       
 25488  *
       
 25489  * @description
       
 25490  * Formats a number as text.
       
 25491  *
       
 25492  * If the input is not a number an empty string is returned.
       
 25493  *
       
 25494  * @param {number|string} number Number to format.
       
 25495  * @param {(number|string)=} fractionSize Number of decimal places to round the number to.
       
 25496  * If this is not provided then the fraction size is computed from the current locale's number
       
 25497  * formatting pattern. In the case of the default locale, it will be 3.
       
 25498  * @returns {string} Number rounded to decimalPlaces and places a “,” after each third digit.
       
 25499  *
       
 25500  * @example
       
 25501    <example module="numberFilterExample">
       
 25502      <file name="index.html">
       
 25503        <script>
       
 25504          angular.module('numberFilterExample', [])
       
 25505            .controller('ExampleController', ['$scope', function($scope) {
       
 25506              $scope.val = 1234.56789;
       
 25507            }]);
       
 25508        </script>
       
 25509        <div ng-controller="ExampleController">
       
 25510          Enter number: <input ng-model='val'><br>
       
 25511          Default formatting: <span id='number-default'>{{val | number}}</span><br>
       
 25512          No fractions: <span>{{val | number:0}}</span><br>
       
 25513          Negative number: <span>{{-val | number:4}}</span>
       
 25514        </div>
       
 25515      </file>
       
 25516      <file name="protractor.js" type="protractor">
       
 25517        it('should format numbers', function() {
       
 25518          expect(element(by.id('number-default')).getText()).toBe('1,234.568');
       
 25519          expect(element(by.binding('val | number:0')).getText()).toBe('1,235');
       
 25520          expect(element(by.binding('-val | number:4')).getText()).toBe('-1,234.5679');
       
 25521        });
       
 25522 
       
 25523        it('should update', function() {
       
 25524          element(by.model('val')).clear();
       
 25525          element(by.model('val')).sendKeys('3374.333');
       
 25526          expect(element(by.id('number-default')).getText()).toBe('3,374.333');
       
 25527          expect(element(by.binding('val | number:0')).getText()).toBe('3,374');
       
 25528          expect(element(by.binding('-val | number:4')).getText()).toBe('-3,374.3330');
       
 25529       });
       
 25530      </file>
       
 25531    </example>
       
 25532  */
       
 25533 
       
 25534 
       
 25535 numberFilter.$inject = ['$locale'];
       
 25536 function numberFilter($locale) {
       
 25537   var formats = $locale.NUMBER_FORMATS;
       
 25538   return function(number, fractionSize) {
       
 25539 
       
 25540     // if null or undefined pass it through
       
 25541     return (number == null)
       
 25542         ? number
       
 25543         : formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP, formats.DECIMAL_SEP,
       
 25544                        fractionSize);
       
 25545   };
       
 25546 }
       
 25547 
       
 25548 var DECIMAL_SEP = '.';
       
 25549 function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
       
 25550   if (!isFinite(number) || isObject(number)) return '';
       
 25551 
       
 25552   var isNegative = number < 0;
       
 25553   number = Math.abs(number);
       
 25554   var numStr = number + '',
       
 25555       formatedText = '',
       
 25556       parts = [];
       
 25557 
       
 25558   var hasExponent = false;
       
 25559   if (numStr.indexOf('e') !== -1) {
       
 25560     var match = numStr.match(/([\d\.]+)e(-?)(\d+)/);
       
 25561     if (match && match[2] == '-' && match[3] > fractionSize + 1) {
       
 25562       numStr = '0';
       
 25563       number = 0;
       
 25564     } else {
       
 25565       formatedText = numStr;
       
 25566       hasExponent = true;
       
 25567     }
       
 25568   }
       
 25569 
       
 25570   if (!hasExponent) {
       
 25571     var fractionLen = (numStr.split(DECIMAL_SEP)[1] || '').length;
       
 25572 
       
 25573     // determine fractionSize if it is not specified
       
 25574     if (isUndefined(fractionSize)) {
       
 25575       fractionSize = Math.min(Math.max(pattern.minFrac, fractionLen), pattern.maxFrac);
       
 25576     }
       
 25577 
       
 25578     // safely round numbers in JS without hitting imprecisions of floating-point arithmetics
       
 25579     // inspired by:
       
 25580     // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
       
 25581     number = +(Math.round(+(number.toString() + 'e' + fractionSize)).toString() + 'e' + -fractionSize);
       
 25582 
       
 25583     if (number === 0) {
       
 25584       isNegative = false;
       
 25585     }
       
 25586 
       
 25587     var fraction = ('' + number).split(DECIMAL_SEP);
       
 25588     var whole = fraction[0];
       
 25589     fraction = fraction[1] || '';
       
 25590 
       
 25591     var i, pos = 0,
       
 25592         lgroup = pattern.lgSize,
       
 25593         group = pattern.gSize;
       
 25594 
       
 25595     if (whole.length >= (lgroup + group)) {
       
 25596       pos = whole.length - lgroup;
       
 25597       for (i = 0; i < pos; i++) {
       
 25598         if ((pos - i)%group === 0 && i !== 0) {
       
 25599           formatedText += groupSep;
       
 25600         }
       
 25601         formatedText += whole.charAt(i);
       
 25602       }
       
 25603     }
       
 25604 
       
 25605     for (i = pos; i < whole.length; i++) {
       
 25606       if ((whole.length - i)%lgroup === 0 && i !== 0) {
       
 25607         formatedText += groupSep;
       
 25608       }
       
 25609       formatedText += whole.charAt(i);
       
 25610     }
       
 25611 
       
 25612     // format fraction part.
       
 25613     while(fraction.length < fractionSize) {
       
 25614       fraction += '0';
       
 25615     }
       
 25616 
       
 25617     if (fractionSize && fractionSize !== "0") formatedText += decimalSep + fraction.substr(0, fractionSize);
       
 25618   } else {
       
 25619 
       
 25620     if (fractionSize > 0 && number > -1 && number < 1) {
       
 25621       formatedText = number.toFixed(fractionSize);
       
 25622     }
       
 25623   }
       
 25624 
       
 25625   parts.push(isNegative ? pattern.negPre : pattern.posPre);
       
 25626   parts.push(formatedText);
       
 25627   parts.push(isNegative ? pattern.negSuf : pattern.posSuf);
       
 25628   return parts.join('');
       
 25629 }
       
 25630 
       
 25631 function padNumber(num, digits, trim) {
       
 25632   var neg = '';
       
 25633   if (num < 0) {
       
 25634     neg =  '-';
       
 25635     num = -num;
       
 25636   }
       
 25637   num = '' + num;
       
 25638   while(num.length < digits) num = '0' + num;
       
 25639   if (trim)
       
 25640     num = num.substr(num.length - digits);
       
 25641   return neg + num;
       
 25642 }
       
 25643 
       
 25644 
       
 25645 function dateGetter(name, size, offset, trim) {
       
 25646   offset = offset || 0;
       
 25647   return function(date) {
       
 25648     var value = date['get' + name]();
       
 25649     if (offset > 0 || value > -offset)
       
 25650       value += offset;
       
 25651     if (value === 0 && offset == -12 ) value = 12;
       
 25652     return padNumber(value, size, trim);
       
 25653   };
       
 25654 }
       
 25655 
       
 25656 function dateStrGetter(name, shortForm) {
       
 25657   return function(date, formats) {
       
 25658     var value = date['get' + name]();
       
 25659     var get = uppercase(shortForm ? ('SHORT' + name) : name);
       
 25660 
       
 25661     return formats[get][value];
       
 25662   };
       
 25663 }
       
 25664 
       
 25665 function timeZoneGetter(date) {
       
 25666   var zone = -1 * date.getTimezoneOffset();
       
 25667   var paddedZone = (zone >= 0) ? "+" : "";
       
 25668 
       
 25669   paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) +
       
 25670                 padNumber(Math.abs(zone % 60), 2);
       
 25671 
       
 25672   return paddedZone;
       
 25673 }
       
 25674 
       
 25675 function getFirstThursdayOfYear(year) {
       
 25676     // 0 = index of January
       
 25677     var dayOfWeekOnFirst = (new Date(year, 0, 1)).getDay();
       
 25678     // 4 = index of Thursday (+1 to account for 1st = 5)
       
 25679     // 11 = index of *next* Thursday (+1 account for 1st = 12)
       
 25680     return new Date(year, 0, ((dayOfWeekOnFirst <= 4) ? 5 : 12) - dayOfWeekOnFirst);
       
 25681 }
       
 25682 
       
 25683 function getThursdayThisWeek(datetime) {
       
 25684     return new Date(datetime.getFullYear(), datetime.getMonth(),
       
 25685       // 4 = index of Thursday
       
 25686       datetime.getDate() + (4 - datetime.getDay()));
       
 25687 }
       
 25688 
       
 25689 function weekGetter(size) {
       
 25690    return function(date) {
       
 25691       var firstThurs = getFirstThursdayOfYear(date.getFullYear()),
       
 25692          thisThurs = getThursdayThisWeek(date);
       
 25693 
       
 25694       var diff = +thisThurs - +firstThurs,
       
 25695          result = 1 + Math.round(diff / 6.048e8); // 6.048e8 ms per week
       
 25696 
       
 25697       return padNumber(result, size);
       
 25698    };
       
 25699 }
       
 25700 
       
 25701 function ampmGetter(date, formats) {
       
 25702   return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1];
       
 25703 }
       
 25704 
       
 25705 var DATE_FORMATS = {
       
 25706   yyyy: dateGetter('FullYear', 4),
       
 25707     yy: dateGetter('FullYear', 2, 0, true),
       
 25708      y: dateGetter('FullYear', 1),
       
 25709   MMMM: dateStrGetter('Month'),
       
 25710    MMM: dateStrGetter('Month', true),
       
 25711     MM: dateGetter('Month', 2, 1),
       
 25712      M: dateGetter('Month', 1, 1),
       
 25713     dd: dateGetter('Date', 2),
       
 25714      d: dateGetter('Date', 1),
       
 25715     HH: dateGetter('Hours', 2),
       
 25716      H: dateGetter('Hours', 1),
       
 25717     hh: dateGetter('Hours', 2, -12),
       
 25718      h: dateGetter('Hours', 1, -12),
       
 25719     mm: dateGetter('Minutes', 2),
       
 25720      m: dateGetter('Minutes', 1),
       
 25721     ss: dateGetter('Seconds', 2),
       
 25722      s: dateGetter('Seconds', 1),
       
 25723      // while ISO 8601 requires fractions to be prefixed with `.` or `,`
       
 25724      // we can be just safely rely on using `sss` since we currently don't support single or two digit fractions
       
 25725    sss: dateGetter('Milliseconds', 3),
       
 25726   EEEE: dateStrGetter('Day'),
       
 25727    EEE: dateStrGetter('Day', true),
       
 25728      a: ampmGetter,
       
 25729      Z: timeZoneGetter,
       
 25730     ww: weekGetter(2),
       
 25731      w: weekGetter(1)
       
 25732 };
       
 25733 
       
 25734 var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZEw']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z|w+))(.*)/,
       
 25735     NUMBER_STRING = /^\-?\d+$/;
       
 25736 
       
 25737 /**
       
 25738  * @ngdoc filter
       
 25739  * @name date
       
 25740  * @kind function
       
 25741  *
       
 25742  * @description
       
 25743  *   Formats `date` to a string based on the requested `format`.
       
 25744  *
       
 25745  *   `format` string can be composed of the following elements:
       
 25746  *
       
 25747  *   * `'yyyy'`: 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010)
       
 25748  *   * `'yy'`: 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10)
       
 25749  *   * `'y'`: 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199)
       
 25750  *   * `'MMMM'`: Month in year (January-December)
       
 25751  *   * `'MMM'`: Month in year (Jan-Dec)
       
 25752  *   * `'MM'`: Month in year, padded (01-12)
       
 25753  *   * `'M'`: Month in year (1-12)
       
 25754  *   * `'dd'`: Day in month, padded (01-31)
       
 25755  *   * `'d'`: Day in month (1-31)
       
 25756  *   * `'EEEE'`: Day in Week,(Sunday-Saturday)
       
 25757  *   * `'EEE'`: Day in Week, (Sun-Sat)
       
 25758  *   * `'HH'`: Hour in day, padded (00-23)
       
 25759  *   * `'H'`: Hour in day (0-23)
       
 25760  *   * `'hh'`: Hour in AM/PM, padded (01-12)
       
 25761  *   * `'h'`: Hour in AM/PM, (1-12)
       
 25762  *   * `'mm'`: Minute in hour, padded (00-59)
       
 25763  *   * `'m'`: Minute in hour (0-59)
       
 25764  *   * `'ss'`: Second in minute, padded (00-59)
       
 25765  *   * `'s'`: Second in minute (0-59)
       
 25766  *   * `'.sss' or ',sss'`: Millisecond in second, padded (000-999)
       
 25767  *   * `'a'`: AM/PM marker
       
 25768  *   * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200)
       
 25769  *   * `'ww'`: ISO-8601 week of year (00-53)
       
 25770  *   * `'w'`: ISO-8601 week of year (0-53)
       
 25771  *
       
 25772  *   `format` string can also be one of the following predefined
       
 25773  *   {@link guide/i18n localizable formats}:
       
 25774  *
       
 25775  *   * `'medium'`: equivalent to `'MMM d, y h:mm:ss a'` for en_US locale
       
 25776  *     (e.g. Sep 3, 2010 12:05:08 PM)
       
 25777  *   * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US  locale (e.g. 9/3/10 12:05 PM)
       
 25778  *   * `'fullDate'`: equivalent to `'EEEE, MMMM d, y'` for en_US  locale
       
 25779  *     (e.g. Friday, September 3, 2010)
       
 25780  *   * `'longDate'`: equivalent to `'MMMM d, y'` for en_US  locale (e.g. September 3, 2010)
       
 25781  *   * `'mediumDate'`: equivalent to `'MMM d, y'` for en_US  locale (e.g. Sep 3, 2010)
       
 25782  *   * `'shortDate'`: equivalent to `'M/d/yy'` for en_US locale (e.g. 9/3/10)
       
 25783  *   * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 PM)
       
 25784  *   * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 PM)
       
 25785  *
       
 25786  *   `format` string can contain literal values. These need to be escaped by surrounding with single quotes (e.g.
       
 25787  *   `"h 'in the morning'"`). In order to output a single quote, escape it - i.e., two single quotes in a sequence
       
 25788  *   (e.g. `"h 'o''clock'"`).
       
 25789  *
       
 25790  * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
       
 25791  *    number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.sssZ and its
       
 25792  *    shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is
       
 25793  *    specified in the string input, the time is considered to be in the local timezone.
       
 25794  * @param {string=} format Formatting rules (see Description). If not specified,
       
 25795  *    `mediumDate` is used.
       
 25796  * @param {string=} timezone Timezone to be used for formatting. Right now, only `'UTC'` is supported.
       
 25797  *    If not specified, the timezone of the browser will be used.
       
 25798  * @returns {string} Formatted string or the input if input is not recognized as date/millis.
       
 25799  *
       
 25800  * @example
       
 25801    <example>
       
 25802      <file name="index.html">
       
 25803        <span ng-non-bindable>{{1288323623006 | date:'medium'}}</span>:
       
 25804            <span>{{1288323623006 | date:'medium'}}</span><br>
       
 25805        <span ng-non-bindable>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span>:
       
 25806           <span>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span><br>
       
 25807        <span ng-non-bindable>{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}</span>:
       
 25808           <span>{{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}</span><br>
       
 25809        <span ng-non-bindable>{{1288323623006 | date:"MM/dd/yyyy 'at' h:mma"}}</span>:
       
 25810           <span>{{'1288323623006' | date:"MM/dd/yyyy 'at' h:mma"}}</span><br>
       
 25811      </file>
       
 25812      <file name="protractor.js" type="protractor">
       
 25813        it('should format date', function() {
       
 25814          expect(element(by.binding("1288323623006 | date:'medium'")).getText()).
       
 25815             toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/);
       
 25816          expect(element(by.binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).getText()).
       
 25817             toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/);
       
 25818          expect(element(by.binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).getText()).
       
 25819             toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
       
 25820          expect(element(by.binding("'1288323623006' | date:\"MM/dd/yyyy 'at' h:mma\"")).getText()).
       
 25821             toMatch(/10\/2\d\/2010 at \d{1,2}:\d{2}(AM|PM)/);
       
 25822        });
       
 25823      </file>
       
 25824    </example>
       
 25825  */
       
 25826 dateFilter.$inject = ['$locale'];
       
 25827 function dateFilter($locale) {
       
 25828 
       
 25829 
       
 25830   var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
       
 25831                      // 1        2       3         4          5          6          7          8  9     10      11
       
 25832   function jsonStringToDate(string) {
       
 25833     var match;
       
 25834     if (match = string.match(R_ISO8601_STR)) {
       
 25835       var date = new Date(0),
       
 25836           tzHour = 0,
       
 25837           tzMin  = 0,
       
 25838           dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear,
       
 25839           timeSetter = match[8] ? date.setUTCHours : date.setHours;
       
 25840 
       
 25841       if (match[9]) {
       
 25842         tzHour = int(match[9] + match[10]);
       
 25843         tzMin = int(match[9] + match[11]);
       
 25844       }
       
 25845       dateSetter.call(date, int(match[1]), int(match[2]) - 1, int(match[3]));
       
 25846       var h = int(match[4]||0) - tzHour;
       
 25847       var m = int(match[5]||0) - tzMin;
       
 25848       var s = int(match[6]||0);
       
 25849       var ms = Math.round(parseFloat('0.' + (match[7]||0)) * 1000);
       
 25850       timeSetter.call(date, h, m, s, ms);
       
 25851       return date;
       
 25852     }
       
 25853     return string;
       
 25854   }
       
 25855 
       
 25856 
       
 25857   return function(date, format, timezone) {
       
 25858     var text = '',
       
 25859         parts = [],
       
 25860         fn, match;
       
 25861 
       
 25862     format = format || 'mediumDate';
       
 25863     format = $locale.DATETIME_FORMATS[format] || format;
       
 25864     if (isString(date)) {
       
 25865       date = NUMBER_STRING.test(date) ? int(date) : jsonStringToDate(date);
       
 25866     }
       
 25867 
       
 25868     if (isNumber(date)) {
       
 25869       date = new Date(date);
       
 25870     }
       
 25871 
       
 25872     if (!isDate(date)) {
       
 25873       return date;
       
 25874     }
       
 25875 
       
 25876     while(format) {
       
 25877       match = DATE_FORMATS_SPLIT.exec(format);
       
 25878       if (match) {
       
 25879         parts = concat(parts, match, 1);
       
 25880         format = parts.pop();
       
 25881       } else {
       
 25882         parts.push(format);
       
 25883         format = null;
       
 25884       }
       
 25885     }
       
 25886 
       
 25887     if (timezone && timezone === 'UTC') {
       
 25888       date = new Date(date.getTime());
       
 25889       date.setMinutes(date.getMinutes() + date.getTimezoneOffset());
       
 25890     }
       
 25891     forEach(parts, function(value){
       
 25892       fn = DATE_FORMATS[value];
       
 25893       text += fn ? fn(date, $locale.DATETIME_FORMATS)
       
 25894                  : value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
       
 25895     });
       
 25896 
       
 25897     return text;
       
 25898   };
       
 25899 }
       
 25900 
       
 25901 
       
 25902 /**
       
 25903  * @ngdoc filter
       
 25904  * @name json
       
 25905  * @kind function
       
 25906  *
       
 25907  * @description
       
 25908  *   Allows you to convert a JavaScript object into JSON string.
       
 25909  *
       
 25910  *   This filter is mostly useful for debugging. When using the double curly {{value}} notation
       
 25911  *   the binding is automatically converted to JSON.
       
 25912  *
       
 25913  * @param {*} object Any JavaScript object (including arrays and primitive types) to filter.
       
 25914  * @returns {string} JSON string.
       
 25915  *
       
 25916  *
       
 25917  * @example
       
 25918    <example>
       
 25919      <file name="index.html">
       
 25920        <pre>{{ {'name':'value'} | json }}</pre>
       
 25921      </file>
       
 25922      <file name="protractor.js" type="protractor">
       
 25923        it('should jsonify filtered objects', function() {
       
 25924          expect(element(by.binding("{'name':'value'}")).getText()).toMatch(/\{\n  "name": ?"value"\n}/);
       
 25925        });
       
 25926      </file>
       
 25927    </example>
       
 25928  *
       
 25929  */
       
 25930 function jsonFilter() {
       
 25931   return function(object) {
       
 25932     return toJson(object, true);
       
 25933   };
       
 25934 }
       
 25935 
       
 25936 
       
 25937 /**
       
 25938  * @ngdoc filter
       
 25939  * @name lowercase
       
 25940  * @kind function
       
 25941  * @description
       
 25942  * Converts string to lowercase.
       
 25943  * @see angular.lowercase
       
 25944  */
       
 25945 var lowercaseFilter = valueFn(lowercase);
       
 25946 
       
 25947 
       
 25948 /**
       
 25949  * @ngdoc filter
       
 25950  * @name uppercase
       
 25951  * @kind function
       
 25952  * @description
       
 25953  * Converts string to uppercase.
       
 25954  * @see angular.uppercase
       
 25955  */
       
 25956 var uppercaseFilter = valueFn(uppercase);
       
 25957 
       
 25958 /**
       
 25959  * @ngdoc filter
       
 25960  * @name limitTo
       
 25961  * @kind function
       
 25962  *
       
 25963  * @description
       
 25964  * Creates a new array or string containing only a specified number of elements. The elements
       
 25965  * are taken from either the beginning or the end of the source array, string or number, as specified by
       
 25966  * the value and sign (positive or negative) of `limit`. If a number is used as input, it is
       
 25967  * converted to a string.
       
 25968  *
       
 25969  * @param {Array|string|number} input Source array, string or number to be limited.
       
 25970  * @param {string|number} limit The length of the returned array or string. If the `limit` number
       
 25971  *     is positive, `limit` number of items from the beginning of the source array/string are copied.
       
 25972  *     If the number is negative, `limit` number  of items from the end of the source array/string
       
 25973  *     are copied. The `limit` will be trimmed if it exceeds `array.length`
       
 25974  * @returns {Array|string} A new sub-array or substring of length `limit` or less if input array
       
 25975  *     had less than `limit` elements.
       
 25976  *
       
 25977  * @example
       
 25978    <example module="limitToExample">
       
 25979      <file name="index.html">
       
 25980        <script>
       
 25981          angular.module('limitToExample', [])
       
 25982            .controller('ExampleController', ['$scope', function($scope) {
       
 25983              $scope.numbers = [1,2,3,4,5,6,7,8,9];
       
 25984              $scope.letters = "abcdefghi";
       
 25985              $scope.longNumber = 2345432342;
       
 25986              $scope.numLimit = 3;
       
 25987              $scope.letterLimit = 3;
       
 25988              $scope.longNumberLimit = 3;
       
 25989            }]);
       
 25990        </script>
       
 25991        <div ng-controller="ExampleController">
       
 25992          Limit {{numbers}} to: <input type="number" step="1" ng-model="numLimit">
       
 25993          <p>Output numbers: {{ numbers | limitTo:numLimit }}</p>
       
 25994          Limit {{letters}} to: <input type="number" step="1" ng-model="letterLimit">
       
 25995          <p>Output letters: {{ letters | limitTo:letterLimit }}</p>
       
 25996          Limit {{longNumber}} to: <input type="integer" ng-model="longNumberLimit">
       
 25997          <p>Output long number: {{ longNumber | limitTo:longNumberLimit }}</p>
       
 25998        </div>
       
 25999      </file>
       
 26000      <file name="protractor.js" type="protractor">
       
 26001        var numLimitInput = element(by.model('numLimit'));
       
 26002        var letterLimitInput = element(by.model('letterLimit'));
       
 26003        var longNumberLimitInput = element(by.model('longNumberLimit'));
       
 26004        var limitedNumbers = element(by.binding('numbers | limitTo:numLimit'));
       
 26005        var limitedLetters = element(by.binding('letters | limitTo:letterLimit'));
       
 26006        var limitedLongNumber = element(by.binding('longNumber | limitTo:longNumberLimit'));
       
 26007 
       
 26008        it('should limit the number array to first three items', function() {
       
 26009          expect(numLimitInput.getAttribute('value')).toBe('3');
       
 26010          expect(letterLimitInput.getAttribute('value')).toBe('3');
       
 26011          expect(longNumberLimitInput.getAttribute('value')).toBe('3');
       
 26012          expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3]');
       
 26013          expect(limitedLetters.getText()).toEqual('Output letters: abc');
       
 26014          expect(limitedLongNumber.getText()).toEqual('Output long number: 234');
       
 26015        });
       
 26016 
       
 26017        // There is a bug in safari and protractor that doesn't like the minus key
       
 26018        // it('should update the output when -3 is entered', function() {
       
 26019        //   numLimitInput.clear();
       
 26020        //   numLimitInput.sendKeys('-3');
       
 26021        //   letterLimitInput.clear();
       
 26022        //   letterLimitInput.sendKeys('-3');
       
 26023        //   longNumberLimitInput.clear();
       
 26024        //   longNumberLimitInput.sendKeys('-3');
       
 26025        //   expect(limitedNumbers.getText()).toEqual('Output numbers: [7,8,9]');
       
 26026        //   expect(limitedLetters.getText()).toEqual('Output letters: ghi');
       
 26027        //   expect(limitedLongNumber.getText()).toEqual('Output long number: 342');
       
 26028        // });
       
 26029 
       
 26030        it('should not exceed the maximum size of input array', function() {
       
 26031          numLimitInput.clear();
       
 26032          numLimitInput.sendKeys('100');
       
 26033          letterLimitInput.clear();
       
 26034          letterLimitInput.sendKeys('100');
       
 26035          longNumberLimitInput.clear();
       
 26036          longNumberLimitInput.sendKeys('100');
       
 26037          expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3,4,5,6,7,8,9]');
       
 26038          expect(limitedLetters.getText()).toEqual('Output letters: abcdefghi');
       
 26039          expect(limitedLongNumber.getText()).toEqual('Output long number: 2345432342');
       
 26040        });
       
 26041      </file>
       
 26042    </example>
       
 26043 */
       
 26044 function limitToFilter(){
       
 26045   return function(input, limit) {
       
 26046     if (isNumber(input)) input = input.toString();
       
 26047     if (!isArray(input) && !isString(input)) return input;
       
 26048 
       
 26049     if (Math.abs(Number(limit)) === Infinity) {
       
 26050       limit = Number(limit);
       
 26051     } else {
       
 26052       limit = int(limit);
       
 26053     }
       
 26054 
       
 26055     if (isString(input)) {
       
 26056       //NaN check on limit
       
 26057       if (limit) {
       
 26058         return limit >= 0 ? input.slice(0, limit) : input.slice(limit, input.length);
       
 26059       } else {
       
 26060         return "";
       
 26061       }
       
 26062     }
       
 26063 
       
 26064     var out = [],
       
 26065       i, n;
       
 26066 
       
 26067     // if abs(limit) exceeds maximum length, trim it
       
 26068     if (limit > input.length)
       
 26069       limit = input.length;
       
 26070     else if (limit < -input.length)
       
 26071       limit = -input.length;
       
 26072 
       
 26073     if (limit > 0) {
       
 26074       i = 0;
       
 26075       n = limit;
       
 26076     } else {
       
 26077       i = input.length + limit;
       
 26078       n = input.length;
       
 26079     }
       
 26080 
       
 26081     for (; i<n; i++) {
       
 26082       out.push(input[i]);
       
 26083     }
       
 26084 
       
 26085     return out;
       
 26086   };
       
 26087 }
       
 26088 
       
 26089 /**
       
 26090  * @ngdoc filter
       
 26091  * @name orderBy
       
 26092  * @kind function
       
 26093  *
       
 26094  * @description
       
 26095  * Orders a specified `array` by the `expression` predicate. It is ordered alphabetically
       
 26096  * for strings and numerically for numbers. Note: if you notice numbers are not being sorted
       
 26097  * correctly, make sure they are actually being saved as numbers and not strings.
       
 26098  *
       
 26099  * @param {Array} array The array to sort.
       
 26100  * @param {function(*)|string|Array.<(function(*)|string)>=} expression A predicate to be
       
 26101  *    used by the comparator to determine the order of elements.
       
 26102  *
       
 26103  *    Can be one of:
       
 26104  *
       
 26105  *    - `function`: Getter function. The result of this function will be sorted using the
       
 26106  *      `<`, `=`, `>` operator.
       
 26107  *    - `string`: An Angular expression. The result of this expression is used to compare elements
       
 26108  *      (for example `name` to sort by a property called `name` or `name.substr(0, 3)` to sort by
       
 26109  *      3 first characters of a property called `name`). The result of a constant expression
       
 26110  *      is interpreted as a property name to be used in comparisons (for example `"special name"`
       
 26111  *      to sort object by the value of their `special name` property). An expression can be
       
 26112  *      optionally prefixed with `+` or `-` to control ascending or descending sort order
       
 26113  *      (for example, `+name` or `-name`). If no property is provided, (e.g. `'+'`) then the array
       
 26114  *      element itself is used to compare where sorting.
       
 26115  *    - `Array`: An array of function or string predicates. The first predicate in the array
       
 26116  *      is used for sorting, but when two items are equivalent, the next predicate is used.
       
 26117  *
       
 26118  *    If the predicate is missing or empty then it defaults to `'+'`.
       
 26119  *
       
 26120  * @param {boolean=} reverse Reverse the order of the array.
       
 26121  * @returns {Array} Sorted copy of the source array.
       
 26122  *
       
 26123  * @example
       
 26124    <example module="orderByExample">
       
 26125      <file name="index.html">
       
 26126        <script>
       
 26127          angular.module('orderByExample', [])
       
 26128            .controller('ExampleController', ['$scope', function($scope) {
       
 26129              $scope.friends =
       
 26130                  [{name:'John', phone:'555-1212', age:10},
       
 26131                   {name:'Mary', phone:'555-9876', age:19},
       
 26132                   {name:'Mike', phone:'555-4321', age:21},
       
 26133                   {name:'Adam', phone:'555-5678', age:35},
       
 26134                   {name:'Julie', phone:'555-8765', age:29}];
       
 26135              $scope.predicate = '-age';
       
 26136            }]);
       
 26137        </script>
       
 26138        <div ng-controller="ExampleController">
       
 26139          <pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
       
 26140          <hr/>
       
 26141          [ <a href="" ng-click="predicate=''">unsorted</a> ]
       
 26142          <table class="friend">
       
 26143            <tr>
       
 26144              <th><a href="" ng-click="predicate = 'name'; reverse=false">Name</a>
       
 26145                  (<a href="" ng-click="predicate = '-name'; reverse=false">^</a>)</th>
       
 26146              <th><a href="" ng-click="predicate = 'phone'; reverse=!reverse">Phone Number</a></th>
       
 26147              <th><a href="" ng-click="predicate = 'age'; reverse=!reverse">Age</a></th>
       
 26148            </tr>
       
 26149            <tr ng-repeat="friend in friends | orderBy:predicate:reverse">
       
 26150              <td>{{friend.name}}</td>
       
 26151              <td>{{friend.phone}}</td>
       
 26152              <td>{{friend.age}}</td>
       
 26153            </tr>
       
 26154          </table>
       
 26155        </div>
       
 26156      </file>
       
 26157    </example>
       
 26158  *
       
 26159  * It's also possible to call the orderBy filter manually, by injecting `$filter`, retrieving the
       
 26160  * filter routine with `$filter('orderBy')`, and calling the returned filter routine with the
       
 26161  * desired parameters.
       
 26162  *
       
 26163  * Example:
       
 26164  *
       
 26165  * @example
       
 26166   <example module="orderByExample">
       
 26167     <file name="index.html">
       
 26168       <div ng-controller="ExampleController">
       
 26169         <table class="friend">
       
 26170           <tr>
       
 26171             <th><a href="" ng-click="reverse=false;order('name', false)">Name</a>
       
 26172               (<a href="" ng-click="order('-name',false)">^</a>)</th>
       
 26173             <th><a href="" ng-click="reverse=!reverse;order('phone', reverse)">Phone Number</a></th>
       
 26174             <th><a href="" ng-click="reverse=!reverse;order('age',reverse)">Age</a></th>
       
 26175           </tr>
       
 26176           <tr ng-repeat="friend in friends">
       
 26177             <td>{{friend.name}}</td>
       
 26178             <td>{{friend.phone}}</td>
       
 26179             <td>{{friend.age}}</td>
       
 26180           </tr>
       
 26181         </table>
       
 26182       </div>
       
 26183     </file>
       
 26184 
       
 26185     <file name="script.js">
       
 26186       angular.module('orderByExample', [])
       
 26187         .controller('ExampleController', ['$scope', '$filter', function($scope, $filter) {
       
 26188           var orderBy = $filter('orderBy');
       
 26189           $scope.friends = [
       
 26190             { name: 'John',    phone: '555-1212',    age: 10 },
       
 26191             { name: 'Mary',    phone: '555-9876',    age: 19 },
       
 26192             { name: 'Mike',    phone: '555-4321',    age: 21 },
       
 26193             { name: 'Adam',    phone: '555-5678',    age: 35 },
       
 26194             { name: 'Julie',   phone: '555-8765',    age: 29 }
       
 26195           ];
       
 26196           $scope.order = function(predicate, reverse) {
       
 26197             $scope.friends = orderBy($scope.friends, predicate, reverse);
       
 26198           };
       
 26199           $scope.order('-age',false);
       
 26200         }]);
       
 26201     </file>
       
 26202 </example>
       
 26203  */
       
 26204 orderByFilter.$inject = ['$parse'];
       
 26205 function orderByFilter($parse){
       
 26206   return function(array, sortPredicate, reverseOrder) {
       
 26207     if (!(isArrayLike(array))) return array;
       
 26208     sortPredicate = isArray(sortPredicate) ? sortPredicate: [sortPredicate];
       
 26209     if (sortPredicate.length === 0) { sortPredicate = ['+']; }
       
 26210     sortPredicate = sortPredicate.map(function(predicate){
       
 26211       var descending = false, get = predicate || identity;
       
 26212       if (isString(predicate)) {
       
 26213         if ((predicate.charAt(0) == '+' || predicate.charAt(0) == '-')) {
       
 26214           descending = predicate.charAt(0) == '-';
       
 26215           predicate = predicate.substring(1);
       
 26216         }
       
 26217         if ( predicate === '' ) {
       
 26218           // Effectively no predicate was passed so we compare identity
       
 26219           return reverseComparator(function(a,b) {
       
 26220             return compare(a, b);
       
 26221           }, descending);
       
 26222         }
       
 26223         get = $parse(predicate);
       
 26224         if (get.constant) {
       
 26225           var key = get();
       
 26226           return reverseComparator(function(a,b) {
       
 26227             return compare(a[key], b[key]);
       
 26228           }, descending);
       
 26229         }
       
 26230       }
       
 26231       return reverseComparator(function(a,b){
       
 26232         return compare(get(a),get(b));
       
 26233       }, descending);
       
 26234     });
       
 26235     var arrayCopy = [];
       
 26236     for ( var i = 0; i < array.length; i++) { arrayCopy.push(array[i]); }
       
 26237     return arrayCopy.sort(reverseComparator(comparator, reverseOrder));
       
 26238 
       
 26239     function comparator(o1, o2){
       
 26240       for ( var i = 0; i < sortPredicate.length; i++) {
       
 26241         var comp = sortPredicate[i](o1, o2);
       
 26242         if (comp !== 0) return comp;
       
 26243       }
       
 26244       return 0;
       
 26245     }
       
 26246     function reverseComparator(comp, descending) {
       
 26247       return descending
       
 26248           ? function(a,b){return comp(b,a);}
       
 26249           : comp;
       
 26250     }
       
 26251     function compare(v1, v2){
       
 26252       var t1 = typeof v1;
       
 26253       var t2 = typeof v2;
       
 26254       if (t1 == t2) {
       
 26255         if (isDate(v1) && isDate(v2)) {
       
 26256           v1 = v1.valueOf();
       
 26257           v2 = v2.valueOf();
       
 26258         }
       
 26259         if (t1 == "string") {
       
 26260            v1 = v1.toLowerCase();
       
 26261            v2 = v2.toLowerCase();
       
 26262         }
       
 26263         if (v1 === v2) return 0;
       
 26264         return v1 < v2 ? -1 : 1;
       
 26265       } else {
       
 26266         return t1 < t2 ? -1 : 1;
       
 26267       }
       
 26268     }
       
 26269   };
       
 26270 }
       
 26271 
       
 26272 function ngDirective(directive) {
       
 26273   if (isFunction(directive)) {
       
 26274     directive = {
       
 26275       link: directive
       
 26276     };
       
 26277   }
       
 26278   directive.restrict = directive.restrict || 'AC';
       
 26279   return valueFn(directive);
       
 26280 }
       
 26281 
       
 26282 /**
       
 26283  * @ngdoc directive
       
 26284  * @name a
       
 26285  * @restrict E
       
 26286  *
       
 26287  * @description
       
 26288  * Modifies the default behavior of the html A tag so that the default action is prevented when
       
 26289  * the href attribute is empty.
       
 26290  *
       
 26291  * This change permits the easy creation of action links with the `ngClick` directive
       
 26292  * without changing the location or causing page reloads, e.g.:
       
 26293  * `<a href="" ng-click="list.addItem()">Add Item</a>`
       
 26294  */
       
 26295 var htmlAnchorDirective = valueFn({
       
 26296   restrict: 'E',
       
 26297   compile: function(element, attr) {
       
 26298     if (!attr.href && !attr.xlinkHref && !attr.name) {
       
 26299       return function(scope, element) {
       
 26300         // SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
       
 26301         var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
       
 26302                    'xlink:href' : 'href';
       
 26303         element.on('click', function(event){
       
 26304           // if we have no href url, then don't navigate anywhere.
       
 26305           if (!element.attr(href)) {
       
 26306             event.preventDefault();
       
 26307           }
       
 26308         });
       
 26309       };
       
 26310     }
       
 26311   }
       
 26312 });
       
 26313 
       
 26314 /**
       
 26315  * @ngdoc directive
       
 26316  * @name ngHref
       
 26317  * @restrict A
       
 26318  * @priority 99
       
 26319  *
       
 26320  * @description
       
 26321  * Using Angular markup like `{{hash}}` in an href attribute will
       
 26322  * make the link go to the wrong URL if the user clicks it before
       
 26323  * Angular has a chance to replace the `{{hash}}` markup with its
       
 26324  * value. Until Angular replaces the markup the link will be broken
       
 26325  * and will most likely return a 404 error.
       
 26326  *
       
 26327  * The `ngHref` directive solves this problem.
       
 26328  *
       
 26329  * The wrong way to write it:
       
 26330  * ```html
       
 26331  * <a href="http://www.gravatar.com/avatar/{{hash}}">link1</a>
       
 26332  * ```
       
 26333  *
       
 26334  * The correct way to write it:
       
 26335  * ```html
       
 26336  * <a ng-href="http://www.gravatar.com/avatar/{{hash}}">link1</a>
       
 26337  * ```
       
 26338  *
       
 26339  * @element A
       
 26340  * @param {template} ngHref any string which can contain `{{}}` markup.
       
 26341  *
       
 26342  * @example
       
 26343  * This example shows various combinations of `href`, `ng-href` and `ng-click` attributes
       
 26344  * in links and their different behaviors:
       
 26345     <example>
       
 26346       <file name="index.html">
       
 26347         <input ng-model="value" /><br />
       
 26348         <a id="link-1" href ng-click="value = 1">link 1</a> (link, don't reload)<br />
       
 26349         <a id="link-2" href="" ng-click="value = 2">link 2</a> (link, don't reload)<br />
       
 26350         <a id="link-3" ng-href="/{{'123'}}">link 3</a> (link, reload!)<br />
       
 26351         <a id="link-4" href="" name="xx" ng-click="value = 4">anchor</a> (link, don't reload)<br />
       
 26352         <a id="link-5" name="xxx" ng-click="value = 5">anchor</a> (no link)<br />
       
 26353         <a id="link-6" ng-href="{{value}}">link</a> (link, change location)
       
 26354       </file>
       
 26355       <file name="protractor.js" type="protractor">
       
 26356         it('should execute ng-click but not reload when href without value', function() {
       
 26357           element(by.id('link-1')).click();
       
 26358           expect(element(by.model('value')).getAttribute('value')).toEqual('1');
       
 26359           expect(element(by.id('link-1')).getAttribute('href')).toBe('');
       
 26360         });
       
 26361 
       
 26362         it('should execute ng-click but not reload when href empty string', function() {
       
 26363           element(by.id('link-2')).click();
       
 26364           expect(element(by.model('value')).getAttribute('value')).toEqual('2');
       
 26365           expect(element(by.id('link-2')).getAttribute('href')).toBe('');
       
 26366         });
       
 26367 
       
 26368         it('should execute ng-click and change url when ng-href specified', function() {
       
 26369           expect(element(by.id('link-3')).getAttribute('href')).toMatch(/\/123$/);
       
 26370 
       
 26371           element(by.id('link-3')).click();
       
 26372 
       
 26373           // At this point, we navigate away from an Angular page, so we need
       
 26374           // to use browser.driver to get the base webdriver.
       
 26375 
       
 26376           browser.wait(function() {
       
 26377             return browser.driver.getCurrentUrl().then(function(url) {
       
 26378               return url.match(/\/123$/);
       
 26379             });
       
 26380           }, 5000, 'page should navigate to /123');
       
 26381         });
       
 26382 
       
 26383         xit('should execute ng-click but not reload when href empty string and name specified', function() {
       
 26384           element(by.id('link-4')).click();
       
 26385           expect(element(by.model('value')).getAttribute('value')).toEqual('4');
       
 26386           expect(element(by.id('link-4')).getAttribute('href')).toBe('');
       
 26387         });
       
 26388 
       
 26389         it('should execute ng-click but not reload when no href but name specified', function() {
       
 26390           element(by.id('link-5')).click();
       
 26391           expect(element(by.model('value')).getAttribute('value')).toEqual('5');
       
 26392           expect(element(by.id('link-5')).getAttribute('href')).toBe(null);
       
 26393         });
       
 26394 
       
 26395         it('should only change url when only ng-href', function() {
       
 26396           element(by.model('value')).clear();
       
 26397           element(by.model('value')).sendKeys('6');
       
 26398           expect(element(by.id('link-6')).getAttribute('href')).toMatch(/\/6$/);
       
 26399 
       
 26400           element(by.id('link-6')).click();
       
 26401 
       
 26402           // At this point, we navigate away from an Angular page, so we need
       
 26403           // to use browser.driver to get the base webdriver.
       
 26404           browser.wait(function() {
       
 26405             return browser.driver.getCurrentUrl().then(function(url) {
       
 26406               return url.match(/\/6$/);
       
 26407             });
       
 26408           }, 5000, 'page should navigate to /6');
       
 26409         });
       
 26410       </file>
       
 26411     </example>
       
 26412  */
       
 26413 
       
 26414 /**
       
 26415  * @ngdoc directive
       
 26416  * @name ngSrc
       
 26417  * @restrict A
       
 26418  * @priority 99
       
 26419  *
       
 26420  * @description
       
 26421  * Using Angular markup like `{{hash}}` in a `src` attribute doesn't
       
 26422  * work right: The browser will fetch from the URL with the literal
       
 26423  * text `{{hash}}` until Angular replaces the expression inside
       
 26424  * `{{hash}}`. The `ngSrc` directive solves this problem.
       
 26425  *
       
 26426  * The buggy way to write it:
       
 26427  * ```html
       
 26428  * <img src="http://www.gravatar.com/avatar/{{hash}}"/>
       
 26429  * ```
       
 26430  *
       
 26431  * The correct way to write it:
       
 26432  * ```html
       
 26433  * <img ng-src="http://www.gravatar.com/avatar/{{hash}}"/>
       
 26434  * ```
       
 26435  *
       
 26436  * @element IMG
       
 26437  * @param {template} ngSrc any string which can contain `{{}}` markup.
       
 26438  */
       
 26439 
       
 26440 /**
       
 26441  * @ngdoc directive
       
 26442  * @name ngSrcset
       
 26443  * @restrict A
       
 26444  * @priority 99
       
 26445  *
       
 26446  * @description
       
 26447  * Using Angular markup like `{{hash}}` in a `srcset` attribute doesn't
       
 26448  * work right: The browser will fetch from the URL with the literal
       
 26449  * text `{{hash}}` until Angular replaces the expression inside
       
 26450  * `{{hash}}`. The `ngSrcset` directive solves this problem.
       
 26451  *
       
 26452  * The buggy way to write it:
       
 26453  * ```html
       
 26454  * <img srcset="http://www.gravatar.com/avatar/{{hash}} 2x"/>
       
 26455  * ```
       
 26456  *
       
 26457  * The correct way to write it:
       
 26458  * ```html
       
 26459  * <img ng-srcset="http://www.gravatar.com/avatar/{{hash}} 2x"/>
       
 26460  * ```
       
 26461  *
       
 26462  * @element IMG
       
 26463  * @param {template} ngSrcset any string which can contain `{{}}` markup.
       
 26464  */
       
 26465 
       
 26466 /**
       
 26467  * @ngdoc directive
       
 26468  * @name ngDisabled
       
 26469  * @restrict A
       
 26470  * @priority 100
       
 26471  *
       
 26472  * @description
       
 26473  *
       
 26474  * We shouldn't do this, because it will make the button enabled on Chrome/Firefox but not on IE8 and older IEs:
       
 26475  * ```html
       
 26476  * <div ng-init="scope = { isDisabled: false }">
       
 26477  *  <button disabled="{{scope.isDisabled}}">Disabled</button>
       
 26478  * </div>
       
 26479  * ```
       
 26480  *
       
 26481  * The HTML specification does not require browsers to preserve the values of boolean attributes
       
 26482  * such as disabled. (Their presence means true and their absence means false.)
       
 26483  * If we put an Angular interpolation expression into such an attribute then the
       
 26484  * binding information would be lost when the browser removes the attribute.
       
 26485  * The `ngDisabled` directive solves this problem for the `disabled` attribute.
       
 26486  * This complementary directive is not removed by the browser and so provides
       
 26487  * a permanent reliable place to store the binding information.
       
 26488  *
       
 26489  * @example
       
 26490     <example>
       
 26491       <file name="index.html">
       
 26492         Click me to toggle: <input type="checkbox" ng-model="checked"><br/>
       
 26493         <button ng-model="button" ng-disabled="checked">Button</button>
       
 26494       </file>
       
 26495       <file name="protractor.js" type="protractor">
       
 26496         it('should toggle button', function() {
       
 26497           expect(element(by.css('button')).getAttribute('disabled')).toBeFalsy();
       
 26498           element(by.model('checked')).click();
       
 26499           expect(element(by.css('button')).getAttribute('disabled')).toBeTruthy();
       
 26500         });
       
 26501       </file>
       
 26502     </example>
       
 26503  *
       
 26504  * @element INPUT
       
 26505  * @param {expression} ngDisabled If the {@link guide/expression expression} is truthy,
       
 26506  *     then special attribute "disabled" will be set on the element
       
 26507  */
       
 26508 
       
 26509 
       
 26510 /**
       
 26511  * @ngdoc directive
       
 26512  * @name ngChecked
       
 26513  * @restrict A
       
 26514  * @priority 100
       
 26515  *
       
 26516  * @description
       
 26517  * The HTML specification does not require browsers to preserve the values of boolean attributes
       
 26518  * such as checked. (Their presence means true and their absence means false.)
       
 26519  * If we put an Angular interpolation expression into such an attribute then the
       
 26520  * binding information would be lost when the browser removes the attribute.
       
 26521  * The `ngChecked` directive solves this problem for the `checked` attribute.
       
 26522  * This complementary directive is not removed by the browser and so provides
       
 26523  * a permanent reliable place to store the binding information.
       
 26524  * @example
       
 26525     <example>
       
 26526       <file name="index.html">
       
 26527         Check me to check both: <input type="checkbox" ng-model="master"><br/>
       
 26528         <input id="checkSlave" type="checkbox" ng-checked="master">
       
 26529       </file>
       
 26530       <file name="protractor.js" type="protractor">
       
 26531         it('should check both checkBoxes', function() {
       
 26532           expect(element(by.id('checkSlave')).getAttribute('checked')).toBeFalsy();
       
 26533           element(by.model('master')).click();
       
 26534           expect(element(by.id('checkSlave')).getAttribute('checked')).toBeTruthy();
       
 26535         });
       
 26536       </file>
       
 26537     </example>
       
 26538  *
       
 26539  * @element INPUT
       
 26540  * @param {expression} ngChecked If the {@link guide/expression expression} is truthy,
       
 26541  *     then special attribute "checked" will be set on the element
       
 26542  */
       
 26543 
       
 26544 
       
 26545 /**
       
 26546  * @ngdoc directive
       
 26547  * @name ngReadonly
       
 26548  * @restrict A
       
 26549  * @priority 100
       
 26550  *
       
 26551  * @description
       
 26552  * The HTML specification does not require browsers to preserve the values of boolean attributes
       
 26553  * such as readonly. (Their presence means true and their absence means false.)
       
 26554  * If we put an Angular interpolation expression into such an attribute then the
       
 26555  * binding information would be lost when the browser removes the attribute.
       
 26556  * The `ngReadonly` directive solves this problem for the `readonly` attribute.
       
 26557  * This complementary directive is not removed by the browser and so provides
       
 26558  * a permanent reliable place to store the binding information.
       
 26559  * @example
       
 26560     <example>
       
 26561       <file name="index.html">
       
 26562         Check me to make text readonly: <input type="checkbox" ng-model="checked"><br/>
       
 26563         <input type="text" ng-readonly="checked" value="I'm Angular"/>
       
 26564       </file>
       
 26565       <file name="protractor.js" type="protractor">
       
 26566         it('should toggle readonly attr', function() {
       
 26567           expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeFalsy();
       
 26568           element(by.model('checked')).click();
       
 26569           expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeTruthy();
       
 26570         });
       
 26571       </file>
       
 26572     </example>
       
 26573  *
       
 26574  * @element INPUT
       
 26575  * @param {expression} ngReadonly If the {@link guide/expression expression} is truthy,
       
 26576  *     then special attribute "readonly" will be set on the element
       
 26577  */
       
 26578 
       
 26579 
       
 26580 /**
       
 26581  * @ngdoc directive
       
 26582  * @name ngSelected
       
 26583  * @restrict A
       
 26584  * @priority 100
       
 26585  *
       
 26586  * @description
       
 26587  * The HTML specification does not require browsers to preserve the values of boolean attributes
       
 26588  * such as selected. (Their presence means true and their absence means false.)
       
 26589  * If we put an Angular interpolation expression into such an attribute then the
       
 26590  * binding information would be lost when the browser removes the attribute.
       
 26591  * The `ngSelected` directive solves this problem for the `selected` attribute.
       
 26592  * This complementary directive is not removed by the browser and so provides
       
 26593  * a permanent reliable place to store the binding information.
       
 26594  *
       
 26595  * @example
       
 26596     <example>
       
 26597       <file name="index.html">
       
 26598         Check me to select: <input type="checkbox" ng-model="selected"><br/>
       
 26599         <select>
       
 26600           <option>Hello!</option>
       
 26601           <option id="greet" ng-selected="selected">Greetings!</option>
       
 26602         </select>
       
 26603       </file>
       
 26604       <file name="protractor.js" type="protractor">
       
 26605         it('should select Greetings!', function() {
       
 26606           expect(element(by.id('greet')).getAttribute('selected')).toBeFalsy();
       
 26607           element(by.model('selected')).click();
       
 26608           expect(element(by.id('greet')).getAttribute('selected')).toBeTruthy();
       
 26609         });
       
 26610       </file>
       
 26611     </example>
       
 26612  *
       
 26613  * @element OPTION
       
 26614  * @param {expression} ngSelected If the {@link guide/expression expression} is truthy,
       
 26615  *     then special attribute "selected" will be set on the element
       
 26616  */
       
 26617 
       
 26618 /**
       
 26619  * @ngdoc directive
       
 26620  * @name ngOpen
       
 26621  * @restrict A
       
 26622  * @priority 100
       
 26623  *
       
 26624  * @description
       
 26625  * The HTML specification does not require browsers to preserve the values of boolean attributes
       
 26626  * such as open. (Their presence means true and their absence means false.)
       
 26627  * If we put an Angular interpolation expression into such an attribute then the
       
 26628  * binding information would be lost when the browser removes the attribute.
       
 26629  * The `ngOpen` directive solves this problem for the `open` attribute.
       
 26630  * This complementary directive is not removed by the browser and so provides
       
 26631  * a permanent reliable place to store the binding information.
       
 26632  * @example
       
 26633      <example>
       
 26634        <file name="index.html">
       
 26635          Check me check multiple: <input type="checkbox" ng-model="open"><br/>
       
 26636          <details id="details" ng-open="open">
       
 26637             <summary>Show/Hide me</summary>
       
 26638          </details>
       
 26639        </file>
       
 26640        <file name="protractor.js" type="protractor">
       
 26641          it('should toggle open', function() {
       
 26642            expect(element(by.id('details')).getAttribute('open')).toBeFalsy();
       
 26643            element(by.model('open')).click();
       
 26644            expect(element(by.id('details')).getAttribute('open')).toBeTruthy();
       
 26645          });
       
 26646        </file>
       
 26647      </example>
       
 26648  *
       
 26649  * @element DETAILS
       
 26650  * @param {expression} ngOpen If the {@link guide/expression expression} is truthy,
       
 26651  *     then special attribute "open" will be set on the element
       
 26652  */
       
 26653 
       
 26654 var ngAttributeAliasDirectives = {};
       
 26655 
       
 26656 
       
 26657 // boolean attrs are evaluated
       
 26658 forEach(BOOLEAN_ATTR, function(propName, attrName) {
       
 26659   // binding to multiple is not supported
       
 26660   if (propName == "multiple") return;
       
 26661 
       
 26662   var normalized = directiveNormalize('ng-' + attrName);
       
 26663   ngAttributeAliasDirectives[normalized] = function() {
       
 26664     return {
       
 26665       restrict: 'A',
       
 26666       priority: 100,
       
 26667       link: function(scope, element, attr) {
       
 26668         scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
       
 26669           attr.$set(attrName, !!value);
       
 26670         });
       
 26671       }
       
 26672     };
       
 26673   };
       
 26674 });
       
 26675 
       
 26676 // aliased input attrs are evaluated
       
 26677 forEach(ALIASED_ATTR, function(htmlAttr, ngAttr) {
       
 26678   ngAttributeAliasDirectives[ngAttr] = function() {
       
 26679     return {
       
 26680       priority: 100,
       
 26681       link: function(scope, element, attr) {
       
 26682         //special case ngPattern when a literal regular expression value
       
 26683         //is used as the expression (this way we don't have to watch anything).
       
 26684         if (ngAttr === "ngPattern" && attr.ngPattern.charAt(0) == "/") {
       
 26685           var match = attr.ngPattern.match(REGEX_STRING_REGEXP);
       
 26686           if (match) {
       
 26687             attr.$set("ngPattern", new RegExp(match[1], match[2]));
       
 26688             return;
       
 26689           }
       
 26690         }
       
 26691 
       
 26692         scope.$watch(attr[ngAttr], function ngAttrAliasWatchAction(value) {
       
 26693           attr.$set(ngAttr, value);
       
 26694         });
       
 26695       }
       
 26696     };
       
 26697   };
       
 26698 });
       
 26699 
       
 26700 // ng-src, ng-srcset, ng-href are interpolated
       
 26701 forEach(['src', 'srcset', 'href'], function(attrName) {
       
 26702   var normalized = directiveNormalize('ng-' + attrName);
       
 26703   ngAttributeAliasDirectives[normalized] = function() {
       
 26704     return {
       
 26705       priority: 99, // it needs to run after the attributes are interpolated
       
 26706       link: function(scope, element, attr) {
       
 26707         var propName = attrName,
       
 26708             name = attrName;
       
 26709 
       
 26710         if (attrName === 'href' &&
       
 26711             toString.call(element.prop('href')) === '[object SVGAnimatedString]') {
       
 26712           name = 'xlinkHref';
       
 26713           attr.$attr[name] = 'xlink:href';
       
 26714           propName = null;
       
 26715         }
       
 26716 
       
 26717         attr.$observe(normalized, function(value) {
       
 26718           if (!value) {
       
 26719             if (attrName === 'href') {
       
 26720               attr.$set(name, null);
       
 26721             }
       
 26722             return;
       
 26723           }
       
 26724 
       
 26725           attr.$set(name, value);
       
 26726 
       
 26727           // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
       
 26728           // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
       
 26729           // to set the property as well to achieve the desired effect.
       
 26730           // we use attr[attrName] value since $set can sanitize the url.
       
 26731           if (msie && propName) element.prop(propName, attr[name]);
       
 26732         });
       
 26733       }
       
 26734     };
       
 26735   };
       
 26736 });
       
 26737 
       
 26738 /* global -nullFormCtrl, -SUBMITTED_CLASS, addSetValidityMethod: true
       
 26739  */
       
 26740 var nullFormCtrl = {
       
 26741   $addControl: noop,
       
 26742   $$renameControl: nullFormRenameControl,
       
 26743   $removeControl: noop,
       
 26744   $setValidity: noop,
       
 26745   $setDirty: noop,
       
 26746   $setPristine: noop,
       
 26747   $setSubmitted: noop
       
 26748 },
       
 26749 SUBMITTED_CLASS = 'ng-submitted';
       
 26750 
       
 26751 function nullFormRenameControl(control, name) {
       
 26752   control.$name = name;
       
 26753 }
       
 26754 
       
 26755 /**
       
 26756  * @ngdoc type
       
 26757  * @name form.FormController
       
 26758  *
       
 26759  * @property {boolean} $pristine True if user has not interacted with the form yet.
       
 26760  * @property {boolean} $dirty True if user has already interacted with the form.
       
 26761  * @property {boolean} $valid True if all of the containing forms and controls are valid.
       
 26762  * @property {boolean} $invalid True if at least one containing control or form is invalid.
       
 26763  * @property {boolean} $submitted True if user has submitted the form even if its invalid.
       
 26764  *
       
 26765  * @property {Object} $error Is an object hash, containing references to controls or
       
 26766  *  forms with failing validators, where:
       
 26767  *
       
 26768  *  - keys are validation tokens (error names),
       
 26769  *  - values are arrays of controls or forms that have a failing validator for given error name.
       
 26770  *
       
 26771  *  Built-in validation tokens:
       
 26772  *
       
 26773  *  - `email`
       
 26774  *  - `max`
       
 26775  *  - `maxlength`
       
 26776  *  - `min`
       
 26777  *  - `minlength`
       
 26778  *  - `number`
       
 26779  *  - `pattern`
       
 26780  *  - `required`
       
 26781  *  - `url`
       
 26782  *
       
 26783  * @description
       
 26784  * `FormController` keeps track of all its controls and nested forms as well as the state of them,
       
 26785  * such as being valid/invalid or dirty/pristine.
       
 26786  *
       
 26787  * Each {@link ng.directive:form form} directive creates an instance
       
 26788  * of `FormController`.
       
 26789  *
       
 26790  */
       
 26791 //asks for $scope to fool the BC controller module
       
 26792 FormController.$inject = ['$element', '$attrs', '$scope', '$animate', '$interpolate'];
       
 26793 function FormController(element, attrs, $scope, $animate, $interpolate) {
       
 26794   var form = this,
       
 26795       controls = [];
       
 26796 
       
 26797   var parentForm = form.$$parentForm = element.parent().controller('form') || nullFormCtrl;
       
 26798 
       
 26799   // init state
       
 26800   form.$error = {};
       
 26801   form.$$success = {};
       
 26802   form.$pending = undefined;
       
 26803   form.$name = $interpolate(attrs.name || attrs.ngForm || '')($scope);
       
 26804   form.$dirty = false;
       
 26805   form.$pristine = true;
       
 26806   form.$valid = true;
       
 26807   form.$invalid = false;
       
 26808   form.$submitted = false;
       
 26809 
       
 26810   parentForm.$addControl(form);
       
 26811 
       
 26812   /**
       
 26813    * @ngdoc method
       
 26814    * @name form.FormController#$rollbackViewValue
       
 26815    *
       
 26816    * @description
       
 26817    * Rollback all form controls pending updates to the `$modelValue`.
       
 26818    *
       
 26819    * Updates may be pending by a debounced event or because the input is waiting for a some future
       
 26820    * event defined in `ng-model-options`. This method is typically needed by the reset button of
       
 26821    * a form that uses `ng-model-options` to pend updates.
       
 26822    */
       
 26823   form.$rollbackViewValue = function() {
       
 26824     forEach(controls, function(control) {
       
 26825       control.$rollbackViewValue();
       
 26826     });
       
 26827   };
       
 26828 
       
 26829   /**
       
 26830    * @ngdoc method
       
 26831    * @name form.FormController#$commitViewValue
       
 26832    *
       
 26833    * @description
       
 26834    * Commit all form controls pending updates to the `$modelValue`.
       
 26835    *
       
 26836    * Updates may be pending by a debounced event or because the input is waiting for a some future
       
 26837    * event defined in `ng-model-options`. This method is rarely needed as `NgModelController`
       
 26838    * usually handles calling this in response to input events.
       
 26839    */
       
 26840   form.$commitViewValue = function() {
       
 26841     forEach(controls, function(control) {
       
 26842       control.$commitViewValue();
       
 26843     });
       
 26844   };
       
 26845 
       
 26846   /**
       
 26847    * @ngdoc method
       
 26848    * @name form.FormController#$addControl
       
 26849    *
       
 26850    * @description
       
 26851    * Register a control with the form.
       
 26852    *
       
 26853    * Input elements using ngModelController do this automatically when they are linked.
       
 26854    */
       
 26855   form.$addControl = function(control) {
       
 26856     // Breaking change - before, inputs whose name was "hasOwnProperty" were quietly ignored
       
 26857     // and not added to the scope.  Now we throw an error.
       
 26858     assertNotHasOwnProperty(control.$name, 'input');
       
 26859     controls.push(control);
       
 26860 
       
 26861     if (control.$name) {
       
 26862       form[control.$name] = control;
       
 26863     }
       
 26864   };
       
 26865 
       
 26866   // Private API: rename a form control
       
 26867   form.$$renameControl = function(control, newName) {
       
 26868     var oldName = control.$name;
       
 26869 
       
 26870     if (form[oldName] === control) {
       
 26871       delete form[oldName];
       
 26872     }
       
 26873     form[newName] = control;
       
 26874     control.$name = newName;
       
 26875   };
       
 26876 
       
 26877   /**
       
 26878    * @ngdoc method
       
 26879    * @name form.FormController#$removeControl
       
 26880    *
       
 26881    * @description
       
 26882    * Deregister a control from the form.
       
 26883    *
       
 26884    * Input elements using ngModelController do this automatically when they are destroyed.
       
 26885    */
       
 26886   form.$removeControl = function(control) {
       
 26887     if (control.$name && form[control.$name] === control) {
       
 26888       delete form[control.$name];
       
 26889     }
       
 26890     forEach(form.$pending, function(value, name) {
       
 26891       form.$setValidity(name, null, control);
       
 26892     });
       
 26893     forEach(form.$error, function(value, name) {
       
 26894       form.$setValidity(name, null, control);
       
 26895     });
       
 26896 
       
 26897     arrayRemove(controls, control);
       
 26898   };
       
 26899 
       
 26900 
       
 26901   /**
       
 26902    * @ngdoc method
       
 26903    * @name form.FormController#$setValidity
       
 26904    *
       
 26905    * @description
       
 26906    * Sets the validity of a form control.
       
 26907    *
       
 26908    * This method will also propagate to parent forms.
       
 26909    */
       
 26910   addSetValidityMethod({
       
 26911     ctrl: this,
       
 26912     $element: element,
       
 26913     set: function(object, property, control) {
       
 26914       var list = object[property];
       
 26915       if (!list) {
       
 26916         object[property] = [control];
       
 26917       } else {
       
 26918         var index = list.indexOf(control);
       
 26919         if (index === -1) {
       
 26920           list.push(control);
       
 26921         }
       
 26922       }
       
 26923     },
       
 26924     unset: function(object, property, control) {
       
 26925       var list = object[property];
       
 26926       if (!list) {
       
 26927         return;
       
 26928       }
       
 26929       arrayRemove(list, control);
       
 26930       if (list.length === 0) {
       
 26931         delete object[property];
       
 26932       }
       
 26933     },
       
 26934     parentForm: parentForm,
       
 26935     $animate: $animate
       
 26936   });
       
 26937 
       
 26938   /**
       
 26939    * @ngdoc method
       
 26940    * @name form.FormController#$setDirty
       
 26941    *
       
 26942    * @description
       
 26943    * Sets the form to a dirty state.
       
 26944    *
       
 26945    * This method can be called to add the 'ng-dirty' class and set the form to a dirty
       
 26946    * state (ng-dirty class). This method will also propagate to parent forms.
       
 26947    */
       
 26948   form.$setDirty = function() {
       
 26949     $animate.removeClass(element, PRISTINE_CLASS);
       
 26950     $animate.addClass(element, DIRTY_CLASS);
       
 26951     form.$dirty = true;
       
 26952     form.$pristine = false;
       
 26953     parentForm.$setDirty();
       
 26954   };
       
 26955 
       
 26956   /**
       
 26957    * @ngdoc method
       
 26958    * @name form.FormController#$setPristine
       
 26959    *
       
 26960    * @description
       
 26961    * Sets the form to its pristine state.
       
 26962    *
       
 26963    * This method can be called to remove the 'ng-dirty' class and set the form to its pristine
       
 26964    * state (ng-pristine class). This method will also propagate to all the controls contained
       
 26965    * in this form.
       
 26966    *
       
 26967    * Setting a form back to a pristine state is often useful when we want to 'reuse' a form after
       
 26968    * saving or resetting it.
       
 26969    */
       
 26970   form.$setPristine = function () {
       
 26971     $animate.setClass(element, PRISTINE_CLASS, DIRTY_CLASS + ' ' + SUBMITTED_CLASS);
       
 26972     form.$dirty = false;
       
 26973     form.$pristine = true;
       
 26974     form.$submitted = false;
       
 26975     forEach(controls, function(control) {
       
 26976       control.$setPristine();
       
 26977     });
       
 26978   };
       
 26979 
       
 26980   /**
       
 26981    * @ngdoc method
       
 26982    * @name form.FormController#$setUntouched
       
 26983    *
       
 26984    * @description
       
 26985    * Sets the form to its untouched state.
       
 26986    *
       
 26987    * This method can be called to remove the 'ng-touched' class and set the form controls to their
       
 26988    * untouched state (ng-untouched class).
       
 26989    *
       
 26990    * Setting a form controls back to their untouched state is often useful when setting the form
       
 26991    * back to its pristine state.
       
 26992    */
       
 26993   form.$setUntouched = function () {
       
 26994     forEach(controls, function(control) {
       
 26995       control.$setUntouched();
       
 26996     });
       
 26997   };
       
 26998 
       
 26999   /**
       
 27000    * @ngdoc method
       
 27001    * @name form.FormController#$setSubmitted
       
 27002    *
       
 27003    * @description
       
 27004    * Sets the form to its submitted state.
       
 27005    */
       
 27006   form.$setSubmitted = function () {
       
 27007     $animate.addClass(element, SUBMITTED_CLASS);
       
 27008     form.$submitted = true;
       
 27009     parentForm.$setSubmitted();
       
 27010   };
       
 27011 }
       
 27012 
       
 27013 /**
       
 27014  * @ngdoc directive
       
 27015  * @name ngForm
       
 27016  * @restrict EAC
       
 27017  *
       
 27018  * @description
       
 27019  * Nestable alias of {@link ng.directive:form `form`} directive. HTML
       
 27020  * does not allow nesting of form elements. It is useful to nest forms, for example if the validity of a
       
 27021  * sub-group of controls needs to be determined.
       
 27022  *
       
 27023  * Note: the purpose of `ngForm` is to group controls,
       
 27024  * but not to be a replacement for the `<form>` tag with all of its capabilities
       
 27025  * (e.g. posting to the server, ...).
       
 27026  *
       
 27027  * @param {string=} ngForm|name Name of the form. If specified, the form controller will be published into
       
 27028  *                       related scope, under this name.
       
 27029  *
       
 27030  */
       
 27031 
       
 27032  /**
       
 27033  * @ngdoc directive
       
 27034  * @name form
       
 27035  * @restrict E
       
 27036  *
       
 27037  * @description
       
 27038  * Directive that instantiates
       
 27039  * {@link form.FormController FormController}.
       
 27040  *
       
 27041  * If the `name` attribute is specified, the form controller is published onto the current scope under
       
 27042  * this name.
       
 27043  *
       
 27044  * # Alias: {@link ng.directive:ngForm `ngForm`}
       
 27045  *
       
 27046  * In Angular forms can be nested. This means that the outer form is valid when all of the child
       
 27047  * forms are valid as well. However, browsers do not allow nesting of `<form>` elements, so
       
 27048  * Angular provides the {@link ng.directive:ngForm `ngForm`} directive which behaves identically to
       
 27049  * `<form>` but can be nested.  This allows you to have nested forms, which is very useful when
       
 27050  * using Angular validation directives in forms that are dynamically generated using the
       
 27051  * {@link ng.directive:ngRepeat `ngRepeat`} directive. Since you cannot dynamically generate the `name`
       
 27052  * attribute of input elements using interpolation, you have to wrap each set of repeated inputs in an
       
 27053  * `ngForm` directive and nest these in an outer `form` element.
       
 27054  *
       
 27055  *
       
 27056  * # CSS classes
       
 27057  *  - `ng-valid` is set if the form is valid.
       
 27058  *  - `ng-invalid` is set if the form is invalid.
       
 27059  *  - `ng-pristine` is set if the form is pristine.
       
 27060  *  - `ng-dirty` is set if the form is dirty.
       
 27061  *  - `ng-submitted` is set if the form was submitted.
       
 27062  *
       
 27063  * Keep in mind that ngAnimate can detect each of these classes when added and removed.
       
 27064  *
       
 27065  *
       
 27066  * # Submitting a form and preventing the default action
       
 27067  *
       
 27068  * Since the role of forms in client-side Angular applications is different than in classical
       
 27069  * roundtrip apps, it is desirable for the browser not to translate the form submission into a full
       
 27070  * page reload that sends the data to the server. Instead some javascript logic should be triggered
       
 27071  * to handle the form submission in an application-specific way.
       
 27072  *
       
 27073  * For this reason, Angular prevents the default action (form submission to the server) unless the
       
 27074  * `<form>` element has an `action` attribute specified.
       
 27075  *
       
 27076  * You can use one of the following two ways to specify what javascript method should be called when
       
 27077  * a form is submitted:
       
 27078  *
       
 27079  * - {@link ng.directive:ngSubmit ngSubmit} directive on the form element
       
 27080  * - {@link ng.directive:ngClick ngClick} directive on the first
       
 27081   *  button or input field of type submit (input[type=submit])
       
 27082  *
       
 27083  * To prevent double execution of the handler, use only one of the {@link ng.directive:ngSubmit ngSubmit}
       
 27084  * or {@link ng.directive:ngClick ngClick} directives.
       
 27085  * This is because of the following form submission rules in the HTML specification:
       
 27086  *
       
 27087  * - If a form has only one input field then hitting enter in this field triggers form submit
       
 27088  * (`ngSubmit`)
       
 27089  * - if a form has 2+ input fields and no buttons or input[type=submit] then hitting enter
       
 27090  * doesn't trigger submit
       
 27091  * - if a form has one or more input fields and one or more buttons or input[type=submit] then
       
 27092  * hitting enter in any of the input fields will trigger the click handler on the *first* button or
       
 27093  * input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`)
       
 27094  *
       
 27095  * Any pending `ngModelOptions` changes will take place immediately when an enclosing form is
       
 27096  * submitted. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit`
       
 27097  * to have access to the updated model.
       
 27098  *
       
 27099  * ## Animation Hooks
       
 27100  *
       
 27101  * Animations in ngForm are triggered when any of the associated CSS classes are added and removed.
       
 27102  * These classes are: `.ng-pristine`, `.ng-dirty`, `.ng-invalid` and `.ng-valid` as well as any
       
 27103  * other validations that are performed within the form. Animations in ngForm are similar to how
       
 27104  * they work in ngClass and animations can be hooked into using CSS transitions, keyframes as well
       
 27105  * as JS animations.
       
 27106  *
       
 27107  * The following example shows a simple way to utilize CSS transitions to style a form element
       
 27108  * that has been rendered as invalid after it has been validated:
       
 27109  *
       
 27110  * <pre>
       
 27111  * //be sure to include ngAnimate as a module to hook into more
       
 27112  * //advanced animations
       
 27113  * .my-form {
       
 27114  *   transition:0.5s linear all;
       
 27115  *   background: white;
       
 27116  * }
       
 27117  * .my-form.ng-invalid {
       
 27118  *   background: red;
       
 27119  *   color:white;
       
 27120  * }
       
 27121  * </pre>
       
 27122  *
       
 27123  * @example
       
 27124     <example deps="angular-animate.js" animations="true" fixBase="true" module="formExample">
       
 27125       <file name="index.html">
       
 27126        <script>
       
 27127          angular.module('formExample', [])
       
 27128            .controller('FormController', ['$scope', function($scope) {
       
 27129              $scope.userType = 'guest';
       
 27130            }]);
       
 27131        </script>
       
 27132        <style>
       
 27133         .my-form {
       
 27134           -webkit-transition:all linear 0.5s;
       
 27135           transition:all linear 0.5s;
       
 27136           background: transparent;
       
 27137         }
       
 27138         .my-form.ng-invalid {
       
 27139           background: red;
       
 27140         }
       
 27141        </style>
       
 27142        <form name="myForm" ng-controller="FormController" class="my-form">
       
 27143          userType: <input name="input" ng-model="userType" required>
       
 27144          <span class="error" ng-show="myForm.input.$error.required">Required!</span><br>
       
 27145          <tt>userType = {{userType}}</tt><br>
       
 27146          <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br>
       
 27147          <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br>
       
 27148          <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
       
 27149          <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
       
 27150         </form>
       
 27151       </file>
       
 27152       <file name="protractor.js" type="protractor">
       
 27153         it('should initialize to model', function() {
       
 27154           var userType = element(by.binding('userType'));
       
 27155           var valid = element(by.binding('myForm.input.$valid'));
       
 27156 
       
 27157           expect(userType.getText()).toContain('guest');
       
 27158           expect(valid.getText()).toContain('true');
       
 27159         });
       
 27160 
       
 27161         it('should be invalid if empty', function() {
       
 27162           var userType = element(by.binding('userType'));
       
 27163           var valid = element(by.binding('myForm.input.$valid'));
       
 27164           var userInput = element(by.model('userType'));
       
 27165 
       
 27166           userInput.clear();
       
 27167           userInput.sendKeys('');
       
 27168 
       
 27169           expect(userType.getText()).toEqual('userType =');
       
 27170           expect(valid.getText()).toContain('false');
       
 27171         });
       
 27172       </file>
       
 27173     </example>
       
 27174  *
       
 27175  * @param {string=} name Name of the form. If specified, the form controller will be published into
       
 27176  *                       related scope, under this name.
       
 27177  */
       
 27178 var formDirectiveFactory = function(isNgForm) {
       
 27179   return ['$timeout', function($timeout) {
       
 27180     var formDirective = {
       
 27181       name: 'form',
       
 27182       restrict: isNgForm ? 'EAC' : 'E',
       
 27183       controller: FormController,
       
 27184       compile: function ngFormCompile(formElement) {
       
 27185         // Setup initial state of the control
       
 27186         formElement.addClass(PRISTINE_CLASS).addClass(VALID_CLASS);
       
 27187 
       
 27188         return {
       
 27189           pre: function ngFormPreLink(scope, formElement, attr, controller) {
       
 27190             // if `action` attr is not present on the form, prevent the default action (submission)
       
 27191             if (!('action' in attr)) {
       
 27192               // we can't use jq events because if a form is destroyed during submission the default
       
 27193               // action is not prevented. see #1238
       
 27194               //
       
 27195               // IE 9 is not affected because it doesn't fire a submit event and try to do a full
       
 27196               // page reload if the form was destroyed by submission of the form via a click handler
       
 27197               // on a button in the form. Looks like an IE9 specific bug.
       
 27198               var handleFormSubmission = function(event) {
       
 27199                 scope.$apply(function() {
       
 27200                   controller.$commitViewValue();
       
 27201                   controller.$setSubmitted();
       
 27202                 });
       
 27203 
       
 27204                 event.preventDefault
       
 27205                   ? event.preventDefault()
       
 27206                   : event.returnValue = false; // IE
       
 27207               };
       
 27208 
       
 27209               addEventListenerFn(formElement[0], 'submit', handleFormSubmission);
       
 27210 
       
 27211               // unregister the preventDefault listener so that we don't not leak memory but in a
       
 27212               // way that will achieve the prevention of the default action.
       
 27213               formElement.on('$destroy', function() {
       
 27214                 $timeout(function() {
       
 27215                   removeEventListenerFn(formElement[0], 'submit', handleFormSubmission);
       
 27216                 }, 0, false);
       
 27217               });
       
 27218             }
       
 27219 
       
 27220             var parentFormCtrl = controller.$$parentForm,
       
 27221                 alias = controller.$name;
       
 27222 
       
 27223             if (alias) {
       
 27224               setter(scope, alias, controller, alias);
       
 27225               attr.$observe(attr.name ? 'name' : 'ngForm', function(newValue) {
       
 27226                 if (alias === newValue) return;
       
 27227                 setter(scope, alias, undefined, alias);
       
 27228                 alias = newValue;
       
 27229                 setter(scope, alias, controller, alias);
       
 27230                 parentFormCtrl.$$renameControl(controller, alias);
       
 27231               });
       
 27232             }
       
 27233             if (parentFormCtrl !== nullFormCtrl) {
       
 27234               formElement.on('$destroy', function() {
       
 27235                 parentFormCtrl.$removeControl(controller);
       
 27236                 if (alias) {
       
 27237                   setter(scope, alias, undefined, alias);
       
 27238                 }
       
 27239                 extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards
       
 27240               });
       
 27241             }
       
 27242           }
       
 27243         };
       
 27244       }
       
 27245     };
       
 27246 
       
 27247     return formDirective;
       
 27248   }];
       
 27249 };
       
 27250 
       
 27251 var formDirective = formDirectiveFactory();
       
 27252 var ngFormDirective = formDirectiveFactory(true);
       
 27253 
       
 27254 /* global VALID_CLASS: true,
       
 27255   INVALID_CLASS: true,
       
 27256   PRISTINE_CLASS: true,
       
 27257   DIRTY_CLASS: true,
       
 27258   UNTOUCHED_CLASS: true,
       
 27259   TOUCHED_CLASS: true,
       
 27260 */
       
 27261 
       
 27262 // Regex code is obtained from SO: https://stackoverflow.com/questions/3143070/javascript-regex-iso-datetime#answer-3143231
       
 27263 var ISO_DATE_REGEXP = /\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/;
       
 27264 var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/;
       
 27265 var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;
       
 27266 var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/;
       
 27267 var DATE_REGEXP = /^(\d{4})-(\d{2})-(\d{2})$/;
       
 27268 var DATETIMELOCAL_REGEXP = /^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
       
 27269 var WEEK_REGEXP = /^(\d{4})-W(\d\d)$/;
       
 27270 var MONTH_REGEXP = /^(\d{4})-(\d\d)$/;
       
 27271 var TIME_REGEXP = /^(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
       
 27272 var DEFAULT_REGEXP = /(\s+|^)default(\s+|$)/;
       
 27273 
       
 27274 var $ngModelMinErr = new minErr('ngModel');
       
 27275 
       
 27276 var inputType = {
       
 27277 
       
 27278   /**
       
 27279    * @ngdoc input
       
 27280    * @name input[text]
       
 27281    *
       
 27282    * @description
       
 27283    * Standard HTML text input with angular data binding, inherited by most of the `input` elements.
       
 27284    *
       
 27285    * *NOTE* Not every feature offered is available for all input types.
       
 27286    *
       
 27287    * @param {string} ngModel Assignable angular expression to data-bind to.
       
 27288    * @param {string=} name Property name of the form under which the control is published.
       
 27289    * @param {string=} required Adds `required` validation error key if the value is not entered.
       
 27290    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
       
 27291    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
       
 27292    *    `required` when you want to data-bind to the `required` attribute.
       
 27293    * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
       
 27294    *    minlength.
       
 27295    * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
       
 27296    *    maxlength.
       
 27297    * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
       
 27298    *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
       
 27299    *    patterns defined as scope expressions.
       
 27300    * @param {string=} ngChange Angular expression to be executed when input changes due to user
       
 27301    *    interaction with the input element.
       
 27302    * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
       
 27303    *    This parameter is ignored for input[type=password] controls, which will never trim the
       
 27304    *    input.
       
 27305    *
       
 27306    * @example
       
 27307       <example name="text-input-directive" module="textInputExample">
       
 27308         <file name="index.html">
       
 27309          <script>
       
 27310            angular.module('textInputExample', [])
       
 27311              .controller('ExampleController', ['$scope', function($scope) {
       
 27312                $scope.text = 'guest';
       
 27313                $scope.word = /^\s*\w*\s*$/;
       
 27314              }]);
       
 27315          </script>
       
 27316          <form name="myForm" ng-controller="ExampleController">
       
 27317            Single word: <input type="text" name="input" ng-model="text"
       
 27318                                ng-pattern="word" required ng-trim="false">
       
 27319            <span class="error" ng-show="myForm.input.$error.required">
       
 27320              Required!</span>
       
 27321            <span class="error" ng-show="myForm.input.$error.pattern">
       
 27322              Single word only!</span>
       
 27323 
       
 27324            <tt>text = {{text}}</tt><br/>
       
 27325            <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
       
 27326            <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
       
 27327            <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
       
 27328            <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
       
 27329           </form>
       
 27330         </file>
       
 27331         <file name="protractor.js" type="protractor">
       
 27332           var text = element(by.binding('text'));
       
 27333           var valid = element(by.binding('myForm.input.$valid'));
       
 27334           var input = element(by.model('text'));
       
 27335 
       
 27336           it('should initialize to model', function() {
       
 27337             expect(text.getText()).toContain('guest');
       
 27338             expect(valid.getText()).toContain('true');
       
 27339           });
       
 27340 
       
 27341           it('should be invalid if empty', function() {
       
 27342             input.clear();
       
 27343             input.sendKeys('');
       
 27344 
       
 27345             expect(text.getText()).toEqual('text =');
       
 27346             expect(valid.getText()).toContain('false');
       
 27347           });
       
 27348 
       
 27349           it('should be invalid if multi word', function() {
       
 27350             input.clear();
       
 27351             input.sendKeys('hello world');
       
 27352 
       
 27353             expect(valid.getText()).toContain('false');
       
 27354           });
       
 27355         </file>
       
 27356       </example>
       
 27357    */
       
 27358   'text': textInputType,
       
 27359 
       
 27360     /**
       
 27361      * @ngdoc input
       
 27362      * @name input[date]
       
 27363      *
       
 27364      * @description
       
 27365      * Input with date validation and transformation. In browsers that do not yet support
       
 27366      * the HTML5 date input, a text element will be used. In that case, text must be entered in a valid ISO-8601
       
 27367      * date format (yyyy-MM-dd), for example: `2009-01-06`. Since many
       
 27368      * modern browsers do not yet support this input type, it is important to provide cues to users on the
       
 27369      * expected input format via a placeholder or label. The model must always be a Date object.
       
 27370      *
       
 27371      * The timezone to be used to read/write the `Date` instance in the model can be defined using
       
 27372      * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
       
 27373      *
       
 27374      * @param {string} ngModel Assignable angular expression to data-bind to.
       
 27375      * @param {string=} name Property name of the form under which the control is published.
       
 27376      * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
       
 27377      * valid ISO date string (yyyy-MM-dd).
       
 27378      * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be
       
 27379      * a valid ISO date string (yyyy-MM-dd).
       
 27380      * @param {string=} required Sets `required` validation error key if the value is not entered.
       
 27381      * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
       
 27382      *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
       
 27383      *    `required` when you want to data-bind to the `required` attribute.
       
 27384      * @param {string=} ngChange Angular expression to be executed when input changes due to user
       
 27385      *    interaction with the input element.
       
 27386      *
       
 27387      * @example
       
 27388      <example name="date-input-directive" module="dateInputExample">
       
 27389      <file name="index.html">
       
 27390        <script>
       
 27391           angular.module('dateInputExample', [])
       
 27392             .controller('DateController', ['$scope', function($scope) {
       
 27393               $scope.value = new Date(2013, 9, 22);
       
 27394             }]);
       
 27395        </script>
       
 27396        <form name="myForm" ng-controller="DateController as dateCtrl">
       
 27397           Pick a date in 2013:
       
 27398           <input type="date" id="exampleInput" name="input" ng-model="value"
       
 27399               placeholder="yyyy-MM-dd" min="2013-01-01" max="2013-12-31" required />
       
 27400           <span class="error" ng-show="myForm.input.$error.required">
       
 27401               Required!</span>
       
 27402           <span class="error" ng-show="myForm.input.$error.date">
       
 27403               Not a valid date!</span>
       
 27404            <tt>value = {{value | date: "yyyy-MM-dd"}}</tt><br/>
       
 27405            <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
       
 27406            <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
       
 27407            <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
       
 27408            <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
       
 27409        </form>
       
 27410      </file>
       
 27411      <file name="protractor.js" type="protractor">
       
 27412         var value = element(by.binding('value | date: "yyyy-MM-dd"'));
       
 27413         var valid = element(by.binding('myForm.input.$valid'));
       
 27414         var input = element(by.model('value'));
       
 27415 
       
 27416         // currently protractor/webdriver does not support
       
 27417         // sending keys to all known HTML5 input controls
       
 27418         // for various browsers (see https://github.com/angular/protractor/issues/562).
       
 27419         function setInput(val) {
       
 27420           // set the value of the element and force validation.
       
 27421           var scr = "var ipt = document.getElementById('exampleInput'); " +
       
 27422           "ipt.value = '" + val + "';" +
       
 27423           "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
       
 27424           browser.executeScript(scr);
       
 27425         }
       
 27426 
       
 27427         it('should initialize to model', function() {
       
 27428           expect(value.getText()).toContain('2013-10-22');
       
 27429           expect(valid.getText()).toContain('myForm.input.$valid = true');
       
 27430         });
       
 27431 
       
 27432         it('should be invalid if empty', function() {
       
 27433           setInput('');
       
 27434           expect(value.getText()).toEqual('value =');
       
 27435           expect(valid.getText()).toContain('myForm.input.$valid = false');
       
 27436         });
       
 27437 
       
 27438         it('should be invalid if over max', function() {
       
 27439           setInput('2015-01-01');
       
 27440           expect(value.getText()).toContain('');
       
 27441           expect(valid.getText()).toContain('myForm.input.$valid = false');
       
 27442         });
       
 27443      </file>
       
 27444      </example>
       
 27445      */
       
 27446   'date': createDateInputType('date', DATE_REGEXP,
       
 27447          createDateParser(DATE_REGEXP, ['yyyy', 'MM', 'dd']),
       
 27448          'yyyy-MM-dd'),
       
 27449 
       
 27450    /**
       
 27451     * @ngdoc input
       
 27452     * @name input[dateTimeLocal]
       
 27453     *
       
 27454     * @description
       
 27455     * Input with datetime validation and transformation. In browsers that do not yet support
       
 27456     * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
       
 27457     * local datetime format (yyyy-MM-ddTHH:mm:ss), for example: `2010-12-28T14:57:00`. The model must be a Date object.
       
 27458     *
       
 27459     * The timezone to be used to read/write the `Date` instance in the model can be defined using
       
 27460     * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
       
 27461     *
       
 27462     * @param {string} ngModel Assignable angular expression to data-bind to.
       
 27463     * @param {string=} name Property name of the form under which the control is published.
       
 27464     * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
       
 27465     * valid ISO datetime format (yyyy-MM-ddTHH:mm:ss).
       
 27466     * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be
       
 27467     * a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss).
       
 27468     * @param {string=} required Sets `required` validation error key if the value is not entered.
       
 27469     * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
       
 27470     *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
       
 27471     *    `required` when you want to data-bind to the `required` attribute.
       
 27472     * @param {string=} ngChange Angular expression to be executed when input changes due to user
       
 27473     *    interaction with the input element.
       
 27474     *
       
 27475     * @example
       
 27476     <example name="datetimelocal-input-directive" module="dateExample">
       
 27477     <file name="index.html">
       
 27478       <script>
       
 27479         angular.module('dateExample', [])
       
 27480           .controller('DateController', ['$scope', function($scope) {
       
 27481             $scope.value = new Date(2010, 11, 28, 14, 57);
       
 27482           }]);
       
 27483       </script>
       
 27484       <form name="myForm" ng-controller="DateController as dateCtrl">
       
 27485         Pick a date between in 2013:
       
 27486         <input type="datetime-local" id="exampleInput" name="input" ng-model="value"
       
 27487             placeholder="yyyy-MM-ddTHH:mm:ss" min="2001-01-01T00:00:00" max="2013-12-31T00:00:00" required />
       
 27488         <span class="error" ng-show="myForm.input.$error.required">
       
 27489             Required!</span>
       
 27490         <span class="error" ng-show="myForm.input.$error.datetimelocal">
       
 27491             Not a valid date!</span>
       
 27492         <tt>value = {{value | date: "yyyy-MM-ddTHH:mm:ss"}}</tt><br/>
       
 27493         <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
       
 27494         <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
       
 27495         <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
       
 27496         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
       
 27497       </form>
       
 27498     </file>
       
 27499     <file name="protractor.js" type="protractor">
       
 27500       var value = element(by.binding('value | date: "yyyy-MM-ddTHH:mm:ss"'));
       
 27501       var valid = element(by.binding('myForm.input.$valid'));
       
 27502       var input = element(by.model('value'));
       
 27503 
       
 27504       // currently protractor/webdriver does not support
       
 27505       // sending keys to all known HTML5 input controls
       
 27506       // for various browsers (https://github.com/angular/protractor/issues/562).
       
 27507       function setInput(val) {
       
 27508         // set the value of the element and force validation.
       
 27509         var scr = "var ipt = document.getElementById('exampleInput'); " +
       
 27510         "ipt.value = '" + val + "';" +
       
 27511         "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
       
 27512         browser.executeScript(scr);
       
 27513       }
       
 27514 
       
 27515       it('should initialize to model', function() {
       
 27516         expect(value.getText()).toContain('2010-12-28T14:57:00');
       
 27517         expect(valid.getText()).toContain('myForm.input.$valid = true');
       
 27518       });
       
 27519 
       
 27520       it('should be invalid if empty', function() {
       
 27521         setInput('');
       
 27522         expect(value.getText()).toEqual('value =');
       
 27523         expect(valid.getText()).toContain('myForm.input.$valid = false');
       
 27524       });
       
 27525 
       
 27526       it('should be invalid if over max', function() {
       
 27527         setInput('2015-01-01T23:59:00');
       
 27528         expect(value.getText()).toContain('');
       
 27529         expect(valid.getText()).toContain('myForm.input.$valid = false');
       
 27530       });
       
 27531     </file>
       
 27532     </example>
       
 27533     */
       
 27534   'datetime-local': createDateInputType('datetimelocal', DATETIMELOCAL_REGEXP,
       
 27535       createDateParser(DATETIMELOCAL_REGEXP, ['yyyy', 'MM', 'dd', 'HH', 'mm', 'ss', 'sss']),
       
 27536       'yyyy-MM-ddTHH:mm:ss.sss'),
       
 27537 
       
 27538   /**
       
 27539    * @ngdoc input
       
 27540    * @name input[time]
       
 27541    *
       
 27542    * @description
       
 27543    * Input with time validation and transformation. In browsers that do not yet support
       
 27544    * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
       
 27545    * local time format (HH:mm:ss), for example: `14:57:00`. Model must be a Date object. This binding will always output a
       
 27546    * Date object to the model of January 1, 1970, or local date `new Date(1970, 0, 1, HH, mm, ss)`.
       
 27547    *
       
 27548    * The timezone to be used to read/write the `Date` instance in the model can be defined using
       
 27549    * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
       
 27550    *
       
 27551    * @param {string} ngModel Assignable angular expression to data-bind to.
       
 27552    * @param {string=} name Property name of the form under which the control is published.
       
 27553    * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
       
 27554    * valid ISO time format (HH:mm:ss).
       
 27555    * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be a
       
 27556    * valid ISO time format (HH:mm:ss).
       
 27557    * @param {string=} required Sets `required` validation error key if the value is not entered.
       
 27558    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
       
 27559    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
       
 27560    *    `required` when you want to data-bind to the `required` attribute.
       
 27561    * @param {string=} ngChange Angular expression to be executed when input changes due to user
       
 27562    *    interaction with the input element.
       
 27563    *
       
 27564    * @example
       
 27565    <example name="time-input-directive" module="timeExample">
       
 27566    <file name="index.html">
       
 27567      <script>
       
 27568       angular.module('timeExample', [])
       
 27569         .controller('DateController', ['$scope', function($scope) {
       
 27570           $scope.value = new Date(1970, 0, 1, 14, 57, 0);
       
 27571         }]);
       
 27572      </script>
       
 27573      <form name="myForm" ng-controller="DateController as dateCtrl">
       
 27574         Pick a between 8am and 5pm:
       
 27575         <input type="time" id="exampleInput" name="input" ng-model="value"
       
 27576             placeholder="HH:mm:ss" min="08:00:00" max="17:00:00" required />
       
 27577         <span class="error" ng-show="myForm.input.$error.required">
       
 27578             Required!</span>
       
 27579         <span class="error" ng-show="myForm.input.$error.time">
       
 27580             Not a valid date!</span>
       
 27581         <tt>value = {{value | date: "HH:mm:ss"}}</tt><br/>
       
 27582         <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
       
 27583         <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
       
 27584         <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
       
 27585         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
       
 27586      </form>
       
 27587    </file>
       
 27588    <file name="protractor.js" type="protractor">
       
 27589       var value = element(by.binding('value | date: "HH:mm:ss"'));
       
 27590       var valid = element(by.binding('myForm.input.$valid'));
       
 27591       var input = element(by.model('value'));
       
 27592 
       
 27593       // currently protractor/webdriver does not support
       
 27594       // sending keys to all known HTML5 input controls
       
 27595       // for various browsers (https://github.com/angular/protractor/issues/562).
       
 27596       function setInput(val) {
       
 27597         // set the value of the element and force validation.
       
 27598         var scr = "var ipt = document.getElementById('exampleInput'); " +
       
 27599         "ipt.value = '" + val + "';" +
       
 27600         "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
       
 27601         browser.executeScript(scr);
       
 27602       }
       
 27603 
       
 27604       it('should initialize to model', function() {
       
 27605         expect(value.getText()).toContain('14:57:00');
       
 27606         expect(valid.getText()).toContain('myForm.input.$valid = true');
       
 27607       });
       
 27608 
       
 27609       it('should be invalid if empty', function() {
       
 27610         setInput('');
       
 27611         expect(value.getText()).toEqual('value =');
       
 27612         expect(valid.getText()).toContain('myForm.input.$valid = false');
       
 27613       });
       
 27614 
       
 27615       it('should be invalid if over max', function() {
       
 27616         setInput('23:59:00');
       
 27617         expect(value.getText()).toContain('');
       
 27618         expect(valid.getText()).toContain('myForm.input.$valid = false');
       
 27619       });
       
 27620    </file>
       
 27621    </example>
       
 27622    */
       
 27623   'time': createDateInputType('time', TIME_REGEXP,
       
 27624       createDateParser(TIME_REGEXP, ['HH', 'mm', 'ss', 'sss']),
       
 27625      'HH:mm:ss.sss'),
       
 27626 
       
 27627    /**
       
 27628     * @ngdoc input
       
 27629     * @name input[week]
       
 27630     *
       
 27631     * @description
       
 27632     * Input with week-of-the-year validation and transformation to Date. In browsers that do not yet support
       
 27633     * the HTML5 week input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
       
 27634     * week format (yyyy-W##), for example: `2013-W02`. The model must always be a Date object.
       
 27635     *
       
 27636     * The timezone to be used to read/write the `Date` instance in the model can be defined using
       
 27637     * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
       
 27638     *
       
 27639     * @param {string} ngModel Assignable angular expression to data-bind to.
       
 27640     * @param {string=} name Property name of the form under which the control is published.
       
 27641     * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
       
 27642     * valid ISO week format (yyyy-W##).
       
 27643     * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be
       
 27644     * a valid ISO week format (yyyy-W##).
       
 27645     * @param {string=} required Sets `required` validation error key if the value is not entered.
       
 27646     * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
       
 27647     *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
       
 27648     *    `required` when you want to data-bind to the `required` attribute.
       
 27649     * @param {string=} ngChange Angular expression to be executed when input changes due to user
       
 27650     *    interaction with the input element.
       
 27651     *
       
 27652     * @example
       
 27653     <example name="week-input-directive" module="weekExample">
       
 27654     <file name="index.html">
       
 27655       <script>
       
 27656       angular.module('weekExample', [])
       
 27657         .controller('DateController', ['$scope', function($scope) {
       
 27658           $scope.value = new Date(2013, 0, 3);
       
 27659         }]);
       
 27660       </script>
       
 27661       <form name="myForm" ng-controller="DateController as dateCtrl">
       
 27662         Pick a date between in 2013:
       
 27663         <input id="exampleInput" type="week" name="input" ng-model="value"
       
 27664             placeholder="YYYY-W##" min="2012-W32" max="2013-W52" required />
       
 27665         <span class="error" ng-show="myForm.input.$error.required">
       
 27666             Required!</span>
       
 27667         <span class="error" ng-show="myForm.input.$error.week">
       
 27668             Not a valid date!</span>
       
 27669         <tt>value = {{value | date: "yyyy-Www"}}</tt><br/>
       
 27670         <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
       
 27671         <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
       
 27672         <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
       
 27673         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
       
 27674       </form>
       
 27675     </file>
       
 27676     <file name="protractor.js" type="protractor">
       
 27677       var value = element(by.binding('value | date: "yyyy-Www"'));
       
 27678       var valid = element(by.binding('myForm.input.$valid'));
       
 27679       var input = element(by.model('value'));
       
 27680 
       
 27681       // currently protractor/webdriver does not support
       
 27682       // sending keys to all known HTML5 input controls
       
 27683       // for various browsers (https://github.com/angular/protractor/issues/562).
       
 27684       function setInput(val) {
       
 27685         // set the value of the element and force validation.
       
 27686         var scr = "var ipt = document.getElementById('exampleInput'); " +
       
 27687         "ipt.value = '" + val + "';" +
       
 27688         "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
       
 27689         browser.executeScript(scr);
       
 27690       }
       
 27691 
       
 27692       it('should initialize to model', function() {
       
 27693         expect(value.getText()).toContain('2013-W01');
       
 27694         expect(valid.getText()).toContain('myForm.input.$valid = true');
       
 27695       });
       
 27696 
       
 27697       it('should be invalid if empty', function() {
       
 27698         setInput('');
       
 27699         expect(value.getText()).toEqual('value =');
       
 27700         expect(valid.getText()).toContain('myForm.input.$valid = false');
       
 27701       });
       
 27702 
       
 27703       it('should be invalid if over max', function() {
       
 27704         setInput('2015-W01');
       
 27705         expect(value.getText()).toContain('');
       
 27706         expect(valid.getText()).toContain('myForm.input.$valid = false');
       
 27707       });
       
 27708     </file>
       
 27709     </example>
       
 27710     */
       
 27711   'week': createDateInputType('week', WEEK_REGEXP, weekParser, 'yyyy-Www'),
       
 27712 
       
 27713   /**
       
 27714    * @ngdoc input
       
 27715    * @name input[month]
       
 27716    *
       
 27717    * @description
       
 27718    * Input with month validation and transformation. In browsers that do not yet support
       
 27719    * the HTML5 month input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
       
 27720    * month format (yyyy-MM), for example: `2009-01`. The model must always be a Date object. In the event the model is
       
 27721    * not set to the first of the month, the first of that model's month is assumed.
       
 27722    *
       
 27723    * The timezone to be used to read/write the `Date` instance in the model can be defined using
       
 27724    * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
       
 27725    *
       
 27726    * @param {string} ngModel Assignable angular expression to data-bind to.
       
 27727    * @param {string=} name Property name of the form under which the control is published.
       
 27728    * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be
       
 27729    * a valid ISO month format (yyyy-MM).
       
 27730    * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must
       
 27731    * be a valid ISO month format (yyyy-MM).
       
 27732    * @param {string=} required Sets `required` validation error key if the value is not entered.
       
 27733    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
       
 27734    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
       
 27735    *    `required` when you want to data-bind to the `required` attribute.
       
 27736    * @param {string=} ngChange Angular expression to be executed when input changes due to user
       
 27737    *    interaction with the input element.
       
 27738    *
       
 27739    * @example
       
 27740    <example name="month-input-directive" module="monthExample">
       
 27741    <file name="index.html">
       
 27742      <script>
       
 27743       angular.module('monthExample', [])
       
 27744         .controller('DateController', ['$scope', function($scope) {
       
 27745           $scope.value = new Date(2013, 9, 1);
       
 27746         }]);
       
 27747      </script>
       
 27748      <form name="myForm" ng-controller="DateController as dateCtrl">
       
 27749        Pick a month int 2013:
       
 27750        <input id="exampleInput" type="month" name="input" ng-model="value"
       
 27751           placeholder="yyyy-MM" min="2013-01" max="2013-12" required />
       
 27752        <span class="error" ng-show="myForm.input.$error.required">
       
 27753           Required!</span>
       
 27754        <span class="error" ng-show="myForm.input.$error.month">
       
 27755           Not a valid month!</span>
       
 27756        <tt>value = {{value | date: "yyyy-MM"}}</tt><br/>
       
 27757        <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
       
 27758        <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
       
 27759        <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
       
 27760        <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
       
 27761      </form>
       
 27762    </file>
       
 27763    <file name="protractor.js" type="protractor">
       
 27764       var value = element(by.binding('value | date: "yyyy-MM"'));
       
 27765       var valid = element(by.binding('myForm.input.$valid'));
       
 27766       var input = element(by.model('value'));
       
 27767 
       
 27768       // currently protractor/webdriver does not support
       
 27769       // sending keys to all known HTML5 input controls
       
 27770       // for various browsers (https://github.com/angular/protractor/issues/562).
       
 27771       function setInput(val) {
       
 27772         // set the value of the element and force validation.
       
 27773         var scr = "var ipt = document.getElementById('exampleInput'); " +
       
 27774         "ipt.value = '" + val + "';" +
       
 27775         "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
       
 27776         browser.executeScript(scr);
       
 27777       }
       
 27778 
       
 27779       it('should initialize to model', function() {
       
 27780         expect(value.getText()).toContain('2013-10');
       
 27781         expect(valid.getText()).toContain('myForm.input.$valid = true');
       
 27782       });
       
 27783 
       
 27784       it('should be invalid if empty', function() {
       
 27785         setInput('');
       
 27786         expect(value.getText()).toEqual('value =');
       
 27787         expect(valid.getText()).toContain('myForm.input.$valid = false');
       
 27788       });
       
 27789 
       
 27790       it('should be invalid if over max', function() {
       
 27791         setInput('2015-01');
       
 27792         expect(value.getText()).toContain('');
       
 27793         expect(valid.getText()).toContain('myForm.input.$valid = false');
       
 27794       });
       
 27795    </file>
       
 27796    </example>
       
 27797    */
       
 27798   'month': createDateInputType('month', MONTH_REGEXP,
       
 27799      createDateParser(MONTH_REGEXP, ['yyyy', 'MM']),
       
 27800      'yyyy-MM'),
       
 27801 
       
 27802   /**
       
 27803    * @ngdoc input
       
 27804    * @name input[number]
       
 27805    *
       
 27806    * @description
       
 27807    * Text input with number validation and transformation. Sets the `number` validation
       
 27808    * error if not a valid number.
       
 27809    *
       
 27810    * @param {string} ngModel Assignable angular expression to data-bind to.
       
 27811    * @param {string=} name Property name of the form under which the control is published.
       
 27812    * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
       
 27813    * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
       
 27814    * @param {string=} required Sets `required` validation error key if the value is not entered.
       
 27815    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
       
 27816    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
       
 27817    *    `required` when you want to data-bind to the `required` attribute.
       
 27818    * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
       
 27819    *    minlength.
       
 27820    * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
       
 27821    *    maxlength.
       
 27822    * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
       
 27823    *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
       
 27824    *    patterns defined as scope expressions.
       
 27825    * @param {string=} ngChange Angular expression to be executed when input changes due to user
       
 27826    *    interaction with the input element.
       
 27827    *
       
 27828    * @example
       
 27829       <example name="number-input-directive" module="numberExample">
       
 27830         <file name="index.html">
       
 27831          <script>
       
 27832            angular.module('numberExample', [])
       
 27833              .controller('ExampleController', ['$scope', function($scope) {
       
 27834                $scope.value = 12;
       
 27835              }]);
       
 27836          </script>
       
 27837          <form name="myForm" ng-controller="ExampleController">
       
 27838            Number: <input type="number" name="input" ng-model="value"
       
 27839                           min="0" max="99" required>
       
 27840            <span class="error" ng-show="myForm.input.$error.required">
       
 27841              Required!</span>
       
 27842            <span class="error" ng-show="myForm.input.$error.number">
       
 27843              Not valid number!</span>
       
 27844            <tt>value = {{value}}</tt><br/>
       
 27845            <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
       
 27846            <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
       
 27847            <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
       
 27848            <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
       
 27849           </form>
       
 27850         </file>
       
 27851         <file name="protractor.js" type="protractor">
       
 27852           var value = element(by.binding('value'));
       
 27853           var valid = element(by.binding('myForm.input.$valid'));
       
 27854           var input = element(by.model('value'));
       
 27855 
       
 27856           it('should initialize to model', function() {
       
 27857             expect(value.getText()).toContain('12');
       
 27858             expect(valid.getText()).toContain('true');
       
 27859           });
       
 27860 
       
 27861           it('should be invalid if empty', function() {
       
 27862             input.clear();
       
 27863             input.sendKeys('');
       
 27864             expect(value.getText()).toEqual('value =');
       
 27865             expect(valid.getText()).toContain('false');
       
 27866           });
       
 27867 
       
 27868           it('should be invalid if over max', function() {
       
 27869             input.clear();
       
 27870             input.sendKeys('123');
       
 27871             expect(value.getText()).toEqual('value =');
       
 27872             expect(valid.getText()).toContain('false');
       
 27873           });
       
 27874         </file>
       
 27875       </example>
       
 27876    */
       
 27877   'number': numberInputType,
       
 27878 
       
 27879 
       
 27880   /**
       
 27881    * @ngdoc input
       
 27882    * @name input[url]
       
 27883    *
       
 27884    * @description
       
 27885    * Text input with URL validation. Sets the `url` validation error key if the content is not a
       
 27886    * valid URL.
       
 27887    *
       
 27888    * @param {string} ngModel Assignable angular expression to data-bind to.
       
 27889    * @param {string=} name Property name of the form under which the control is published.
       
 27890    * @param {string=} required Sets `required` validation error key if the value is not entered.
       
 27891    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
       
 27892    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
       
 27893    *    `required` when you want to data-bind to the `required` attribute.
       
 27894    * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
       
 27895    *    minlength.
       
 27896    * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
       
 27897    *    maxlength.
       
 27898    * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
       
 27899    *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
       
 27900    *    patterns defined as scope expressions.
       
 27901    * @param {string=} ngChange Angular expression to be executed when input changes due to user
       
 27902    *    interaction with the input element.
       
 27903    *
       
 27904    * @example
       
 27905       <example name="url-input-directive" module="urlExample">
       
 27906         <file name="index.html">
       
 27907          <script>
       
 27908            angular.module('urlExample', [])
       
 27909              .controller('ExampleController', ['$scope', function($scope) {
       
 27910                $scope.text = 'http://google.com';
       
 27911              }]);
       
 27912          </script>
       
 27913          <form name="myForm" ng-controller="ExampleController">
       
 27914            URL: <input type="url" name="input" ng-model="text" required>
       
 27915            <span class="error" ng-show="myForm.input.$error.required">
       
 27916              Required!</span>
       
 27917            <span class="error" ng-show="myForm.input.$error.url">
       
 27918              Not valid url!</span>
       
 27919            <tt>text = {{text}}</tt><br/>
       
 27920            <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
       
 27921            <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
       
 27922            <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
       
 27923            <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
       
 27924            <tt>myForm.$error.url = {{!!myForm.$error.url}}</tt><br/>
       
 27925           </form>
       
 27926         </file>
       
 27927         <file name="protractor.js" type="protractor">
       
 27928           var text = element(by.binding('text'));
       
 27929           var valid = element(by.binding('myForm.input.$valid'));
       
 27930           var input = element(by.model('text'));
       
 27931 
       
 27932           it('should initialize to model', function() {
       
 27933             expect(text.getText()).toContain('http://google.com');
       
 27934             expect(valid.getText()).toContain('true');
       
 27935           });
       
 27936 
       
 27937           it('should be invalid if empty', function() {
       
 27938             input.clear();
       
 27939             input.sendKeys('');
       
 27940 
       
 27941             expect(text.getText()).toEqual('text =');
       
 27942             expect(valid.getText()).toContain('false');
       
 27943           });
       
 27944 
       
 27945           it('should be invalid if not url', function() {
       
 27946             input.clear();
       
 27947             input.sendKeys('box');
       
 27948 
       
 27949             expect(valid.getText()).toContain('false');
       
 27950           });
       
 27951         </file>
       
 27952       </example>
       
 27953    */
       
 27954   'url': urlInputType,
       
 27955 
       
 27956 
       
 27957   /**
       
 27958    * @ngdoc input
       
 27959    * @name input[email]
       
 27960    *
       
 27961    * @description
       
 27962    * Text input with email validation. Sets the `email` validation error key if not a valid email
       
 27963    * address.
       
 27964    *
       
 27965    * @param {string} ngModel Assignable angular expression to data-bind to.
       
 27966    * @param {string=} name Property name of the form under which the control is published.
       
 27967    * @param {string=} required Sets `required` validation error key if the value is not entered.
       
 27968    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
       
 27969    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
       
 27970    *    `required` when you want to data-bind to the `required` attribute.
       
 27971    * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
       
 27972    *    minlength.
       
 27973    * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
       
 27974    *    maxlength.
       
 27975    * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
       
 27976    *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
       
 27977    *    patterns defined as scope expressions.
       
 27978    * @param {string=} ngChange Angular expression to be executed when input changes due to user
       
 27979    *    interaction with the input element.
       
 27980    *
       
 27981    * @example
       
 27982       <example name="email-input-directive" module="emailExample">
       
 27983         <file name="index.html">
       
 27984          <script>
       
 27985            angular.module('emailExample', [])
       
 27986              .controller('ExampleController', ['$scope', function($scope) {
       
 27987                $scope.text = 'me@example.com';
       
 27988              }]);
       
 27989          </script>
       
 27990            <form name="myForm" ng-controller="ExampleController">
       
 27991              Email: <input type="email" name="input" ng-model="text" required>
       
 27992              <span class="error" ng-show="myForm.input.$error.required">
       
 27993                Required!</span>
       
 27994              <span class="error" ng-show="myForm.input.$error.email">
       
 27995                Not valid email!</span>
       
 27996              <tt>text = {{text}}</tt><br/>
       
 27997              <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
       
 27998              <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
       
 27999              <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
       
 28000              <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
       
 28001              <tt>myForm.$error.email = {{!!myForm.$error.email}}</tt><br/>
       
 28002            </form>
       
 28003          </file>
       
 28004         <file name="protractor.js" type="protractor">
       
 28005           var text = element(by.binding('text'));
       
 28006           var valid = element(by.binding('myForm.input.$valid'));
       
 28007           var input = element(by.model('text'));
       
 28008 
       
 28009           it('should initialize to model', function() {
       
 28010             expect(text.getText()).toContain('me@example.com');
       
 28011             expect(valid.getText()).toContain('true');
       
 28012           });
       
 28013 
       
 28014           it('should be invalid if empty', function() {
       
 28015             input.clear();
       
 28016             input.sendKeys('');
       
 28017             expect(text.getText()).toEqual('text =');
       
 28018             expect(valid.getText()).toContain('false');
       
 28019           });
       
 28020 
       
 28021           it('should be invalid if not email', function() {
       
 28022             input.clear();
       
 28023             input.sendKeys('xxx');
       
 28024 
       
 28025             expect(valid.getText()).toContain('false');
       
 28026           });
       
 28027         </file>
       
 28028       </example>
       
 28029    */
       
 28030   'email': emailInputType,
       
 28031 
       
 28032 
       
 28033   /**
       
 28034    * @ngdoc input
       
 28035    * @name input[radio]
       
 28036    *
       
 28037    * @description
       
 28038    * HTML radio button.
       
 28039    *
       
 28040    * @param {string} ngModel Assignable angular expression to data-bind to.
       
 28041    * @param {string} value The value to which the expression should be set when selected.
       
 28042    * @param {string=} name Property name of the form under which the control is published.
       
 28043    * @param {string=} ngChange Angular expression to be executed when input changes due to user
       
 28044    *    interaction with the input element.
       
 28045    * @param {string} ngValue Angular expression which sets the value to which the expression should
       
 28046    *    be set when selected.
       
 28047    *
       
 28048    * @example
       
 28049       <example name="radio-input-directive" module="radioExample">
       
 28050         <file name="index.html">
       
 28051          <script>
       
 28052            angular.module('radioExample', [])
       
 28053              .controller('ExampleController', ['$scope', function($scope) {
       
 28054                $scope.color = 'blue';
       
 28055                $scope.specialValue = {
       
 28056                  "id": "12345",
       
 28057                  "value": "green"
       
 28058                };
       
 28059              }]);
       
 28060          </script>
       
 28061          <form name="myForm" ng-controller="ExampleController">
       
 28062            <input type="radio" ng-model="color" value="red">  Red <br/>
       
 28063            <input type="radio" ng-model="color" ng-value="specialValue"> Green <br/>
       
 28064            <input type="radio" ng-model="color" value="blue"> Blue <br/>
       
 28065            <tt>color = {{color | json}}</tt><br/>
       
 28066           </form>
       
 28067           Note that `ng-value="specialValue"` sets radio item's value to be the value of `$scope.specialValue`.
       
 28068         </file>
       
 28069         <file name="protractor.js" type="protractor">
       
 28070           it('should change state', function() {
       
 28071             var color = element(by.binding('color'));
       
 28072 
       
 28073             expect(color.getText()).toContain('blue');
       
 28074 
       
 28075             element.all(by.model('color')).get(0).click();
       
 28076 
       
 28077             expect(color.getText()).toContain('red');
       
 28078           });
       
 28079         </file>
       
 28080       </example>
       
 28081    */
       
 28082   'radio': radioInputType,
       
 28083 
       
 28084 
       
 28085   /**
       
 28086    * @ngdoc input
       
 28087    * @name input[checkbox]
       
 28088    *
       
 28089    * @description
       
 28090    * HTML checkbox.
       
 28091    *
       
 28092    * @param {string} ngModel Assignable angular expression to data-bind to.
       
 28093    * @param {string=} name Property name of the form under which the control is published.
       
 28094    * @param {expression=} ngTrueValue The value to which the expression should be set when selected.
       
 28095    * @param {expression=} ngFalseValue The value to which the expression should be set when not selected.
       
 28096    * @param {string=} ngChange Angular expression to be executed when input changes due to user
       
 28097    *    interaction with the input element.
       
 28098    *
       
 28099    * @example
       
 28100       <example name="checkbox-input-directive" module="checkboxExample">
       
 28101         <file name="index.html">
       
 28102          <script>
       
 28103            angular.module('checkboxExample', [])
       
 28104              .controller('ExampleController', ['$scope', function($scope) {
       
 28105                $scope.value1 = true;
       
 28106                $scope.value2 = 'YES'
       
 28107              }]);
       
 28108          </script>
       
 28109          <form name="myForm" ng-controller="ExampleController">
       
 28110            Value1: <input type="checkbox" ng-model="value1"> <br/>
       
 28111            Value2: <input type="checkbox" ng-model="value2"
       
 28112                           ng-true-value="'YES'" ng-false-value="'NO'"> <br/>
       
 28113            <tt>value1 = {{value1}}</tt><br/>
       
 28114            <tt>value2 = {{value2}}</tt><br/>
       
 28115           </form>
       
 28116         </file>
       
 28117         <file name="protractor.js" type="protractor">
       
 28118           it('should change state', function() {
       
 28119             var value1 = element(by.binding('value1'));
       
 28120             var value2 = element(by.binding('value2'));
       
 28121 
       
 28122             expect(value1.getText()).toContain('true');
       
 28123             expect(value2.getText()).toContain('YES');
       
 28124 
       
 28125             element(by.model('value1')).click();
       
 28126             element(by.model('value2')).click();
       
 28127 
       
 28128             expect(value1.getText()).toContain('false');
       
 28129             expect(value2.getText()).toContain('NO');
       
 28130           });
       
 28131         </file>
       
 28132       </example>
       
 28133    */
       
 28134   'checkbox': checkboxInputType,
       
 28135 
       
 28136   'hidden': noop,
       
 28137   'button': noop,
       
 28138   'submit': noop,
       
 28139   'reset': noop,
       
 28140   'file': noop
       
 28141 };
       
 28142 
       
 28143 function testFlags(validity, flags) {
       
 28144   var i, flag;
       
 28145   if (flags) {
       
 28146     for (i=0; i<flags.length; ++i) {
       
 28147       flag = flags[i];
       
 28148       if (validity[flag]) {
       
 28149         return true;
       
 28150       }
       
 28151     }
       
 28152   }
       
 28153   return false;
       
 28154 }
       
 28155 
       
 28156 function stringBasedInputType(ctrl) {
       
 28157   ctrl.$formatters.push(function(value) {
       
 28158     return ctrl.$isEmpty(value) ? value : value.toString();
       
 28159   });
       
 28160 }
       
 28161 
       
 28162 function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
       
 28163   baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
       
 28164   stringBasedInputType(ctrl);
       
 28165 }
       
 28166 
       
 28167 function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) {
       
 28168   var validity = element.prop(VALIDITY_STATE_PROPERTY);
       
 28169   var placeholder = element[0].placeholder, noevent = {};
       
 28170   var type = lowercase(element[0].type);
       
 28171 
       
 28172   // In composition mode, users are still inputing intermediate text buffer,
       
 28173   // hold the listener until composition is done.
       
 28174   // More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent
       
 28175   if (!$sniffer.android) {
       
 28176     var composing = false;
       
 28177 
       
 28178     element.on('compositionstart', function(data) {
       
 28179       composing = true;
       
 28180     });
       
 28181 
       
 28182     element.on('compositionend', function() {
       
 28183       composing = false;
       
 28184       listener();
       
 28185     });
       
 28186   }
       
 28187 
       
 28188   var listener = function(ev) {
       
 28189     if (composing) return;
       
 28190     var value = element.val(),
       
 28191         event = ev && ev.type;
       
 28192 
       
 28193     // IE (11 and under) seem to emit an 'input' event if the placeholder value changes.
       
 28194     // We don't want to dirty the value when this happens, so we abort here. Unfortunately,
       
 28195     // IE also sends input events for other non-input-related things, (such as focusing on a
       
 28196     // form control), so this change is not entirely enough to solve this.
       
 28197     if (msie && (ev || noevent).type === 'input' && element[0].placeholder !== placeholder) {
       
 28198       placeholder = element[0].placeholder;
       
 28199       return;
       
 28200     }
       
 28201 
       
 28202     // By default we will trim the value
       
 28203     // If the attribute ng-trim exists we will avoid trimming
       
 28204     // If input type is 'password', the value is never trimmed
       
 28205     if (type !== 'password' && (!attr.ngTrim || attr.ngTrim !== 'false')) {
       
 28206       value = trim(value);
       
 28207     }
       
 28208 
       
 28209     // If a control is suffering from bad input (due to native validators), browsers discard its
       
 28210     // value, so it may be necessary to revalidate (by calling $setViewValue again) even if the
       
 28211     // control's value is the same empty value twice in a row.
       
 28212     if (ctrl.$viewValue !== value || (value === '' && ctrl.$$hasNativeValidators)) {
       
 28213       ctrl.$setViewValue(value, event);
       
 28214     }
       
 28215   };
       
 28216 
       
 28217   // if the browser does support "input" event, we are fine - except on IE9 which doesn't fire the
       
 28218   // input event on backspace, delete or cut
       
 28219   if ($sniffer.hasEvent('input')) {
       
 28220     element.on('input', listener);
       
 28221   } else {
       
 28222     var timeout;
       
 28223 
       
 28224     var deferListener = function(ev) {
       
 28225       if (!timeout) {
       
 28226         timeout = $browser.defer(function() {
       
 28227           listener(ev);
       
 28228           timeout = null;
       
 28229         });
       
 28230       }
       
 28231     };
       
 28232 
       
 28233     element.on('keydown', function(event) {
       
 28234       var key = event.keyCode;
       
 28235 
       
 28236       // ignore
       
 28237       //    command            modifiers                   arrows
       
 28238       if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return;
       
 28239 
       
 28240       deferListener(event);
       
 28241     });
       
 28242 
       
 28243     // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it
       
 28244     if ($sniffer.hasEvent('paste')) {
       
 28245       element.on('paste cut', deferListener);
       
 28246     }
       
 28247   }
       
 28248 
       
 28249   // if user paste into input using mouse on older browser
       
 28250   // or form autocomplete on newer browser, we need "change" event to catch it
       
 28251   element.on('change', listener);
       
 28252 
       
 28253   ctrl.$render = function() {
       
 28254     element.val(ctrl.$isEmpty(ctrl.$modelValue) ? '' : ctrl.$viewValue);
       
 28255   };
       
 28256 }
       
 28257 
       
 28258 function weekParser(isoWeek, existingDate) {
       
 28259   if (isDate(isoWeek)) {
       
 28260     return isoWeek;
       
 28261   }
       
 28262 
       
 28263   if (isString(isoWeek)) {
       
 28264     WEEK_REGEXP.lastIndex = 0;
       
 28265     var parts = WEEK_REGEXP.exec(isoWeek);
       
 28266     if (parts) {
       
 28267       var year = +parts[1],
       
 28268           week = +parts[2],
       
 28269           hours = 0,
       
 28270           minutes = 0,
       
 28271           seconds = 0,
       
 28272           milliseconds = 0,
       
 28273           firstThurs = getFirstThursdayOfYear(year),
       
 28274           addDays = (week - 1) * 7;
       
 28275 
       
 28276       if (existingDate) {
       
 28277         hours = existingDate.getHours();
       
 28278         minutes = existingDate.getMinutes();
       
 28279         seconds = existingDate.getSeconds();
       
 28280         milliseconds = existingDate.getMilliseconds();
       
 28281       }
       
 28282 
       
 28283       return new Date(year, 0, firstThurs.getDate() + addDays, hours, minutes, seconds, milliseconds);
       
 28284     }
       
 28285   }
       
 28286 
       
 28287   return NaN;
       
 28288 }
       
 28289 
       
 28290 function createDateParser(regexp, mapping) {
       
 28291   return function(iso, date) {
       
 28292     var parts, map;
       
 28293 
       
 28294     if (isDate(iso)) {
       
 28295       return iso;
       
 28296     }
       
 28297 
       
 28298     if (isString(iso)) {
       
 28299       // When a date is JSON'ified to wraps itself inside of an extra
       
 28300       // set of double quotes. This makes the date parsing code unable
       
 28301       // to match the date string and parse it as a date.
       
 28302       if (iso.charAt(0) == '"' && iso.charAt(iso.length-1) == '"') {
       
 28303         iso = iso.substring(1, iso.length-1);
       
 28304       }
       
 28305       if (ISO_DATE_REGEXP.test(iso)) {
       
 28306         return new Date(iso);
       
 28307       }
       
 28308       regexp.lastIndex = 0;
       
 28309       parts = regexp.exec(iso);
       
 28310 
       
 28311       if (parts) {
       
 28312         parts.shift();
       
 28313         if (date) {
       
 28314           map = {
       
 28315             yyyy: date.getFullYear(),
       
 28316             MM: date.getMonth() + 1,
       
 28317             dd: date.getDate(),
       
 28318             HH: date.getHours(),
       
 28319             mm: date.getMinutes(),
       
 28320             ss: date.getSeconds(),
       
 28321             sss: date.getMilliseconds() / 1000
       
 28322           };
       
 28323         } else {
       
 28324           map = { yyyy: 1970, MM: 1, dd: 1, HH: 0, mm: 0, ss: 0, sss: 0 };
       
 28325         }
       
 28326 
       
 28327         forEach(parts, function(part, index) {
       
 28328           if (index < mapping.length) {
       
 28329             map[mapping[index]] = +part;
       
 28330           }
       
 28331         });
       
 28332         return new Date(map.yyyy, map.MM - 1, map.dd, map.HH, map.mm, map.ss || 0, map.sss * 1000 || 0);
       
 28333       }
       
 28334     }
       
 28335 
       
 28336     return NaN;
       
 28337   };
       
 28338 }
       
 28339 
       
 28340 function createDateInputType(type, regexp, parseDate, format) {
       
 28341   return function dynamicDateInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter) {
       
 28342     badInputChecker(scope, element, attr, ctrl);
       
 28343     baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
       
 28344     var timezone = ctrl && ctrl.$options && ctrl.$options.timezone;
       
 28345     var previousDate;
       
 28346 
       
 28347     ctrl.$$parserName = type;
       
 28348     ctrl.$parsers.push(function(value) {
       
 28349       if (ctrl.$isEmpty(value)) return null;
       
 28350       if (regexp.test(value)) {
       
 28351         // Note: We cannot read ctrl.$modelValue, as there might be a different
       
 28352         // parser/formatter in the processing chain so that the model
       
 28353         // contains some different data format!
       
 28354         var parsedDate = parseDate(value, previousDate);
       
 28355         if (timezone === 'UTC') {
       
 28356           parsedDate.setMinutes(parsedDate.getMinutes() - parsedDate.getTimezoneOffset());
       
 28357         }
       
 28358         return parsedDate;
       
 28359       }
       
 28360       return undefined;
       
 28361     });
       
 28362 
       
 28363     ctrl.$formatters.push(function(value) {
       
 28364       if (!ctrl.$isEmpty(value)) {
       
 28365         if (!isDate(value)) {
       
 28366           throw $ngModelMinErr('datefmt', 'Expected `{0}` to be a date', value);
       
 28367         }
       
 28368         previousDate = value;
       
 28369         if (previousDate && timezone === 'UTC') {
       
 28370           var timezoneOffset = 60000 * previousDate.getTimezoneOffset();
       
 28371           previousDate = new Date(previousDate.getTime() + timezoneOffset);
       
 28372         }
       
 28373         return $filter('date')(value, format, timezone);
       
 28374       } else {
       
 28375         previousDate = null;
       
 28376       }
       
 28377       return '';
       
 28378     });
       
 28379 
       
 28380     if (isDefined(attr.min) || attr.ngMin) {
       
 28381       var minVal;
       
 28382       ctrl.$validators.min = function(value) {
       
 28383         return ctrl.$isEmpty(value) || isUndefined(minVal) || parseDate(value) >= minVal;
       
 28384       };
       
 28385       attr.$observe('min', function(val) {
       
 28386         minVal = parseObservedDateValue(val);
       
 28387         ctrl.$validate();
       
 28388       });
       
 28389     }
       
 28390 
       
 28391     if (isDefined(attr.max) || attr.ngMax) {
       
 28392       var maxVal;
       
 28393       ctrl.$validators.max = function(value) {
       
 28394         return ctrl.$isEmpty(value) || isUndefined(maxVal) || parseDate(value) <= maxVal;
       
 28395       };
       
 28396       attr.$observe('max', function(val) {
       
 28397         maxVal = parseObservedDateValue(val);
       
 28398         ctrl.$validate();
       
 28399       });
       
 28400     }
       
 28401     // Override the standard $isEmpty to detect invalid dates as well
       
 28402     ctrl.$isEmpty = function(value) {
       
 28403       // Invalid Date: getTime() returns NaN
       
 28404       return !value || (value.getTime && value.getTime() !== value.getTime());
       
 28405     };
       
 28406 
       
 28407     function parseObservedDateValue(val) {
       
 28408       return isDefined(val) ? (isDate(val) ? val : parseDate(val)) : undefined;
       
 28409     }
       
 28410   };
       
 28411 }
       
 28412 
       
 28413 function badInputChecker(scope, element, attr, ctrl) {
       
 28414   var node = element[0];
       
 28415   var nativeValidation = ctrl.$$hasNativeValidators = isObject(node.validity);
       
 28416   if (nativeValidation) {
       
 28417     ctrl.$parsers.push(function(value) {
       
 28418       var validity = element.prop(VALIDITY_STATE_PROPERTY) || {};
       
 28419       // Detect bug in FF35 for input[email] (https://bugzilla.mozilla.org/show_bug.cgi?id=1064430):
       
 28420       // - also sets validity.badInput (should only be validity.typeMismatch).
       
 28421       // - see http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#e-mail-state-(type=email)
       
 28422       // - can ignore this case as we can still read out the erroneous email...
       
 28423       return validity.badInput && !validity.typeMismatch ? undefined : value;
       
 28424     });
       
 28425   }
       
 28426 }
       
 28427 
       
 28428 function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
       
 28429   badInputChecker(scope, element, attr, ctrl);
       
 28430   baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
       
 28431 
       
 28432   ctrl.$$parserName = 'number';
       
 28433   ctrl.$parsers.push(function(value) {
       
 28434     if (ctrl.$isEmpty(value))      return null;
       
 28435     if (NUMBER_REGEXP.test(value)) return parseFloat(value);
       
 28436     return undefined;
       
 28437   });
       
 28438 
       
 28439   ctrl.$formatters.push(function(value) {
       
 28440     if (!ctrl.$isEmpty(value)) {
       
 28441       if (!isNumber(value)) {
       
 28442         throw $ngModelMinErr('numfmt', 'Expected `{0}` to be a number', value);
       
 28443       }
       
 28444       value = value.toString();
       
 28445     }
       
 28446     return value;
       
 28447   });
       
 28448 
       
 28449   if (attr.min || attr.ngMin) {
       
 28450     var minVal;
       
 28451     ctrl.$validators.min = function(value) {
       
 28452       return ctrl.$isEmpty(value) || isUndefined(minVal) || value >= minVal;
       
 28453     };
       
 28454 
       
 28455     attr.$observe('min', function(val) {
       
 28456       if (isDefined(val) && !isNumber(val)) {
       
 28457         val = parseFloat(val, 10);
       
 28458       }
       
 28459       minVal = isNumber(val) && !isNaN(val) ? val : undefined;
       
 28460       // TODO(matsko): implement validateLater to reduce number of validations
       
 28461       ctrl.$validate();
       
 28462     });
       
 28463   }
       
 28464 
       
 28465   if (attr.max || attr.ngMax) {
       
 28466     var maxVal;
       
 28467     ctrl.$validators.max = function(value) {
       
 28468       return ctrl.$isEmpty(value) || isUndefined(maxVal) || value <= maxVal;
       
 28469     };
       
 28470 
       
 28471     attr.$observe('max', function(val) {
       
 28472       if (isDefined(val) && !isNumber(val)) {
       
 28473         val = parseFloat(val, 10);
       
 28474       }
       
 28475       maxVal = isNumber(val) && !isNaN(val) ? val : undefined;
       
 28476       // TODO(matsko): implement validateLater to reduce number of validations
       
 28477       ctrl.$validate();
       
 28478     });
       
 28479   }
       
 28480 }
       
 28481 
       
 28482 function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
       
 28483   // Note: no badInputChecker here by purpose as `url` is only a validation
       
 28484   // in browsers, i.e. we can always read out input.value even if it is not valid!
       
 28485   baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
       
 28486   stringBasedInputType(ctrl);
       
 28487 
       
 28488   ctrl.$$parserName = 'url';
       
 28489   ctrl.$validators.url = function(value) {
       
 28490     return ctrl.$isEmpty(value) || URL_REGEXP.test(value);
       
 28491   };
       
 28492 }
       
 28493 
       
 28494 function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
       
 28495   // Note: no badInputChecker here by purpose as `url` is only a validation
       
 28496   // in browsers, i.e. we can always read out input.value even if it is not valid!
       
 28497   baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
       
 28498   stringBasedInputType(ctrl);
       
 28499 
       
 28500   ctrl.$$parserName = 'email';
       
 28501   ctrl.$validators.email = function(value) {
       
 28502     return ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value);
       
 28503   };
       
 28504 }
       
 28505 
       
 28506 function radioInputType(scope, element, attr, ctrl) {
       
 28507   // make the name unique, if not defined
       
 28508   if (isUndefined(attr.name)) {
       
 28509     element.attr('name', nextUid());
       
 28510   }
       
 28511 
       
 28512   var listener = function(ev) {
       
 28513     if (element[0].checked) {
       
 28514       ctrl.$setViewValue(attr.value, ev && ev.type);
       
 28515     }
       
 28516   };
       
 28517 
       
 28518   element.on('click', listener);
       
 28519 
       
 28520   ctrl.$render = function() {
       
 28521     var value = attr.value;
       
 28522     element[0].checked = (value == ctrl.$viewValue);
       
 28523   };
       
 28524 
       
 28525   attr.$observe('value', ctrl.$render);
       
 28526 }
       
 28527 
       
 28528 function parseConstantExpr($parse, context, name, expression, fallback) {
       
 28529   var parseFn;
       
 28530   if (isDefined(expression)) {
       
 28531     parseFn = $parse(expression);
       
 28532     if (!parseFn.constant) {
       
 28533       throw minErr('ngModel')('constexpr', 'Expected constant expression for `{0}`, but saw ' +
       
 28534                                    '`{1}`.', name, expression);
       
 28535     }
       
 28536     return parseFn(context);
       
 28537   }
       
 28538   return fallback;
       
 28539 }
       
 28540 
       
 28541 function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter, $parse) {
       
 28542   var trueValue = parseConstantExpr($parse, scope, 'ngTrueValue', attr.ngTrueValue, true);
       
 28543   var falseValue = parseConstantExpr($parse, scope, 'ngFalseValue', attr.ngFalseValue, false);
       
 28544 
       
 28545   var listener = function(ev) {
       
 28546     ctrl.$setViewValue(element[0].checked, ev && ev.type);
       
 28547   };
       
 28548 
       
 28549   element.on('click', listener);
       
 28550 
       
 28551   ctrl.$render = function() {
       
 28552     element[0].checked = ctrl.$viewValue;
       
 28553   };
       
 28554 
       
 28555   // Override the standard `$isEmpty` because an empty checkbox is never equal to the trueValue
       
 28556   ctrl.$isEmpty = function(value) {
       
 28557     return value !== trueValue;
       
 28558   };
       
 28559 
       
 28560   ctrl.$formatters.push(function(value) {
       
 28561     return equals(value, trueValue);
       
 28562   });
       
 28563 
       
 28564   ctrl.$parsers.push(function(value) {
       
 28565     return value ? trueValue : falseValue;
       
 28566   });
       
 28567 }
       
 28568 
       
 28569 
       
 28570 /**
       
 28571  * @ngdoc directive
       
 28572  * @name textarea
       
 28573  * @restrict E
       
 28574  *
       
 28575  * @description
       
 28576  * HTML textarea element control with angular data-binding. The data-binding and validation
       
 28577  * properties of this element are exactly the same as those of the
       
 28578  * {@link ng.directive:input input element}.
       
 28579  *
       
 28580  * @param {string} ngModel Assignable angular expression to data-bind to.
       
 28581  * @param {string=} name Property name of the form under which the control is published.
       
 28582  * @param {string=} required Sets `required` validation error key if the value is not entered.
       
 28583  * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
       
 28584  *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
       
 28585  *    `required` when you want to data-bind to the `required` attribute.
       
 28586  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
       
 28587  *    minlength.
       
 28588  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
       
 28589  *    maxlength.
       
 28590  * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
       
 28591  *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
       
 28592  *    patterns defined as scope expressions.
       
 28593  * @param {string=} ngChange Angular expression to be executed when input changes due to user
       
 28594  *    interaction with the input element.
       
 28595  * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
       
 28596  */
       
 28597 
       
 28598 
       
 28599 /**
       
 28600  * @ngdoc directive
       
 28601  * @name input
       
 28602  * @restrict E
       
 28603  *
       
 28604  * @description
       
 28605  * HTML input element control with angular data-binding. Input control follows HTML5 input types
       
 28606  * and polyfills the HTML5 validation behavior for older browsers.
       
 28607  *
       
 28608  * *NOTE* Not every feature offered is available for all input types.
       
 28609  *
       
 28610  * @param {string} ngModel Assignable angular expression to data-bind to.
       
 28611  * @param {string=} name Property name of the form under which the control is published.
       
 28612  * @param {string=} required Sets `required` validation error key if the value is not entered.
       
 28613  * @param {boolean=} ngRequired Sets `required` attribute if set to true
       
 28614  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
       
 28615  *    minlength.
       
 28616  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
       
 28617  *    maxlength.
       
 28618  * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
       
 28619  *    RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
       
 28620  *    patterns defined as scope expressions.
       
 28621  * @param {string=} ngChange Angular expression to be executed when input changes due to user
       
 28622  *    interaction with the input element.
       
 28623  * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
       
 28624  *    This parameter is ignored for input[type=password] controls, which will never trim the
       
 28625  *    input.
       
 28626  *
       
 28627  * @example
       
 28628     <example name="input-directive" module="inputExample">
       
 28629       <file name="index.html">
       
 28630        <script>
       
 28631           angular.module('inputExample', [])
       
 28632             .controller('ExampleController', ['$scope', function($scope) {
       
 28633               $scope.user = {name: 'guest', last: 'visitor'};
       
 28634             }]);
       
 28635        </script>
       
 28636        <div ng-controller="ExampleController">
       
 28637          <form name="myForm">
       
 28638            User name: <input type="text" name="userName" ng-model="user.name" required>
       
 28639            <span class="error" ng-show="myForm.userName.$error.required">
       
 28640              Required!</span><br>
       
 28641            Last name: <input type="text" name="lastName" ng-model="user.last"
       
 28642              ng-minlength="3" ng-maxlength="10">
       
 28643            <span class="error" ng-show="myForm.lastName.$error.minlength">
       
 28644              Too short!</span>
       
 28645            <span class="error" ng-show="myForm.lastName.$error.maxlength">
       
 28646              Too long!</span><br>
       
 28647          </form>
       
 28648          <hr>
       
 28649          <tt>user = {{user}}</tt><br/>
       
 28650          <tt>myForm.userName.$valid = {{myForm.userName.$valid}}</tt><br>
       
 28651          <tt>myForm.userName.$error = {{myForm.userName.$error}}</tt><br>
       
 28652          <tt>myForm.lastName.$valid = {{myForm.lastName.$valid}}</tt><br>
       
 28653          <tt>myForm.lastName.$error = {{myForm.lastName.$error}}</tt><br>
       
 28654          <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
       
 28655          <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
       
 28656          <tt>myForm.$error.minlength = {{!!myForm.$error.minlength}}</tt><br>
       
 28657          <tt>myForm.$error.maxlength = {{!!myForm.$error.maxlength}}</tt><br>
       
 28658        </div>
       
 28659       </file>
       
 28660       <file name="protractor.js" type="protractor">
       
 28661         var user = element(by.exactBinding('user'));
       
 28662         var userNameValid = element(by.binding('myForm.userName.$valid'));
       
 28663         var lastNameValid = element(by.binding('myForm.lastName.$valid'));
       
 28664         var lastNameError = element(by.binding('myForm.lastName.$error'));
       
 28665         var formValid = element(by.binding('myForm.$valid'));
       
 28666         var userNameInput = element(by.model('user.name'));
       
 28667         var userLastInput = element(by.model('user.last'));
       
 28668 
       
 28669         it('should initialize to model', function() {
       
 28670           expect(user.getText()).toContain('{"name":"guest","last":"visitor"}');
       
 28671           expect(userNameValid.getText()).toContain('true');
       
 28672           expect(formValid.getText()).toContain('true');
       
 28673         });
       
 28674 
       
 28675         it('should be invalid if empty when required', function() {
       
 28676           userNameInput.clear();
       
 28677           userNameInput.sendKeys('');
       
 28678 
       
 28679           expect(user.getText()).toContain('{"last":"visitor"}');
       
 28680           expect(userNameValid.getText()).toContain('false');
       
 28681           expect(formValid.getText()).toContain('false');
       
 28682         });
       
 28683 
       
 28684         it('should be valid if empty when min length is set', function() {
       
 28685           userLastInput.clear();
       
 28686           userLastInput.sendKeys('');
       
 28687 
       
 28688           expect(user.getText()).toContain('{"name":"guest","last":""}');
       
 28689           expect(lastNameValid.getText()).toContain('true');
       
 28690           expect(formValid.getText()).toContain('true');
       
 28691         });
       
 28692 
       
 28693         it('should be invalid if less than required min length', function() {
       
 28694           userLastInput.clear();
       
 28695           userLastInput.sendKeys('xx');
       
 28696 
       
 28697           expect(user.getText()).toContain('{"name":"guest"}');
       
 28698           expect(lastNameValid.getText()).toContain('false');
       
 28699           expect(lastNameError.getText()).toContain('minlength');
       
 28700           expect(formValid.getText()).toContain('false');
       
 28701         });
       
 28702 
       
 28703         it('should be invalid if longer than max length', function() {
       
 28704           userLastInput.clear();
       
 28705           userLastInput.sendKeys('some ridiculously long name');
       
 28706 
       
 28707           expect(user.getText()).toContain('{"name":"guest"}');
       
 28708           expect(lastNameValid.getText()).toContain('false');
       
 28709           expect(lastNameError.getText()).toContain('maxlength');
       
 28710           expect(formValid.getText()).toContain('false');
       
 28711         });
       
 28712       </file>
       
 28713     </example>
       
 28714  */
       
 28715 var inputDirective = ['$browser', '$sniffer', '$filter', '$parse',
       
 28716     function($browser, $sniffer, $filter, $parse) {
       
 28717   return {
       
 28718     restrict: 'E',
       
 28719     require: ['?ngModel'],
       
 28720     link: {
       
 28721       pre: function(scope, element, attr, ctrls) {
       
 28722         if (ctrls[0]) {
       
 28723           (inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrls[0], $sniffer,
       
 28724                                                               $browser, $filter, $parse);
       
 28725         }
       
 28726       }
       
 28727     }
       
 28728   };
       
 28729 }];
       
 28730 
       
 28731 var VALID_CLASS = 'ng-valid',
       
 28732     INVALID_CLASS = 'ng-invalid',
       
 28733     PRISTINE_CLASS = 'ng-pristine',
       
 28734     DIRTY_CLASS = 'ng-dirty',
       
 28735     UNTOUCHED_CLASS = 'ng-untouched',
       
 28736     TOUCHED_CLASS = 'ng-touched',
       
 28737     PENDING_CLASS = 'ng-pending';
       
 28738 
       
 28739 /**
       
 28740  * @ngdoc type
       
 28741  * @name ngModel.NgModelController
       
 28742  *
       
 28743  * @property {string} $viewValue Actual string value in the view.
       
 28744  * @property {*} $modelValue The value in the model, that the control is bound to.
       
 28745  * @property {Array.<Function>} $parsers Array of functions to execute, as a pipeline, whenever
       
 28746        the control reads value from the DOM.  Each function is called, in turn, passing the value
       
 28747        through to the next. The last return value is used to populate the model.
       
 28748        Used to sanitize / convert the value as well as validation. For validation,
       
 28749        the parsers should update the validity state using
       
 28750        {@link ngModel.NgModelController#$setValidity $setValidity()},
       
 28751        and return `undefined` for invalid values.
       
 28752 
       
 28753  *
       
 28754  * @property {Array.<Function>} $formatters Array of functions to execute, as a pipeline, whenever
       
 28755        the model value changes. Each function is called, in turn, passing the value through to the
       
 28756        next. Used to format / convert values for display in the control and validation.
       
 28757  * ```js
       
 28758  * function formatter(value) {
       
 28759  *   if (value) {
       
 28760  *     return value.toUpperCase();
       
 28761  *   }
       
 28762  * }
       
 28763  * ngModel.$formatters.push(formatter);
       
 28764  * ```
       
 28765  *
       
 28766  * @property {Object.<string, function>} $validators A collection of validators that are applied
       
 28767  *      whenever the model value changes. The key value within the object refers to the name of the
       
 28768  *      validator while the function refers to the validation operation. The validation operation is
       
 28769  *      provided with the model value as an argument and must return a true or false value depending
       
 28770  *      on the response of that validation.
       
 28771  *
       
 28772  * ```js
       
 28773  * ngModel.$validators.validCharacters = function(modelValue, viewValue) {
       
 28774  *   var value = modelValue || viewValue;
       
 28775  *   return /[0-9]+/.test(value) &&
       
 28776  *          /[a-z]+/.test(value) &&
       
 28777  *          /[A-Z]+/.test(value) &&
       
 28778  *          /\W+/.test(value);
       
 28779  * };
       
 28780  * ```
       
 28781  *
       
 28782  * @property {Object.<string, function>} $asyncValidators A collection of validations that are expected to
       
 28783  *      perform an asynchronous validation (e.g. a HTTP request). The validation function that is provided
       
 28784  *      is expected to return a promise when it is run during the model validation process. Once the promise
       
 28785  *      is delivered then the validation status will be set to true when fulfilled and false when rejected.
       
 28786  *      When the asynchronous validators are triggered, each of the validators will run in parallel and the model
       
 28787  *      value will only be updated once all validators have been fulfilled. Also, keep in mind that all
       
 28788  *      asynchronous validators will only run once all synchronous validators have passed.
       
 28789  *
       
 28790  * Please note that if $http is used then it is important that the server returns a success HTTP response code
       
 28791  * in order to fulfill the validation and a status level of `4xx` in order to reject the validation.
       
 28792  *
       
 28793  * ```js
       
 28794  * ngModel.$asyncValidators.uniqueUsername = function(modelValue, viewValue) {
       
 28795  *   var value = modelValue || viewValue;
       
 28796  *
       
 28797  *   // Lookup user by username
       
 28798  *   return $http.get('/api/users/' + value).
       
 28799  *      then(function resolved() {
       
 28800  *        //username exists, this means validation fails
       
 28801  *        return $q.reject('exists');
       
 28802  *      }, function rejected() {
       
 28803  *        //username does not exist, therefore this validation passes
       
 28804  *        return true;
       
 28805  *      });
       
 28806  * };
       
 28807  * ```
       
 28808  *
       
 28809  * @param {string} name The name of the validator.
       
 28810  * @param {Function} validationFn The validation function that will be run.
       
 28811  *
       
 28812  * @property {Array.<Function>} $viewChangeListeners Array of functions to execute whenever the
       
 28813  *     view value has changed. It is called with no arguments, and its return value is ignored.
       
 28814  *     This can be used in place of additional $watches against the model value.
       
 28815  *
       
 28816  * @property {Object} $error An object hash with all failing validator ids as keys.
       
 28817  * @property {Object} $pending An object hash with all pending validator ids as keys.
       
 28818  *
       
 28819  * @property {boolean} $untouched True if control has not lost focus yet.
       
 28820  * @property {boolean} $touched True if control has lost focus.
       
 28821  * @property {boolean} $pristine True if user has not interacted with the control yet.
       
 28822  * @property {boolean} $dirty True if user has already interacted with the control.
       
 28823  * @property {boolean} $valid True if there is no error.
       
 28824  * @property {boolean} $invalid True if at least one error on the control.
       
 28825  *
       
 28826  * @description
       
 28827  *
       
 28828  * `NgModelController` provides API for the `ng-model` directive. The controller contains
       
 28829  * services for data-binding, validation, CSS updates, and value formatting and parsing. It
       
 28830  * purposefully does not contain any logic which deals with DOM rendering or listening to
       
 28831  * DOM events. Such DOM related logic should be provided by other directives which make use of
       
 28832  * `NgModelController` for data-binding.
       
 28833  *
       
 28834  * ## Custom Control Example
       
 28835  * This example shows how to use `NgModelController` with a custom control to achieve
       
 28836  * data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`)
       
 28837  * collaborate together to achieve the desired result.
       
 28838  *
       
 28839  * Note that `contenteditable` is an HTML5 attribute, which tells the browser to let the element
       
 28840  * contents be edited in place by the user.  This will not work on older browsers.
       
 28841  *
       
 28842  * We are using the {@link ng.service:$sce $sce} service here and include the {@link ngSanitize $sanitize}
       
 28843  * module to automatically remove "bad" content like inline event listener (e.g. `<span onclick="...">`).
       
 28844  * However, as we are using `$sce` the model can still decide to to provide unsafe content if it marks
       
 28845  * that content using the `$sce` service.
       
 28846  *
       
 28847  * <example name="NgModelController" module="customControl" deps="angular-sanitize.js">
       
 28848     <file name="style.css">
       
 28849       [contenteditable] {
       
 28850         border: 1px solid black;
       
 28851         background-color: white;
       
 28852         min-height: 20px;
       
 28853       }
       
 28854 
       
 28855       .ng-invalid {
       
 28856         border: 1px solid red;
       
 28857       }
       
 28858 
       
 28859     </file>
       
 28860     <file name="script.js">
       
 28861       angular.module('customControl', ['ngSanitize']).
       
 28862         directive('contenteditable', ['$sce', function($sce) {
       
 28863           return {
       
 28864             restrict: 'A', // only activate on element attribute
       
 28865             require: '?ngModel', // get a hold of NgModelController
       
 28866             link: function(scope, element, attrs, ngModel) {
       
 28867               if (!ngModel) return; // do nothing if no ng-model
       
 28868 
       
 28869               // Specify how UI should be updated
       
 28870               ngModel.$render = function() {
       
 28871                 element.html($sce.getTrustedHtml(ngModel.$viewValue || ''));
       
 28872               };
       
 28873 
       
 28874               // Listen for change events to enable binding
       
 28875               element.on('blur keyup change', function() {
       
 28876                 scope.$apply(read);
       
 28877               });
       
 28878               read(); // initialize
       
 28879 
       
 28880               // Write data to the model
       
 28881               function read() {
       
 28882                 var html = element.html();
       
 28883                 // When we clear the content editable the browser leaves a <br> behind
       
 28884                 // If strip-br attribute is provided then we strip this out
       
 28885                 if ( attrs.stripBr && html == '<br>' ) {
       
 28886                   html = '';
       
 28887                 }
       
 28888                 ngModel.$setViewValue(html);
       
 28889               }
       
 28890             }
       
 28891           };
       
 28892         }]);
       
 28893     </file>
       
 28894     <file name="index.html">
       
 28895       <form name="myForm">
       
 28896        <div contenteditable
       
 28897             name="myWidget" ng-model="userContent"
       
 28898             strip-br="true"
       
 28899             required>Change me!</div>
       
 28900         <span ng-show="myForm.myWidget.$error.required">Required!</span>
       
 28901        <hr>
       
 28902        <textarea ng-model="userContent"></textarea>
       
 28903       </form>
       
 28904     </file>
       
 28905     <file name="protractor.js" type="protractor">
       
 28906     it('should data-bind and become invalid', function() {
       
 28907       if (browser.params.browser == 'safari' || browser.params.browser == 'firefox') {
       
 28908         // SafariDriver can't handle contenteditable
       
 28909         // and Firefox driver can't clear contenteditables very well
       
 28910         return;
       
 28911       }
       
 28912       var contentEditable = element(by.css('[contenteditable]'));
       
 28913       var content = 'Change me!';
       
 28914 
       
 28915       expect(contentEditable.getText()).toEqual(content);
       
 28916 
       
 28917       contentEditable.clear();
       
 28918       contentEditable.sendKeys(protractor.Key.BACK_SPACE);
       
 28919       expect(contentEditable.getText()).toEqual('');
       
 28920       expect(contentEditable.getAttribute('class')).toMatch(/ng-invalid-required/);
       
 28921     });
       
 28922     </file>
       
 28923  * </example>
       
 28924  *
       
 28925  *
       
 28926  */
       
 28927 var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse', '$animate', '$timeout', '$rootScope', '$q', '$interpolate',
       
 28928     function($scope, $exceptionHandler, $attr, $element, $parse, $animate, $timeout, $rootScope, $q, $interpolate) {
       
 28929   this.$viewValue = Number.NaN;
       
 28930   this.$modelValue = Number.NaN;
       
 28931   this.$validators = {};
       
 28932   this.$asyncValidators = {};
       
 28933   this.$parsers = [];
       
 28934   this.$formatters = [];
       
 28935   this.$viewChangeListeners = [];
       
 28936   this.$untouched = true;
       
 28937   this.$touched = false;
       
 28938   this.$pristine = true;
       
 28939   this.$dirty = false;
       
 28940   this.$valid = true;
       
 28941   this.$invalid = false;
       
 28942   this.$error = {}; // keep invalid keys here
       
 28943   this.$$success = {}; // keep valid keys here
       
 28944   this.$pending = undefined; // keep pending keys here
       
 28945   this.$name = $interpolate($attr.name || '', false)($scope);
       
 28946 
       
 28947 
       
 28948   var parsedNgModel = $parse($attr.ngModel),
       
 28949       pendingDebounce = null,
       
 28950       ctrl = this;
       
 28951 
       
 28952   var ngModelGet = function ngModelGet() {
       
 28953     var modelValue = parsedNgModel($scope);
       
 28954     if (ctrl.$options && ctrl.$options.getterSetter && isFunction(modelValue)) {
       
 28955       modelValue = modelValue();
       
 28956     }
       
 28957     return modelValue;
       
 28958   };
       
 28959 
       
 28960   var ngModelSet = function ngModelSet(newValue) {
       
 28961     var getterSetter;
       
 28962     if (ctrl.$options && ctrl.$options.getterSetter &&
       
 28963         isFunction(getterSetter = parsedNgModel($scope))) {
       
 28964 
       
 28965       getterSetter(ctrl.$modelValue);
       
 28966     } else {
       
 28967       parsedNgModel.assign($scope, ctrl.$modelValue);
       
 28968     }
       
 28969   };
       
 28970 
       
 28971   this.$$setOptions = function(options) {
       
 28972     ctrl.$options = options;
       
 28973 
       
 28974     if (!parsedNgModel.assign && (!options || !options.getterSetter)) {
       
 28975       throw $ngModelMinErr('nonassign', "Expression '{0}' is non-assignable. Element: {1}",
       
 28976           $attr.ngModel, startingTag($element));
       
 28977     }
       
 28978   };
       
 28979 
       
 28980   /**
       
 28981    * @ngdoc method
       
 28982    * @name ngModel.NgModelController#$render
       
 28983    *
       
 28984    * @description
       
 28985    * Called when the view needs to be updated. It is expected that the user of the ng-model
       
 28986    * directive will implement this method.
       
 28987    *
       
 28988    * The `$render()` method is invoked in the following situations:
       
 28989    *
       
 28990    * * `$rollbackViewValue()` is called.  If we are rolling back the view value to the last
       
 28991    *   committed value then `$render()` is called to update the input control.
       
 28992    * * The value referenced by `ng-model` is changed programmatically and both the `$modelValue` and
       
 28993    *   the `$viewValue` are different to last time.
       
 28994    *
       
 28995    * Since `ng-model` does not do a deep watch, `$render()` is only invoked if the values of
       
 28996    * `$modelValue` and `$viewValue` are actually different to their previous value. If `$modelValue`
       
 28997    * or `$viewValue` are objects (rather than a string or number) then `$render()` will not be
       
 28998    * invoked if you only change a property on the objects.
       
 28999    */
       
 29000   this.$render = noop;
       
 29001 
       
 29002   /**
       
 29003    * @ngdoc method
       
 29004    * @name ngModel.NgModelController#$isEmpty
       
 29005    *
       
 29006    * @description
       
 29007    * This is called when we need to determine if the value of the input is empty.
       
 29008    *
       
 29009    * For instance, the required directive does this to work out if the input has data or not.
       
 29010    * The default `$isEmpty` function checks whether the value is `undefined`, `''`, `null` or `NaN`.
       
 29011    *
       
 29012    * You can override this for input directives whose concept of being empty is different to the
       
 29013    * default. The `checkboxInputType` directive does this because in its case a value of `false`
       
 29014    * implies empty.
       
 29015    *
       
 29016    * @param {*} value Model value to check.
       
 29017    * @returns {boolean} True if `value` is empty.
       
 29018    */
       
 29019   this.$isEmpty = function(value) {
       
 29020     return isUndefined(value) || value === '' || value === null || value !== value;
       
 29021   };
       
 29022 
       
 29023   var parentForm = $element.inheritedData('$formController') || nullFormCtrl,
       
 29024       currentValidationRunId = 0;
       
 29025 
       
 29026   /**
       
 29027    * @ngdoc method
       
 29028    * @name ngModel.NgModelController#$setValidity
       
 29029    *
       
 29030    * @description
       
 29031    * Change the validity state, and notifies the form.
       
 29032    *
       
 29033    * This method can be called within $parsers/$formatters. However, if possible, please use the
       
 29034    *        `ngModel.$validators` pipeline which is designed to call this method automatically.
       
 29035    *
       
 29036    * @param {string} validationErrorKey Name of the validator. the `validationErrorKey` will assign
       
 29037    *        to `$error[validationErrorKey]` and `$pending[validationErrorKey]`
       
 29038    *        so that it is available for data-binding.
       
 29039    *        The `validationErrorKey` should be in camelCase and will get converted into dash-case
       
 29040    *        for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error`
       
 29041    *        class and can be bound to as  `{{someForm.someControl.$error.myError}}` .
       
 29042    * @param {boolean} isValid Whether the current state is valid (true), invalid (false), pending (undefined),
       
 29043    *                          or skipped (null).
       
 29044    */
       
 29045   addSetValidityMethod({
       
 29046     ctrl: this,
       
 29047     $element: $element,
       
 29048     set: function(object, property) {
       
 29049       object[property] = true;
       
 29050     },
       
 29051     unset: function(object, property) {
       
 29052       delete object[property];
       
 29053     },
       
 29054     parentForm: parentForm,
       
 29055     $animate: $animate
       
 29056   });
       
 29057 
       
 29058   /**
       
 29059    * @ngdoc method
       
 29060    * @name ngModel.NgModelController#$setPristine
       
 29061    *
       
 29062    * @description
       
 29063    * Sets the control to its pristine state.
       
 29064    *
       
 29065    * This method can be called to remove the 'ng-dirty' class and set the control to its pristine
       
 29066    * state (ng-pristine class). A model is considered to be pristine when the model has not been changed
       
 29067    * from when first compiled within then form.
       
 29068    */
       
 29069   this.$setPristine = function () {
       
 29070     ctrl.$dirty = false;
       
 29071     ctrl.$pristine = true;
       
 29072     $animate.removeClass($element, DIRTY_CLASS);
       
 29073     $animate.addClass($element, PRISTINE_CLASS);
       
 29074   };
       
 29075 
       
 29076   /**
       
 29077    * @ngdoc method
       
 29078    * @name ngModel.NgModelController#$setUntouched
       
 29079    *
       
 29080    * @description
       
 29081    * Sets the control to its untouched state.
       
 29082    *
       
 29083    * This method can be called to remove the 'ng-touched' class and set the control to its
       
 29084    * untouched state (ng-untouched class). Upon compilation, a model is set as untouched
       
 29085    * by default, however this function can be used to restore that state if the model has
       
 29086    * already been touched by the user.
       
 29087    */
       
 29088   this.$setUntouched = function() {
       
 29089     ctrl.$touched = false;
       
 29090     ctrl.$untouched = true;
       
 29091     $animate.setClass($element, UNTOUCHED_CLASS, TOUCHED_CLASS);
       
 29092   };
       
 29093 
       
 29094   /**
       
 29095    * @ngdoc method
       
 29096    * @name ngModel.NgModelController#$setTouched
       
 29097    *
       
 29098    * @description
       
 29099    * Sets the control to its touched state.
       
 29100    *
       
 29101    * This method can be called to remove the 'ng-untouched' class and set the control to its
       
 29102    * touched state (ng-touched class). A model is considered to be touched when the user has
       
 29103    * first interacted (focussed) on the model input element and then shifted focus away (blurred)
       
 29104    * from the input element.
       
 29105    */
       
 29106   this.$setTouched = function() {
       
 29107     ctrl.$touched = true;
       
 29108     ctrl.$untouched = false;
       
 29109     $animate.setClass($element, TOUCHED_CLASS, UNTOUCHED_CLASS);
       
 29110   };
       
 29111 
       
 29112   /**
       
 29113    * @ngdoc method
       
 29114    * @name ngModel.NgModelController#$rollbackViewValue
       
 29115    *
       
 29116    * @description
       
 29117    * Cancel an update and reset the input element's value to prevent an update to the `$modelValue`,
       
 29118    * which may be caused by a pending debounced event or because the input is waiting for a some
       
 29119    * future event.
       
 29120    *
       
 29121    * If you have an input that uses `ng-model-options` to set up debounced events or events such
       
 29122    * as blur you can have a situation where there is a period when the `$viewValue`
       
 29123    * is out of synch with the ngModel's `$modelValue`.
       
 29124    *
       
 29125    * In this case, you can run into difficulties if you try to update the ngModel's `$modelValue`
       
 29126    * programmatically before these debounced/future events have resolved/occurred, because Angular's
       
 29127    * dirty checking mechanism is not able to tell whether the model has actually changed or not.
       
 29128    *
       
 29129    * The `$rollbackViewValue()` method should be called before programmatically changing the model of an
       
 29130    * input which may have such events pending. This is important in order to make sure that the
       
 29131    * input field will be updated with the new model value and any pending operations are cancelled.
       
 29132    *
       
 29133    * <example name="ng-model-cancel-update" module="cancel-update-example">
       
 29134    *   <file name="app.js">
       
 29135    *     angular.module('cancel-update-example', [])
       
 29136    *
       
 29137    *     .controller('CancelUpdateController', ['$scope', function($scope) {
       
 29138    *       $scope.resetWithCancel = function (e) {
       
 29139    *         if (e.keyCode == 27) {
       
 29140    *           $scope.myForm.myInput1.$rollbackViewValue();
       
 29141    *           $scope.myValue = '';
       
 29142    *         }
       
 29143    *       };
       
 29144    *       $scope.resetWithoutCancel = function (e) {
       
 29145    *         if (e.keyCode == 27) {
       
 29146    *           $scope.myValue = '';
       
 29147    *         }
       
 29148    *       };
       
 29149    *     }]);
       
 29150    *   </file>
       
 29151    *   <file name="index.html">
       
 29152    *     <div ng-controller="CancelUpdateController">
       
 29153    *       <p>Try typing something in each input.  See that the model only updates when you
       
 29154    *          blur off the input.
       
 29155    *        </p>
       
 29156    *        <p>Now see what happens if you start typing then press the Escape key</p>
       
 29157    *
       
 29158    *       <form name="myForm" ng-model-options="{ updateOn: 'blur' }">
       
 29159    *         <p>With $rollbackViewValue()</p>
       
 29160    *         <input name="myInput1" ng-model="myValue" ng-keydown="resetWithCancel($event)"><br/>
       
 29161    *         myValue: "{{ myValue }}"
       
 29162    *
       
 29163    *         <p>Without $rollbackViewValue()</p>
       
 29164    *         <input name="myInput2" ng-model="myValue" ng-keydown="resetWithoutCancel($event)"><br/>
       
 29165    *         myValue: "{{ myValue }}"
       
 29166    *       </form>
       
 29167    *     </div>
       
 29168    *   </file>
       
 29169    * </example>
       
 29170    */
       
 29171   this.$rollbackViewValue = function() {
       
 29172     $timeout.cancel(pendingDebounce);
       
 29173     ctrl.$viewValue = ctrl.$$lastCommittedViewValue;
       
 29174     ctrl.$render();
       
 29175   };
       
 29176 
       
 29177   /**
       
 29178    * @ngdoc method
       
 29179    * @name ngModel.NgModelController#$validate
       
 29180    *
       
 29181    * @description
       
 29182    * Runs each of the registered validators (first synchronous validators and then asynchronous validators).
       
 29183    */
       
 29184   this.$validate = function() {
       
 29185     // ignore $validate before model is initialized
       
 29186     if (isNumber(ctrl.$modelValue) && isNaN(ctrl.$modelValue)) {
       
 29187       return;
       
 29188     }
       
 29189     this.$$parseAndValidate();
       
 29190   };
       
 29191 
       
 29192   this.$$runValidators = function(parseValid, modelValue, viewValue, doneCallback) {
       
 29193     currentValidationRunId++;
       
 29194     var localValidationRunId = currentValidationRunId;
       
 29195 
       
 29196     // check parser error
       
 29197     if (!processParseErrors(parseValid)) {
       
 29198       validationDone(false);
       
 29199       return;
       
 29200     }
       
 29201     if (!processSyncValidators()) {
       
 29202       validationDone(false);
       
 29203       return;
       
 29204     }
       
 29205     processAsyncValidators();
       
 29206 
       
 29207     function processParseErrors(parseValid) {
       
 29208       var errorKey = ctrl.$$parserName || 'parse';
       
 29209       if (parseValid === undefined) {
       
 29210         setValidity(errorKey, null);
       
 29211       } else {
       
 29212         setValidity(errorKey, parseValid);
       
 29213         if (!parseValid) {
       
 29214           forEach(ctrl.$validators, function(v, name) {
       
 29215             setValidity(name, null);
       
 29216           });
       
 29217           forEach(ctrl.$asyncValidators, function(v, name) {
       
 29218             setValidity(name, null);
       
 29219           });
       
 29220           return false;
       
 29221         }
       
 29222       }
       
 29223       return true;
       
 29224     }
       
 29225 
       
 29226     function processSyncValidators() {
       
 29227       var syncValidatorsValid = true;
       
 29228       forEach(ctrl.$validators, function(validator, name) {
       
 29229         var result = validator(modelValue, viewValue);
       
 29230         syncValidatorsValid = syncValidatorsValid && result;
       
 29231         setValidity(name, result);
       
 29232       });
       
 29233       if (!syncValidatorsValid) {
       
 29234         forEach(ctrl.$asyncValidators, function(v, name) {
       
 29235           setValidity(name, null);
       
 29236         });
       
 29237         return false;
       
 29238       }
       
 29239       return true;
       
 29240     }
       
 29241 
       
 29242     function processAsyncValidators() {
       
 29243       var validatorPromises = [];
       
 29244       var allValid = true;
       
 29245       forEach(ctrl.$asyncValidators, function(validator, name) {
       
 29246         var promise = validator(modelValue, viewValue);
       
 29247         if (!isPromiseLike(promise)) {
       
 29248           throw $ngModelMinErr("$asyncValidators",
       
 29249             "Expected asynchronous validator to return a promise but got '{0}' instead.", promise);
       
 29250         }
       
 29251         setValidity(name, undefined);
       
 29252         validatorPromises.push(promise.then(function() {
       
 29253           setValidity(name, true);
       
 29254         }, function(error) {
       
 29255           allValid = false;
       
 29256           setValidity(name, false);
       
 29257         }));
       
 29258       });
       
 29259       if (!validatorPromises.length) {
       
 29260         validationDone(true);
       
 29261       } else {
       
 29262         $q.all(validatorPromises).then(function() {
       
 29263           validationDone(allValid);
       
 29264         }, noop);
       
 29265       }
       
 29266     }
       
 29267 
       
 29268     function setValidity(name, isValid) {
       
 29269       if (localValidationRunId === currentValidationRunId) {
       
 29270         ctrl.$setValidity(name, isValid);
       
 29271       }
       
 29272     }
       
 29273 
       
 29274     function validationDone(allValid) {
       
 29275       if (localValidationRunId === currentValidationRunId) {
       
 29276 
       
 29277         doneCallback(allValid);
       
 29278       }
       
 29279     }
       
 29280   };
       
 29281 
       
 29282   /**
       
 29283    * @ngdoc method
       
 29284    * @name ngModel.NgModelController#$commitViewValue
       
 29285    *
       
 29286    * @description
       
 29287    * Commit a pending update to the `$modelValue`.
       
 29288    *
       
 29289    * Updates may be pending by a debounced event or because the input is waiting for a some future
       
 29290    * event defined in `ng-model-options`. this method is rarely needed as `NgModelController`
       
 29291    * usually handles calling this in response to input events.
       
 29292    */
       
 29293   this.$commitViewValue = function() {
       
 29294     var viewValue = ctrl.$viewValue;
       
 29295 
       
 29296     $timeout.cancel(pendingDebounce);
       
 29297 
       
 29298     // If the view value has not changed then we should just exit, except in the case where there is
       
 29299     // a native validator on the element. In this case the validation state may have changed even though
       
 29300     // the viewValue has stayed empty.
       
 29301     if (ctrl.$$lastCommittedViewValue === viewValue && (viewValue !== '' || !ctrl.$$hasNativeValidators)) {
       
 29302       return;
       
 29303     }
       
 29304     ctrl.$$lastCommittedViewValue = viewValue;
       
 29305 
       
 29306     // change to dirty
       
 29307     if (ctrl.$pristine) {
       
 29308       ctrl.$dirty = true;
       
 29309       ctrl.$pristine = false;
       
 29310       $animate.removeClass($element, PRISTINE_CLASS);
       
 29311       $animate.addClass($element, DIRTY_CLASS);
       
 29312       parentForm.$setDirty();
       
 29313     }
       
 29314     this.$$parseAndValidate();
       
 29315   };
       
 29316 
       
 29317   this.$$parseAndValidate = function() {
       
 29318     var viewValue = ctrl.$$lastCommittedViewValue;
       
 29319     var modelValue = viewValue;
       
 29320     var parserValid = isUndefined(modelValue) ? undefined : true;
       
 29321 
       
 29322     if (parserValid) {
       
 29323       for(var i = 0; i < ctrl.$parsers.length; i++) {
       
 29324         modelValue = ctrl.$parsers[i](modelValue);
       
 29325         if (isUndefined(modelValue)) {
       
 29326           parserValid = false;
       
 29327           break;
       
 29328         }
       
 29329       }
       
 29330     }
       
 29331     if (isNumber(ctrl.$modelValue) && isNaN(ctrl.$modelValue)) {
       
 29332       // ctrl.$modelValue has not been touched yet...
       
 29333       ctrl.$modelValue = ngModelGet();
       
 29334     }
       
 29335     var prevModelValue = ctrl.$modelValue;
       
 29336     var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid;
       
 29337     if (allowInvalid) {
       
 29338       ctrl.$modelValue = modelValue;
       
 29339       writeToModelIfNeeded();
       
 29340     }
       
 29341     ctrl.$$runValidators(parserValid, modelValue, viewValue, function(allValid) {
       
 29342       if (!allowInvalid) {
       
 29343         // Note: Don't check ctrl.$valid here, as we could have
       
 29344         // external validators (e.g. calculated on the server),
       
 29345         // that just call $setValidity and need the model value
       
 29346         // to calculate their validity.
       
 29347         ctrl.$modelValue = allValid ? modelValue : undefined;
       
 29348         writeToModelIfNeeded();
       
 29349       }
       
 29350     });
       
 29351 
       
 29352     function writeToModelIfNeeded() {
       
 29353       if (ctrl.$modelValue !== prevModelValue) {
       
 29354         ctrl.$$writeModelToScope();
       
 29355       }
       
 29356     }
       
 29357   };
       
 29358 
       
 29359   this.$$writeModelToScope = function() {
       
 29360     ngModelSet(ctrl.$modelValue);
       
 29361     forEach(ctrl.$viewChangeListeners, function(listener) {
       
 29362       try {
       
 29363         listener();
       
 29364       } catch(e) {
       
 29365         $exceptionHandler(e);
       
 29366       }
       
 29367     });
       
 29368   };
       
 29369 
       
 29370   /**
       
 29371    * @ngdoc method
       
 29372    * @name ngModel.NgModelController#$setViewValue
       
 29373    *
       
 29374    * @description
       
 29375    * Update the view value.
       
 29376    *
       
 29377    * This method should be called when an input directive want to change the view value; typically,
       
 29378    * this is done from within a DOM event handler.
       
 29379    *
       
 29380    * For example {@link ng.directive:input input} calls it when the value of the input changes and
       
 29381    * {@link ng.directive:select select} calls it when an option is selected.
       
 29382    *
       
 29383    * If the new `value` is an object (rather than a string or a number), we should make a copy of the
       
 29384    * object before passing it to `$setViewValue`.  This is because `ngModel` does not perform a deep
       
 29385    * watch of objects, it only looks for a change of identity. If you only change the property of
       
 29386    * the object then ngModel will not realise that the object has changed and will not invoke the
       
 29387    * `$parsers` and `$validators` pipelines.
       
 29388    *
       
 29389    * For this reason, you should not change properties of the copy once it has been passed to
       
 29390    * `$setViewValue`. Otherwise you may cause the model value on the scope to change incorrectly.
       
 29391    *
       
 29392    * When this method is called, the new `value` will be staged for committing through the `$parsers`
       
 29393    * and `$validators` pipelines. If there are no special {@link ngModelOptions} specified then the staged
       
 29394    * value sent directly for processing, finally to be applied to `$modelValue` and then the
       
 29395    * **expression** specified in the `ng-model` attribute.
       
 29396    *
       
 29397    * Lastly, all the registered change listeners, in the `$viewChangeListeners` list, are called.
       
 29398    *
       
 29399    * In case the {@link ng.directive:ngModelOptions ngModelOptions} directive is used with `updateOn`
       
 29400    * and the `default` trigger is not listed, all those actions will remain pending until one of the
       
 29401    * `updateOn` events is triggered on the DOM element.
       
 29402    * All these actions will be debounced if the {@link ng.directive:ngModelOptions ngModelOptions}
       
 29403    * directive is used with a custom debounce for this particular event.
       
 29404    *
       
 29405    * Note that calling this function does not trigger a `$digest`.
       
 29406    *
       
 29407    * @param {string} value Value from the view.
       
 29408    * @param {string} trigger Event that triggered the update.
       
 29409    */
       
 29410   this.$setViewValue = function(value, trigger) {
       
 29411     ctrl.$viewValue = value;
       
 29412     if (!ctrl.$options || ctrl.$options.updateOnDefault) {
       
 29413       ctrl.$$debounceViewValueCommit(trigger);
       
 29414     }
       
 29415   };
       
 29416 
       
 29417   this.$$debounceViewValueCommit = function(trigger) {
       
 29418     var debounceDelay = 0,
       
 29419         options = ctrl.$options,
       
 29420         debounce;
       
 29421 
       
 29422     if (options && isDefined(options.debounce)) {
       
 29423       debounce = options.debounce;
       
 29424       if (isNumber(debounce)) {
       
 29425         debounceDelay = debounce;
       
 29426       } else if (isNumber(debounce[trigger])) {
       
 29427         debounceDelay = debounce[trigger];
       
 29428       } else if (isNumber(debounce['default'])) {
       
 29429         debounceDelay = debounce['default'];
       
 29430       }
       
 29431     }
       
 29432 
       
 29433     $timeout.cancel(pendingDebounce);
       
 29434     if (debounceDelay) {
       
 29435       pendingDebounce = $timeout(function() {
       
 29436         ctrl.$commitViewValue();
       
 29437       }, debounceDelay);
       
 29438     } else if ($rootScope.$$phase) {
       
 29439       ctrl.$commitViewValue();
       
 29440     } else {
       
 29441       $scope.$apply(function() {
       
 29442         ctrl.$commitViewValue();
       
 29443       });
       
 29444     }
       
 29445   };
       
 29446 
       
 29447   // model -> value
       
 29448   // Note: we cannot use a normal scope.$watch as we want to detect the following:
       
 29449   // 1. scope value is 'a'
       
 29450   // 2. user enters 'b'
       
 29451   // 3. ng-change kicks in and reverts scope value to 'a'
       
 29452   //    -> scope value did not change since the last digest as
       
 29453   //       ng-change executes in apply phase
       
 29454   // 4. view should be changed back to 'a'
       
 29455   $scope.$watch(function ngModelWatch() {
       
 29456     var modelValue = ngModelGet();
       
 29457 
       
 29458     // if scope model value and ngModel value are out of sync
       
 29459     // TODO(perf): why not move this to the action fn?
       
 29460     if (modelValue !== ctrl.$modelValue) {
       
 29461       ctrl.$modelValue = modelValue;
       
 29462 
       
 29463       var formatters = ctrl.$formatters,
       
 29464           idx = formatters.length;
       
 29465 
       
 29466       var viewValue = modelValue;
       
 29467       while(idx--) {
       
 29468         viewValue = formatters[idx](viewValue);
       
 29469       }
       
 29470       if (ctrl.$viewValue !== viewValue) {
       
 29471         ctrl.$viewValue = ctrl.$$lastCommittedViewValue = viewValue;
       
 29472         ctrl.$render();
       
 29473 
       
 29474         ctrl.$$runValidators(undefined, modelValue, viewValue, noop);
       
 29475       }
       
 29476     }
       
 29477 
       
 29478     return modelValue;
       
 29479   });
       
 29480 }];
       
 29481 
       
 29482 
       
 29483 /**
       
 29484  * @ngdoc directive
       
 29485  * @name ngModel
       
 29486  *
       
 29487  * @element input
       
 29488  *
       
 29489  * @description
       
 29490  * The `ngModel` directive binds an `input`,`select`, `textarea` (or custom form control) to a
       
 29491  * property on the scope using {@link ngModel.NgModelController NgModelController},
       
 29492  * which is created and exposed by this directive.
       
 29493  *
       
 29494  * `ngModel` is responsible for:
       
 29495  *
       
 29496  * - Binding the view into the model, which other directives such as `input`, `textarea` or `select`
       
 29497  *   require.
       
 29498  * - Providing validation behavior (i.e. required, number, email, url).
       
 29499  * - Keeping the state of the control (valid/invalid, dirty/pristine, touched/untouched, validation errors).
       
 29500  * - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`, `ng-touched`, `ng-untouched`) including animations.
       
 29501  * - Registering the control with its parent {@link ng.directive:form form}.
       
 29502  *
       
 29503  * Note: `ngModel` will try to bind to the property given by evaluating the expression on the
       
 29504  * current scope. If the property doesn't already exist on this scope, it will be created
       
 29505  * implicitly and added to the scope.
       
 29506  *
       
 29507  * For best practices on using `ngModel`, see:
       
 29508  *
       
 29509  *  - [https://github.com/angular/angular.js/wiki/Understanding-Scopes]
       
 29510  *
       
 29511  * For basic examples, how to use `ngModel`, see:
       
 29512  *
       
 29513  *  - {@link ng.directive:input input}
       
 29514  *    - {@link input[text] text}
       
 29515  *    - {@link input[checkbox] checkbox}
       
 29516  *    - {@link input[radio] radio}
       
 29517  *    - {@link input[number] number}
       
 29518  *    - {@link input[email] email}
       
 29519  *    - {@link input[url] url}
       
 29520  *    - {@link input[date] date}
       
 29521  *    - {@link input[dateTimeLocal] dateTimeLocal}
       
 29522  *    - {@link input[time] time}
       
 29523  *    - {@link input[month] month}
       
 29524  *    - {@link input[week] week}
       
 29525  *  - {@link ng.directive:select select}
       
 29526  *  - {@link ng.directive:textarea textarea}
       
 29527  *
       
 29528  * # CSS classes
       
 29529  * The following CSS classes are added and removed on the associated input/select/textarea element
       
 29530  * depending on the validity of the model.
       
 29531  *
       
 29532  *  - `ng-valid` is set if the model is valid.
       
 29533  *  - `ng-invalid` is set if the model is invalid.
       
 29534  *  - `ng-pristine` is set if the model is pristine.
       
 29535  *  - `ng-dirty` is set if the model is dirty.
       
 29536  *
       
 29537  * Keep in mind that ngAnimate can detect each of these classes when added and removed.
       
 29538  *
       
 29539  * ## Animation Hooks
       
 29540  *
       
 29541  * Animations within models are triggered when any of the associated CSS classes are added and removed
       
 29542  * on the input element which is attached to the model. These classes are: `.ng-pristine`, `.ng-dirty`,
       
 29543  * `.ng-invalid` and `.ng-valid` as well as any other validations that are performed on the model itself.
       
 29544  * The animations that are triggered within ngModel are similar to how they work in ngClass and
       
 29545  * animations can be hooked into using CSS transitions, keyframes as well as JS animations.
       
 29546  *
       
 29547  * The following example shows a simple way to utilize CSS transitions to style an input element
       
 29548  * that has been rendered as invalid after it has been validated:
       
 29549  *
       
 29550  * <pre>
       
 29551  * //be sure to include ngAnimate as a module to hook into more
       
 29552  * //advanced animations
       
 29553  * .my-input {
       
 29554  *   transition:0.5s linear all;
       
 29555  *   background: white;
       
 29556  * }
       
 29557  * .my-input.ng-invalid {
       
 29558  *   background: red;
       
 29559  *   color:white;
       
 29560  * }
       
 29561  * </pre>
       
 29562  *
       
 29563  * @example
       
 29564  * <example deps="angular-animate.js" animations="true" fixBase="true" module="inputExample">
       
 29565      <file name="index.html">
       
 29566        <script>
       
 29567         angular.module('inputExample', [])
       
 29568           .controller('ExampleController', ['$scope', function($scope) {
       
 29569             $scope.val = '1';
       
 29570           }]);
       
 29571        </script>
       
 29572        <style>
       
 29573          .my-input {
       
 29574            -webkit-transition:all linear 0.5s;
       
 29575            transition:all linear 0.5s;
       
 29576            background: transparent;
       
 29577          }
       
 29578          .my-input.ng-invalid {
       
 29579            color:white;
       
 29580            background: red;
       
 29581          }
       
 29582        </style>
       
 29583        Update input to see transitions when valid/invalid.
       
 29584        Integer is a valid value.
       
 29585        <form name="testForm" ng-controller="ExampleController">
       
 29586          <input ng-model="val" ng-pattern="/^\d+$/" name="anim" class="my-input" />
       
 29587        </form>
       
 29588      </file>
       
 29589  * </example>
       
 29590  *
       
 29591  * ## Binding to a getter/setter
       
 29592  *
       
 29593  * Sometimes it's helpful to bind `ngModel` to a getter/setter function.  A getter/setter is a
       
 29594  * function that returns a representation of the model when called with zero arguments, and sets
       
 29595  * the internal state of a model when called with an argument. It's sometimes useful to use this
       
 29596  * for models that have an internal representation that's different than what the model exposes
       
 29597  * to the view.
       
 29598  *
       
 29599  * <div class="alert alert-success">
       
 29600  * **Best Practice:** It's best to keep getters fast because Angular is likely to call them more
       
 29601  * frequently than other parts of your code.
       
 29602  * </div>
       
 29603  *
       
 29604  * You use this behavior by adding `ng-model-options="{ getterSetter: true }"` to an element that
       
 29605  * has `ng-model` attached to it. You can also add `ng-model-options="{ getterSetter: true }"` to
       
 29606  * a `<form>`, which will enable this behavior for all `<input>`s within it. See
       
 29607  * {@link ng.directive:ngModelOptions `ngModelOptions`} for more.
       
 29608  *
       
 29609  * The following example shows how to use `ngModel` with a getter/setter:
       
 29610  *
       
 29611  * @example
       
 29612  * <example name="ngModel-getter-setter" module="getterSetterExample">
       
 29613      <file name="index.html">
       
 29614        <div ng-controller="ExampleController">
       
 29615          <form name="userForm">
       
 29616            Name:
       
 29617            <input type="text" name="userName"
       
 29618                   ng-model="user.name"
       
 29619                   ng-model-options="{ getterSetter: true }" />
       
 29620          </form>
       
 29621          <pre>user.name = <span ng-bind="user.name()"></span></pre>
       
 29622        </div>
       
 29623      </file>
       
 29624      <file name="app.js">
       
 29625        angular.module('getterSetterExample', [])
       
 29626          .controller('ExampleController', ['$scope', function($scope) {
       
 29627            var _name = 'Brian';
       
 29628            $scope.user = {
       
 29629              name: function (newName) {
       
 29630                if (angular.isDefined(newName)) {
       
 29631                  _name = newName;
       
 29632                }
       
 29633                return _name;
       
 29634              }
       
 29635            };
       
 29636          }]);
       
 29637      </file>
       
 29638  * </example>
       
 29639  */
       
 29640 var ngModelDirective = function() {
       
 29641   return {
       
 29642     restrict: 'A',
       
 29643     require: ['ngModel', '^?form', '^?ngModelOptions'],
       
 29644     controller: NgModelController,
       
 29645     // Prelink needs to run before any input directive
       
 29646     // so that we can set the NgModelOptions in NgModelController
       
 29647     // before anyone else uses it.
       
 29648     priority: 1,
       
 29649     compile: function ngModelCompile(element) {
       
 29650       // Setup initial state of the control
       
 29651       element.addClass(PRISTINE_CLASS).addClass(UNTOUCHED_CLASS).addClass(VALID_CLASS);
       
 29652 
       
 29653       return {
       
 29654         pre: function ngModelPreLink(scope, element, attr, ctrls) {
       
 29655           var modelCtrl = ctrls[0],
       
 29656               formCtrl = ctrls[1] || nullFormCtrl;
       
 29657 
       
 29658           modelCtrl.$$setOptions(ctrls[2] && ctrls[2].$options);
       
 29659 
       
 29660           // notify others, especially parent forms
       
 29661           formCtrl.$addControl(modelCtrl);
       
 29662 
       
 29663           attr.$observe('name', function(newValue) {
       
 29664             if (modelCtrl.$name !== newValue) {
       
 29665               formCtrl.$$renameControl(modelCtrl, newValue);
       
 29666             }
       
 29667           });
       
 29668 
       
 29669           scope.$on('$destroy', function() {
       
 29670             formCtrl.$removeControl(modelCtrl);
       
 29671           });
       
 29672         },
       
 29673         post: function ngModelPostLink(scope, element, attr, ctrls) {
       
 29674           var modelCtrl = ctrls[0];
       
 29675           if (modelCtrl.$options && modelCtrl.$options.updateOn) {
       
 29676             element.on(modelCtrl.$options.updateOn, function(ev) {
       
 29677               modelCtrl.$$debounceViewValueCommit(ev && ev.type);
       
 29678             });
       
 29679           }
       
 29680 
       
 29681           element.on('blur', function(ev) {
       
 29682             if (modelCtrl.$touched) return;
       
 29683 
       
 29684             scope.$apply(function() {
       
 29685               modelCtrl.$setTouched();
       
 29686             });
       
 29687           });
       
 29688         }
       
 29689       };
       
 29690     }
       
 29691   };
       
 29692 };
       
 29693 
       
 29694 
       
 29695 /**
       
 29696  * @ngdoc directive
       
 29697  * @name ngChange
       
 29698  *
       
 29699  * @description
       
 29700  * Evaluate the given expression when the user changes the input.
       
 29701  * The expression is evaluated immediately, unlike the JavaScript onchange event
       
 29702  * which only triggers at the end of a change (usually, when the user leaves the
       
 29703  * form element or presses the return key).
       
 29704  *
       
 29705  * The `ngChange` expression is only evaluated when a change in the input value causes
       
 29706  * a new value to be committed to the model.
       
 29707  *
       
 29708  * It will not be evaluated:
       
 29709  * * if the value returned from the `$parsers` transformation pipeline has not changed
       
 29710  * * if the input has continued to be invalid since the model will stay `null`
       
 29711  * * if the model is changed programmatically and not by a change to the input value
       
 29712  *
       
 29713  *
       
 29714  * Note, this directive requires `ngModel` to be present.
       
 29715  *
       
 29716  * @element input
       
 29717  * @param {expression} ngChange {@link guide/expression Expression} to evaluate upon change
       
 29718  * in input value.
       
 29719  *
       
 29720  * @example
       
 29721  * <example name="ngChange-directive" module="changeExample">
       
 29722  *   <file name="index.html">
       
 29723  *     <script>
       
 29724  *       angular.module('changeExample', [])
       
 29725  *         .controller('ExampleController', ['$scope', function($scope) {
       
 29726  *           $scope.counter = 0;
       
 29727  *           $scope.change = function() {
       
 29728  *             $scope.counter++;
       
 29729  *           };
       
 29730  *         }]);
       
 29731  *     </script>
       
 29732  *     <div ng-controller="ExampleController">
       
 29733  *       <input type="checkbox" ng-model="confirmed" ng-change="change()" id="ng-change-example1" />
       
 29734  *       <input type="checkbox" ng-model="confirmed" id="ng-change-example2" />
       
 29735  *       <label for="ng-change-example2">Confirmed</label><br />
       
 29736  *       <tt>debug = {{confirmed}}</tt><br/>
       
 29737  *       <tt>counter = {{counter}}</tt><br/>
       
 29738  *     </div>
       
 29739  *   </file>
       
 29740  *   <file name="protractor.js" type="protractor">
       
 29741  *     var counter = element(by.binding('counter'));
       
 29742  *     var debug = element(by.binding('confirmed'));
       
 29743  *
       
 29744  *     it('should evaluate the expression if changing from view', function() {
       
 29745  *       expect(counter.getText()).toContain('0');
       
 29746  *
       
 29747  *       element(by.id('ng-change-example1')).click();
       
 29748  *
       
 29749  *       expect(counter.getText()).toContain('1');
       
 29750  *       expect(debug.getText()).toContain('true');
       
 29751  *     });
       
 29752  *
       
 29753  *     it('should not evaluate the expression if changing from model', function() {
       
 29754  *       element(by.id('ng-change-example2')).click();
       
 29755 
       
 29756  *       expect(counter.getText()).toContain('0');
       
 29757  *       expect(debug.getText()).toContain('true');
       
 29758  *     });
       
 29759  *   </file>
       
 29760  * </example>
       
 29761  */
       
 29762 var ngChangeDirective = valueFn({
       
 29763   restrict: 'A',
       
 29764   require: 'ngModel',
       
 29765   link: function(scope, element, attr, ctrl) {
       
 29766     ctrl.$viewChangeListeners.push(function() {
       
 29767       scope.$eval(attr.ngChange);
       
 29768     });
       
 29769   }
       
 29770 });
       
 29771 
       
 29772 
       
 29773 var requiredDirective = function() {
       
 29774   return {
       
 29775     restrict: 'A',
       
 29776     require: '?ngModel',
       
 29777     link: function(scope, elm, attr, ctrl) {
       
 29778       if (!ctrl) return;
       
 29779       attr.required = true; // force truthy in case we are on non input element
       
 29780 
       
 29781       ctrl.$validators.required = function(value) {
       
 29782         return !attr.required || !ctrl.$isEmpty(value);
       
 29783       };
       
 29784 
       
 29785       attr.$observe('required', function() {
       
 29786         ctrl.$validate();
       
 29787       });
       
 29788     }
       
 29789   };
       
 29790 };
       
 29791 
       
 29792 
       
 29793 var patternDirective = function() {
       
 29794   return {
       
 29795     restrict: 'A',
       
 29796     require: '?ngModel',
       
 29797     link: function(scope, elm, attr, ctrl) {
       
 29798       if (!ctrl) return;
       
 29799 
       
 29800       var regexp, patternExp = attr.ngPattern || attr.pattern;
       
 29801       attr.$observe('pattern', function(regex) {
       
 29802         if (isString(regex) && regex.length > 0) {
       
 29803           regex = new RegExp(regex);
       
 29804         }
       
 29805 
       
 29806         if (regex && !regex.test) {
       
 29807           throw minErr('ngPattern')('noregexp',
       
 29808             'Expected {0} to be a RegExp but was {1}. Element: {2}', patternExp,
       
 29809             regex, startingTag(elm));
       
 29810         }
       
 29811 
       
 29812         regexp = regex || undefined;
       
 29813         ctrl.$validate();
       
 29814       });
       
 29815 
       
 29816       ctrl.$validators.pattern = function(value) {
       
 29817         return ctrl.$isEmpty(value) || isUndefined(regexp) || regexp.test(value);
       
 29818       };
       
 29819     }
       
 29820   };
       
 29821 };
       
 29822 
       
 29823 
       
 29824 var maxlengthDirective = function() {
       
 29825   return {
       
 29826     restrict: 'A',
       
 29827     require: '?ngModel',
       
 29828     link: function(scope, elm, attr, ctrl) {
       
 29829       if (!ctrl) return;
       
 29830 
       
 29831       var maxlength = 0;
       
 29832       attr.$observe('maxlength', function(value) {
       
 29833         maxlength = int(value) || 0;
       
 29834         ctrl.$validate();
       
 29835       });
       
 29836       ctrl.$validators.maxlength = function(modelValue, viewValue) {
       
 29837         return ctrl.$isEmpty(modelValue) || viewValue.length <= maxlength;
       
 29838       };
       
 29839     }
       
 29840   };
       
 29841 };
       
 29842 
       
 29843 var minlengthDirective = function() {
       
 29844   return {
       
 29845     restrict: 'A',
       
 29846     require: '?ngModel',
       
 29847     link: function(scope, elm, attr, ctrl) {
       
 29848       if (!ctrl) return;
       
 29849 
       
 29850       var minlength = 0;
       
 29851       attr.$observe('minlength', function(value) {
       
 29852         minlength = int(value) || 0;
       
 29853         ctrl.$validate();
       
 29854       });
       
 29855       ctrl.$validators.minlength = function(modelValue, viewValue) {
       
 29856         return ctrl.$isEmpty(modelValue) || viewValue.length >= minlength;
       
 29857       };
       
 29858     }
       
 29859   };
       
 29860 };
       
 29861 
       
 29862 
       
 29863 /**
       
 29864  * @ngdoc directive
       
 29865  * @name ngList
       
 29866  *
       
 29867  * @description
       
 29868  * Text input that converts between a delimited string and an array of strings. The default
       
 29869  * delimiter is a comma followed by a space - equivalent to `ng-list=", "`. You can specify a custom
       
 29870  * delimiter as the value of the `ngList` attribute - for example, `ng-list=" | "`.
       
 29871  *
       
 29872  * The behaviour of the directive is affected by the use of the `ngTrim` attribute.
       
 29873  * * If `ngTrim` is set to `"false"` then whitespace around both the separator and each
       
 29874  *   list item is respected. This implies that the user of the directive is responsible for
       
 29875  *   dealing with whitespace but also allows you to use whitespace as a delimiter, such as a
       
 29876  *   tab or newline character.
       
 29877  * * Otherwise whitespace around the delimiter is ignored when splitting (although it is respected
       
 29878  *   when joining the list items back together) and whitespace around each list item is stripped
       
 29879  *   before it is added to the model.
       
 29880  *
       
 29881  * ### Example with Validation
       
 29882  *
       
 29883  * <example name="ngList-directive" module="listExample">
       
 29884  *   <file name="app.js">
       
 29885  *      angular.module('listExample', [])
       
 29886  *        .controller('ExampleController', ['$scope', function($scope) {
       
 29887  *          $scope.names = ['morpheus', 'neo', 'trinity'];
       
 29888  *        }]);
       
 29889  *   </file>
       
 29890  *   <file name="index.html">
       
 29891  *    <form name="myForm" ng-controller="ExampleController">
       
 29892  *      List: <input name="namesInput" ng-model="names" ng-list required>
       
 29893  *      <span class="error" ng-show="myForm.namesInput.$error.required">
       
 29894  *        Required!</span>
       
 29895  *      <br>
       
 29896  *      <tt>names = {{names}}</tt><br/>
       
 29897  *      <tt>myForm.namesInput.$valid = {{myForm.namesInput.$valid}}</tt><br/>
       
 29898  *      <tt>myForm.namesInput.$error = {{myForm.namesInput.$error}}</tt><br/>
       
 29899  *      <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
       
 29900  *      <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
       
 29901  *     </form>
       
 29902  *   </file>
       
 29903  *   <file name="protractor.js" type="protractor">
       
 29904  *     var listInput = element(by.model('names'));
       
 29905  *     var names = element(by.exactBinding('names'));
       
 29906  *     var valid = element(by.binding('myForm.namesInput.$valid'));
       
 29907  *     var error = element(by.css('span.error'));
       
 29908  *
       
 29909  *     it('should initialize to model', function() {
       
 29910  *       expect(names.getText()).toContain('["morpheus","neo","trinity"]');
       
 29911  *       expect(valid.getText()).toContain('true');
       
 29912  *       expect(error.getCssValue('display')).toBe('none');
       
 29913  *     });
       
 29914  *
       
 29915  *     it('should be invalid if empty', function() {
       
 29916  *       listInput.clear();
       
 29917  *       listInput.sendKeys('');
       
 29918  *
       
 29919  *       expect(names.getText()).toContain('');
       
 29920  *       expect(valid.getText()).toContain('false');
       
 29921  *       expect(error.getCssValue('display')).not.toBe('none');
       
 29922  *     });
       
 29923  *   </file>
       
 29924  * </example>
       
 29925  *
       
 29926  * ### Example - splitting on whitespace
       
 29927  * <example name="ngList-directive-newlines">
       
 29928  *   <file name="index.html">
       
 29929  *    <textarea ng-model="list" ng-list="&#10;" ng-trim="false"></textarea>
       
 29930  *    <pre>{{ list | json }}</pre>
       
 29931  *   </file>
       
 29932  *   <file name="protractor.js" type="protractor">
       
 29933  *     it("should split the text by newlines", function() {
       
 29934  *       var listInput = element(by.model('list'));
       
 29935  *       var output = element(by.binding('list | json'));
       
 29936  *       listInput.sendKeys('abc\ndef\nghi');
       
 29937  *       expect(output.getText()).toContain('[\n  "abc",\n  "def",\n  "ghi"\n]');
       
 29938  *     });
       
 29939  *   </file>
       
 29940  * </example>
       
 29941  *
       
 29942  * @element input
       
 29943  * @param {string=} ngList optional delimiter that should be used to split the value.
       
 29944  */
       
 29945 var ngListDirective = function() {
       
 29946   return {
       
 29947     restrict: 'A',
       
 29948     priority: 100,
       
 29949     require: 'ngModel',
       
 29950     link: function(scope, element, attr, ctrl) {
       
 29951       // We want to control whitespace trimming so we use this convoluted approach
       
 29952       // to access the ngList attribute, which doesn't pre-trim the attribute
       
 29953       var ngList = element.attr(attr.$attr.ngList) || ', ';
       
 29954       var trimValues = attr.ngTrim !== 'false';
       
 29955       var separator = trimValues ? trim(ngList) : ngList;
       
 29956 
       
 29957       var parse = function(viewValue) {
       
 29958         // If the viewValue is invalid (say required but empty) it will be `undefined`
       
 29959         if (isUndefined(viewValue)) return;
       
 29960 
       
 29961         var list = [];
       
 29962 
       
 29963         if (viewValue) {
       
 29964           forEach(viewValue.split(separator), function(value) {
       
 29965             if (value) list.push(trimValues ? trim(value) : value);
       
 29966           });
       
 29967         }
       
 29968 
       
 29969         return list;
       
 29970       };
       
 29971 
       
 29972       ctrl.$parsers.push(parse);
       
 29973       ctrl.$formatters.push(function(value) {
       
 29974         if (isArray(value)) {
       
 29975           return value.join(ngList);
       
 29976         }
       
 29977 
       
 29978         return undefined;
       
 29979       });
       
 29980 
       
 29981       // Override the standard $isEmpty because an empty array means the input is empty.
       
 29982       ctrl.$isEmpty = function(value) {
       
 29983         return !value || !value.length;
       
 29984       };
       
 29985     }
       
 29986   };
       
 29987 };
       
 29988 
       
 29989 
       
 29990 var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
       
 29991 /**
       
 29992  * @ngdoc directive
       
 29993  * @name ngValue
       
 29994  *
       
 29995  * @description
       
 29996  * Binds the given expression to the value of `input[select]` or `input[radio]`, so
       
 29997  * that when the element is selected, the `ngModel` of that element is set to the
       
 29998  * bound value.
       
 29999  *
       
 30000  * `ngValue` is useful when dynamically generating lists of radio buttons using `ng-repeat`, as
       
 30001  * shown below.
       
 30002  *
       
 30003  * @element input
       
 30004  * @param {string=} ngValue angular expression, whose value will be bound to the `value` attribute
       
 30005  *   of the `input` element
       
 30006  *
       
 30007  * @example
       
 30008     <example name="ngValue-directive" module="valueExample">
       
 30009       <file name="index.html">
       
 30010        <script>
       
 30011           angular.module('valueExample', [])
       
 30012             .controller('ExampleController', ['$scope', function($scope) {
       
 30013               $scope.names = ['pizza', 'unicorns', 'robots'];
       
 30014               $scope.my = { favorite: 'unicorns' };
       
 30015             }]);
       
 30016        </script>
       
 30017         <form ng-controller="ExampleController">
       
 30018           <h2>Which is your favorite?</h2>
       
 30019             <label ng-repeat="name in names" for="{{name}}">
       
 30020               {{name}}
       
 30021               <input type="radio"
       
 30022                      ng-model="my.favorite"
       
 30023                      ng-value="name"
       
 30024                      id="{{name}}"
       
 30025                      name="favorite">
       
 30026             </label>
       
 30027           <div>You chose {{my.favorite}}</div>
       
 30028         </form>
       
 30029       </file>
       
 30030       <file name="protractor.js" type="protractor">
       
 30031         var favorite = element(by.binding('my.favorite'));
       
 30032 
       
 30033         it('should initialize to model', function() {
       
 30034           expect(favorite.getText()).toContain('unicorns');
       
 30035         });
       
 30036         it('should bind the values to the inputs', function() {
       
 30037           element.all(by.model('my.favorite')).get(0).click();
       
 30038           expect(favorite.getText()).toContain('pizza');
       
 30039         });
       
 30040       </file>
       
 30041     </example>
       
 30042  */
       
 30043 var ngValueDirective = function() {
       
 30044   return {
       
 30045     restrict: 'A',
       
 30046     priority: 100,
       
 30047     compile: function(tpl, tplAttr) {
       
 30048       if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
       
 30049         return function ngValueConstantLink(scope, elm, attr) {
       
 30050           attr.$set('value', scope.$eval(attr.ngValue));
       
 30051         };
       
 30052       } else {
       
 30053         return function ngValueLink(scope, elm, attr) {
       
 30054           scope.$watch(attr.ngValue, function valueWatchAction(value) {
       
 30055             attr.$set('value', value);
       
 30056           });
       
 30057         };
       
 30058       }
       
 30059     }
       
 30060   };
       
 30061 };
       
 30062 
       
 30063 /**
       
 30064  * @ngdoc directive
       
 30065  * @name ngModelOptions
       
 30066  *
       
 30067  * @description
       
 30068  * Allows tuning how model updates are done. Using `ngModelOptions` you can specify a custom list of
       
 30069  * events that will trigger a model update and/or a debouncing delay so that the actual update only
       
 30070  * takes place when a timer expires; this timer will be reset after another change takes place.
       
 30071  *
       
 30072  * Given the nature of `ngModelOptions`, the value displayed inside input fields in the view might
       
 30073  * be different than the value in the actual model. This means that if you update the model you
       
 30074  * should also invoke {@link ngModel.NgModelController `$rollbackViewValue`} on the relevant input field in
       
 30075  * order to make sure it is synchronized with the model and that any debounced action is canceled.
       
 30076  *
       
 30077  * The easiest way to reference the control's {@link ngModel.NgModelController `$rollbackViewValue`}
       
 30078  * method is by making sure the input is placed inside a form that has a `name` attribute. This is
       
 30079  * important because `form` controllers are published to the related scope under the name in their
       
 30080  * `name` attribute.
       
 30081  *
       
 30082  * Any pending changes will take place immediately when an enclosing form is submitted via the
       
 30083  * `submit` event. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit`
       
 30084  * to have access to the updated model.
       
 30085  *
       
 30086  * `ngModelOptions` has an effect on the element it's declared on and its descendants.
       
 30087  *
       
 30088  * @param {Object} ngModelOptions options to apply to the current model. Valid keys are:
       
 30089  *   - `updateOn`: string specifying which event should be the input bound to. You can set several
       
 30090  *     events using an space delimited list. There is a special event called `default` that
       
 30091  *     matches the default events belonging of the control.
       
 30092  *   - `debounce`: integer value which contains the debounce model update value in milliseconds. A
       
 30093  *     value of 0 triggers an immediate update. If an object is supplied instead, you can specify a
       
 30094  *     custom value for each event. For example:
       
 30095  *     `ng-model-options="{ updateOn: 'default blur', debounce: {'default': 500, 'blur': 0} }"`
       
 30096  *   - `allowInvalid`: boolean value which indicates that the model can be set with values that did
       
 30097  *     not validate correctly instead of the default behavior of setting the model to undefined.
       
 30098  *   - `getterSetter`: boolean value which determines whether or not to treat functions bound to
       
 30099        `ngModel` as getters/setters.
       
 30100  *   - `timezone`: Defines the timezone to be used to read/write the `Date` instance in the model for
       
 30101  *     `<input type="date">`, `<input type="time">`, ... . Right now, the only supported value is `'UTC'`,
       
 30102  *     otherwise the default timezone of the browser will be used.
       
 30103  *
       
 30104  * @example
       
 30105 
       
 30106   The following example shows how to override immediate updates. Changes on the inputs within the
       
 30107   form will update the model only when the control loses focus (blur event). If `escape` key is
       
 30108   pressed while the input field is focused, the value is reset to the value in the current model.
       
 30109 
       
 30110   <example name="ngModelOptions-directive-blur" module="optionsExample">
       
 30111     <file name="index.html">
       
 30112       <div ng-controller="ExampleController">
       
 30113         <form name="userForm">
       
 30114           Name:
       
 30115           <input type="text" name="userName"
       
 30116                  ng-model="user.name"
       
 30117                  ng-model-options="{ updateOn: 'blur' }"
       
 30118                  ng-keyup="cancel($event)" /><br />
       
 30119 
       
 30120           Other data:
       
 30121           <input type="text" ng-model="user.data" /><br />
       
 30122         </form>
       
 30123         <pre>user.name = <span ng-bind="user.name"></span></pre>
       
 30124       </div>
       
 30125     </file>
       
 30126     <file name="app.js">
       
 30127       angular.module('optionsExample', [])
       
 30128         .controller('ExampleController', ['$scope', function($scope) {
       
 30129           $scope.user = { name: 'say', data: '' };
       
 30130 
       
 30131           $scope.cancel = function (e) {
       
 30132             if (e.keyCode == 27) {
       
 30133               $scope.userForm.userName.$rollbackViewValue();
       
 30134             }
       
 30135           };
       
 30136         }]);
       
 30137     </file>
       
 30138     <file name="protractor.js" type="protractor">
       
 30139       var model = element(by.binding('user.name'));
       
 30140       var input = element(by.model('user.name'));
       
 30141       var other = element(by.model('user.data'));
       
 30142 
       
 30143       it('should allow custom events', function() {
       
 30144         input.sendKeys(' hello');
       
 30145         input.click();
       
 30146         expect(model.getText()).toEqual('say');
       
 30147         other.click();
       
 30148         expect(model.getText()).toEqual('say hello');
       
 30149       });
       
 30150 
       
 30151       it('should $rollbackViewValue when model changes', function() {
       
 30152         input.sendKeys(' hello');
       
 30153         expect(input.getAttribute('value')).toEqual('say hello');
       
 30154         input.sendKeys(protractor.Key.ESCAPE);
       
 30155         expect(input.getAttribute('value')).toEqual('say');
       
 30156         other.click();
       
 30157         expect(model.getText()).toEqual('say');
       
 30158       });
       
 30159     </file>
       
 30160   </example>
       
 30161 
       
 30162   This one shows how to debounce model changes. Model will be updated only 1 sec after last change.
       
 30163   If the `Clear` button is pressed, any debounced action is canceled and the value becomes empty.
       
 30164 
       
 30165   <example name="ngModelOptions-directive-debounce" module="optionsExample">
       
 30166     <file name="index.html">
       
 30167       <div ng-controller="ExampleController">
       
 30168         <form name="userForm">
       
 30169           Name:
       
 30170           <input type="text" name="userName"
       
 30171                  ng-model="user.name"
       
 30172                  ng-model-options="{ debounce: 1000 }" />
       
 30173           <button ng-click="userForm.userName.$rollbackViewValue(); user.name=''">Clear</button><br />
       
 30174         </form>
       
 30175         <pre>user.name = <span ng-bind="user.name"></span></pre>
       
 30176       </div>
       
 30177     </file>
       
 30178     <file name="app.js">
       
 30179       angular.module('optionsExample', [])
       
 30180         .controller('ExampleController', ['$scope', function($scope) {
       
 30181           $scope.user = { name: 'say' };
       
 30182         }]);
       
 30183     </file>
       
 30184   </example>
       
 30185 
       
 30186   This one shows how to bind to getter/setters:
       
 30187 
       
 30188   <example name="ngModelOptions-directive-getter-setter" module="getterSetterExample">
       
 30189     <file name="index.html">
       
 30190       <div ng-controller="ExampleController">
       
 30191         <form name="userForm">
       
 30192           Name:
       
 30193           <input type="text" name="userName"
       
 30194                  ng-model="user.name"
       
 30195                  ng-model-options="{ getterSetter: true }" />
       
 30196         </form>
       
 30197         <pre>user.name = <span ng-bind="user.name()"></span></pre>
       
 30198       </div>
       
 30199     </file>
       
 30200     <file name="app.js">
       
 30201       angular.module('getterSetterExample', [])
       
 30202         .controller('ExampleController', ['$scope', function($scope) {
       
 30203           var _name = 'Brian';
       
 30204           $scope.user = {
       
 30205             name: function (newName) {
       
 30206               return angular.isDefined(newName) ? (_name = newName) : _name;
       
 30207             }
       
 30208           };
       
 30209         }]);
       
 30210     </file>
       
 30211   </example>
       
 30212  */
       
 30213 var ngModelOptionsDirective = function() {
       
 30214   return {
       
 30215     restrict: 'A',
       
 30216     controller: ['$scope', '$attrs', function($scope, $attrs) {
       
 30217       var that = this;
       
 30218       this.$options = $scope.$eval($attrs.ngModelOptions);
       
 30219       // Allow adding/overriding bound events
       
 30220       if (this.$options.updateOn !== undefined) {
       
 30221         this.$options.updateOnDefault = false;
       
 30222         // extract "default" pseudo-event from list of events that can trigger a model update
       
 30223         this.$options.updateOn = trim(this.$options.updateOn.replace(DEFAULT_REGEXP, function() {
       
 30224           that.$options.updateOnDefault = true;
       
 30225           return ' ';
       
 30226         }));
       
 30227       } else {
       
 30228         this.$options.updateOnDefault = true;
       
 30229       }
       
 30230     }]
       
 30231   };
       
 30232 };
       
 30233 
       
 30234 // helper methods
       
 30235 function addSetValidityMethod(context) {
       
 30236   var ctrl = context.ctrl,
       
 30237       $element = context.$element,
       
 30238       classCache = {},
       
 30239       set = context.set,
       
 30240       unset = context.unset,
       
 30241       parentForm = context.parentForm,
       
 30242       $animate = context.$animate;
       
 30243 
       
 30244   classCache[INVALID_CLASS] = !(classCache[VALID_CLASS] = $element.hasClass(VALID_CLASS));
       
 30245 
       
 30246   ctrl.$setValidity = setValidity;
       
 30247 
       
 30248   function setValidity(validationErrorKey, state, options) {
       
 30249     if (state === undefined) {
       
 30250       createAndSet('$pending', validationErrorKey, options);
       
 30251     } else {
       
 30252       unsetAndCleanup('$pending', validationErrorKey, options);
       
 30253     }
       
 30254     if (!isBoolean(state)) {
       
 30255       unset(ctrl.$error, validationErrorKey, options);
       
 30256       unset(ctrl.$$success, validationErrorKey, options);
       
 30257     } else {
       
 30258       if (state) {
       
 30259         unset(ctrl.$error, validationErrorKey, options);
       
 30260         set(ctrl.$$success, validationErrorKey, options);
       
 30261       } else {
       
 30262         set(ctrl.$error, validationErrorKey, options);
       
 30263         unset(ctrl.$$success, validationErrorKey, options);
       
 30264       }
       
 30265     }
       
 30266     if (ctrl.$pending) {
       
 30267       cachedToggleClass(PENDING_CLASS, true);
       
 30268       ctrl.$valid = ctrl.$invalid = undefined;
       
 30269       toggleValidationCss('', null);
       
 30270     } else {
       
 30271       cachedToggleClass(PENDING_CLASS, false);
       
 30272       ctrl.$valid = isObjectEmpty(ctrl.$error);
       
 30273       ctrl.$invalid = !ctrl.$valid;
       
 30274       toggleValidationCss('', ctrl.$valid);
       
 30275     }
       
 30276 
       
 30277     // re-read the state as the set/unset methods could have
       
 30278     // combined state in ctrl.$error[validationError] (used for forms),
       
 30279     // where setting/unsetting only increments/decrements the value,
       
 30280     // and does not replace it.
       
 30281     var combinedState;
       
 30282     if (ctrl.$pending && ctrl.$pending[validationErrorKey]) {
       
 30283       combinedState = undefined;
       
 30284     } else if (ctrl.$error[validationErrorKey]) {
       
 30285       combinedState = false;
       
 30286     } else if (ctrl.$$success[validationErrorKey]) {
       
 30287       combinedState = true;
       
 30288     } else {
       
 30289       combinedState = null;
       
 30290     }
       
 30291     toggleValidationCss(validationErrorKey, combinedState);
       
 30292     parentForm.$setValidity(validationErrorKey, combinedState, ctrl);
       
 30293   }
       
 30294 
       
 30295   function createAndSet(name, value, options) {
       
 30296     if (!ctrl[name]) {
       
 30297       ctrl[name] = {};
       
 30298     }
       
 30299     set(ctrl[name], value, options);
       
 30300   }
       
 30301 
       
 30302   function unsetAndCleanup(name, value, options) {
       
 30303     if (ctrl[name]) {
       
 30304       unset(ctrl[name], value, options);
       
 30305     }
       
 30306     if (isObjectEmpty(ctrl[name])) {
       
 30307       ctrl[name] = undefined;
       
 30308     }
       
 30309   }
       
 30310 
       
 30311   function cachedToggleClass(className, switchValue) {
       
 30312     if (switchValue && !classCache[className]) {
       
 30313       $animate.addClass($element, className);
       
 30314       classCache[className] = true;
       
 30315     } else if (!switchValue && classCache[className]) {
       
 30316       $animate.removeClass($element, className);
       
 30317       classCache[className] = false;
       
 30318     }
       
 30319   }
       
 30320 
       
 30321   function toggleValidationCss(validationErrorKey, isValid) {
       
 30322     validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
       
 30323 
       
 30324     cachedToggleClass(VALID_CLASS + validationErrorKey, isValid === true);
       
 30325     cachedToggleClass(INVALID_CLASS + validationErrorKey, isValid === false);
       
 30326   }
       
 30327 }
       
 30328 
       
 30329 function isObjectEmpty(obj) {
       
 30330   if (obj) {
       
 30331     for (var prop in obj) {
       
 30332       return false;
       
 30333     }
       
 30334   }
       
 30335   return true;
       
 30336 }
       
 30337 
       
 30338 /**
       
 30339  * @ngdoc directive
       
 30340  * @name ngBind
       
 30341  * @restrict AC
       
 30342  *
       
 30343  * @description
       
 30344  * The `ngBind` attribute tells Angular to replace the text content of the specified HTML element
       
 30345  * with the value of a given expression, and to update the text content when the value of that
       
 30346  * expression changes.
       
 30347  *
       
 30348  * Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
       
 30349  * `{{ expression }}` which is similar but less verbose.
       
 30350  *
       
 30351  * It is preferable to use `ngBind` instead of `{{ expression }}` if a template is momentarily
       
 30352  * displayed by the browser in its raw state before Angular compiles it. Since `ngBind` is an
       
 30353  * element attribute, it makes the bindings invisible to the user while the page is loading.
       
 30354  *
       
 30355  * An alternative solution to this problem would be using the
       
 30356  * {@link ng.directive:ngCloak ngCloak} directive.
       
 30357  *
       
 30358  *
       
 30359  * @element ANY
       
 30360  * @param {expression} ngBind {@link guide/expression Expression} to evaluate.
       
 30361  *
       
 30362  * @example
       
 30363  * Enter a name in the Live Preview text box; the greeting below the text box changes instantly.
       
 30364    <example module="bindExample">
       
 30365      <file name="index.html">
       
 30366        <script>
       
 30367          angular.module('bindExample', [])
       
 30368            .controller('ExampleController', ['$scope', function($scope) {
       
 30369              $scope.name = 'Whirled';
       
 30370            }]);
       
 30371        </script>
       
 30372        <div ng-controller="ExampleController">
       
 30373          Enter name: <input type="text" ng-model="name"><br>
       
 30374          Hello <span ng-bind="name"></span>!
       
 30375        </div>
       
 30376      </file>
       
 30377      <file name="protractor.js" type="protractor">
       
 30378        it('should check ng-bind', function() {
       
 30379          var nameInput = element(by.model('name'));
       
 30380 
       
 30381          expect(element(by.binding('name')).getText()).toBe('Whirled');
       
 30382          nameInput.clear();
       
 30383          nameInput.sendKeys('world');
       
 30384          expect(element(by.binding('name')).getText()).toBe('world');
       
 30385        });
       
 30386      </file>
       
 30387    </example>
       
 30388  */
       
 30389 var ngBindDirective = ['$compile', function($compile) {
       
 30390   return {
       
 30391     restrict: 'AC',
       
 30392     compile: function ngBindCompile(templateElement) {
       
 30393       $compile.$$addBindingClass(templateElement);
       
 30394       return function ngBindLink(scope, element, attr) {
       
 30395         $compile.$$addBindingInfo(element, attr.ngBind);
       
 30396         element = element[0];
       
 30397         scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
       
 30398           element.textContent = value === undefined ? '' : value;
       
 30399         });
       
 30400       };
       
 30401     }
       
 30402   };
       
 30403 }];
       
 30404 
       
 30405 
       
 30406 /**
       
 30407  * @ngdoc directive
       
 30408  * @name ngBindTemplate
       
 30409  *
       
 30410  * @description
       
 30411  * The `ngBindTemplate` directive specifies that the element
       
 30412  * text content should be replaced with the interpolation of the template
       
 30413  * in the `ngBindTemplate` attribute.
       
 30414  * Unlike `ngBind`, the `ngBindTemplate` can contain multiple `{{` `}}`
       
 30415  * expressions. This directive is needed since some HTML elements
       
 30416  * (such as TITLE and OPTION) cannot contain SPAN elements.
       
 30417  *
       
 30418  * @element ANY
       
 30419  * @param {string} ngBindTemplate template of form
       
 30420  *   <tt>{{</tt> <tt>expression</tt> <tt>}}</tt> to eval.
       
 30421  *
       
 30422  * @example
       
 30423  * Try it here: enter text in text box and watch the greeting change.
       
 30424    <example module="bindExample">
       
 30425      <file name="index.html">
       
 30426        <script>
       
 30427          angular.module('bindExample', [])
       
 30428            .controller('ExampleController', ['$scope', function ($scope) {
       
 30429              $scope.salutation = 'Hello';
       
 30430              $scope.name = 'World';
       
 30431            }]);
       
 30432        </script>
       
 30433        <div ng-controller="ExampleController">
       
 30434         Salutation: <input type="text" ng-model="salutation"><br>
       
 30435         Name: <input type="text" ng-model="name"><br>
       
 30436         <pre ng-bind-template="{{salutation}} {{name}}!"></pre>
       
 30437        </div>
       
 30438      </file>
       
 30439      <file name="protractor.js" type="protractor">
       
 30440        it('should check ng-bind', function() {
       
 30441          var salutationElem = element(by.binding('salutation'));
       
 30442          var salutationInput = element(by.model('salutation'));
       
 30443          var nameInput = element(by.model('name'));
       
 30444 
       
 30445          expect(salutationElem.getText()).toBe('Hello World!');
       
 30446 
       
 30447          salutationInput.clear();
       
 30448          salutationInput.sendKeys('Greetings');
       
 30449          nameInput.clear();
       
 30450          nameInput.sendKeys('user');
       
 30451 
       
 30452          expect(salutationElem.getText()).toBe('Greetings user!');
       
 30453        });
       
 30454      </file>
       
 30455    </example>
       
 30456  */
       
 30457 var ngBindTemplateDirective = ['$interpolate', '$compile', function($interpolate, $compile) {
       
 30458   return {
       
 30459     compile: function ngBindTemplateCompile(templateElement) {
       
 30460       $compile.$$addBindingClass(templateElement);
       
 30461       return function ngBindTemplateLink(scope, element, attr) {
       
 30462         var interpolateFn = $interpolate(element.attr(attr.$attr.ngBindTemplate));
       
 30463         $compile.$$addBindingInfo(element, interpolateFn.expressions);
       
 30464         element = element[0];
       
 30465         attr.$observe('ngBindTemplate', function(value) {
       
 30466           element.textContent = value === undefined ? '' : value;
       
 30467         });
       
 30468       };
       
 30469     }
       
 30470   };
       
 30471 }];
       
 30472 
       
 30473 
       
 30474 /**
       
 30475  * @ngdoc directive
       
 30476  * @name ngBindHtml
       
 30477  *
       
 30478  * @description
       
 30479  * Creates a binding that will innerHTML the result of evaluating the `expression` into the current
       
 30480  * element in a secure way.  By default, the innerHTML-ed content will be sanitized using the {@link
       
 30481  * ngSanitize.$sanitize $sanitize} service.  To utilize this functionality, ensure that `$sanitize`
       
 30482  * is available, for example, by including {@link ngSanitize} in your module's dependencies (not in
       
 30483  * core Angular). In order to use {@link ngSanitize} in your module's dependencies, you need to
       
 30484  * include "angular-sanitize.js" in your application.
       
 30485  *
       
 30486  * You may also bypass sanitization for values you know are safe. To do so, bind to
       
 30487  * an explicitly trusted value via {@link ng.$sce#trustAsHtml $sce.trustAsHtml}.  See the example
       
 30488  * under {@link ng.$sce#Example Strict Contextual Escaping (SCE)}.
       
 30489  *
       
 30490  * Note: If a `$sanitize` service is unavailable and the bound value isn't explicitly trusted, you
       
 30491  * will have an exception (instead of an exploit.)
       
 30492  *
       
 30493  * @element ANY
       
 30494  * @param {expression} ngBindHtml {@link guide/expression Expression} to evaluate.
       
 30495  *
       
 30496  * @example
       
 30497 
       
 30498    <example module="bindHtmlExample" deps="angular-sanitize.js">
       
 30499      <file name="index.html">
       
 30500        <div ng-controller="ExampleController">
       
 30501         <p ng-bind-html="myHTML"></p>
       
 30502        </div>
       
 30503      </file>
       
 30504 
       
 30505      <file name="script.js">
       
 30506        angular.module('bindHtmlExample', ['ngSanitize'])
       
 30507          .controller('ExampleController', ['$scope', function($scope) {
       
 30508            $scope.myHTML =
       
 30509               'I am an <code>HTML</code>string with ' +
       
 30510               '<a href="#">links!</a> and other <em>stuff</em>';
       
 30511          }]);
       
 30512      </file>
       
 30513 
       
 30514      <file name="protractor.js" type="protractor">
       
 30515        it('should check ng-bind-html', function() {
       
 30516          expect(element(by.binding('myHTML')).getText()).toBe(
       
 30517              'I am an HTMLstring with links! and other stuff');
       
 30518        });
       
 30519      </file>
       
 30520    </example>
       
 30521  */
       
 30522 var ngBindHtmlDirective = ['$sce', '$parse', '$compile', function($sce, $parse, $compile) {
       
 30523   return {
       
 30524     restrict: 'A',
       
 30525     compile: function ngBindHtmlCompile(tElement, tAttrs) {
       
 30526       var ngBindHtmlGetter = $parse(tAttrs.ngBindHtml);
       
 30527       var ngBindHtmlWatch = $parse(tAttrs.ngBindHtml, function getStringValue(value) {
       
 30528         return (value || '').toString();
       
 30529       });
       
 30530       $compile.$$addBindingClass(tElement);
       
 30531 
       
 30532       return function ngBindHtmlLink(scope, element, attr) {
       
 30533         $compile.$$addBindingInfo(element, attr.ngBindHtml);
       
 30534 
       
 30535         scope.$watch(ngBindHtmlWatch, function ngBindHtmlWatchAction() {
       
 30536           // we re-evaluate the expr because we want a TrustedValueHolderType
       
 30537           // for $sce, not a string
       
 30538           element.html($sce.getTrustedHtml(ngBindHtmlGetter(scope)) || '');
       
 30539         });
       
 30540       };
       
 30541     }
       
 30542   };
       
 30543 }];
       
 30544 
       
 30545 function classDirective(name, selector) {
       
 30546   name = 'ngClass' + name;
       
 30547   return ['$animate', function($animate) {
       
 30548     return {
       
 30549       restrict: 'AC',
       
 30550       link: function(scope, element, attr) {
       
 30551         var oldVal;
       
 30552 
       
 30553         scope.$watch(attr[name], ngClassWatchAction, true);
       
 30554 
       
 30555         attr.$observe('class', function(value) {
       
 30556           ngClassWatchAction(scope.$eval(attr[name]));
       
 30557         });
       
 30558 
       
 30559 
       
 30560         if (name !== 'ngClass') {
       
 30561           scope.$watch('$index', function($index, old$index) {
       
 30562             // jshint bitwise: false
       
 30563             var mod = $index & 1;
       
 30564             if (mod !== (old$index & 1)) {
       
 30565               var classes = arrayClasses(scope.$eval(attr[name]));
       
 30566               mod === selector ?
       
 30567                 addClasses(classes) :
       
 30568                 removeClasses(classes);
       
 30569             }
       
 30570           });
       
 30571         }
       
 30572 
       
 30573         function addClasses(classes) {
       
 30574           var newClasses = digestClassCounts(classes, 1);
       
 30575           attr.$addClass(newClasses);
       
 30576         }
       
 30577 
       
 30578         function removeClasses(classes) {
       
 30579           var newClasses = digestClassCounts(classes, -1);
       
 30580           attr.$removeClass(newClasses);
       
 30581         }
       
 30582 
       
 30583         function digestClassCounts (classes, count) {
       
 30584           var classCounts = element.data('$classCounts') || {};
       
 30585           var classesToUpdate = [];
       
 30586           forEach(classes, function (className) {
       
 30587             if (count > 0 || classCounts[className]) {
       
 30588               classCounts[className] = (classCounts[className] || 0) + count;
       
 30589               if (classCounts[className] === +(count > 0)) {
       
 30590                 classesToUpdate.push(className);
       
 30591               }
       
 30592             }
       
 30593           });
       
 30594           element.data('$classCounts', classCounts);
       
 30595           return classesToUpdate.join(' ');
       
 30596         }
       
 30597 
       
 30598         function updateClasses (oldClasses, newClasses) {
       
 30599           var toAdd = arrayDifference(newClasses, oldClasses);
       
 30600           var toRemove = arrayDifference(oldClasses, newClasses);
       
 30601           toAdd = digestClassCounts(toAdd, 1);
       
 30602           toRemove = digestClassCounts(toRemove, -1);
       
 30603           if (toAdd && toAdd.length) {
       
 30604             $animate.addClass(element, toAdd);
       
 30605           }
       
 30606           if (toRemove && toRemove.length) {
       
 30607             $animate.removeClass(element, toRemove);
       
 30608           }
       
 30609         }
       
 30610 
       
 30611         function ngClassWatchAction(newVal) {
       
 30612           if (selector === true || scope.$index % 2 === selector) {
       
 30613             var newClasses = arrayClasses(newVal || []);
       
 30614             if (!oldVal) {
       
 30615               addClasses(newClasses);
       
 30616             } else if (!equals(newVal,oldVal)) {
       
 30617               var oldClasses = arrayClasses(oldVal);
       
 30618               updateClasses(oldClasses, newClasses);
       
 30619             }
       
 30620           }
       
 30621           oldVal = shallowCopy(newVal);
       
 30622         }
       
 30623       }
       
 30624     };
       
 30625 
       
 30626     function arrayDifference(tokens1, tokens2) {
       
 30627       var values = [];
       
 30628 
       
 30629       outer:
       
 30630       for(var i = 0; i < tokens1.length; i++) {
       
 30631         var token = tokens1[i];
       
 30632         for(var j = 0; j < tokens2.length; j++) {
       
 30633           if(token == tokens2[j]) continue outer;
       
 30634         }
       
 30635         values.push(token);
       
 30636       }
       
 30637       return values;
       
 30638     }
       
 30639 
       
 30640     function arrayClasses (classVal) {
       
 30641       if (isArray(classVal)) {
       
 30642         return classVal;
       
 30643       } else if (isString(classVal)) {
       
 30644         return classVal.split(' ');
       
 30645       } else if (isObject(classVal)) {
       
 30646         var classes = [], i = 0;
       
 30647         forEach(classVal, function(v, k) {
       
 30648           if (v) {
       
 30649             classes = classes.concat(k.split(' '));
       
 30650           }
       
 30651         });
       
 30652         return classes;
       
 30653       }
       
 30654       return classVal;
       
 30655     }
       
 30656   }];
       
 30657 }
       
 30658 
       
 30659 /**
       
 30660  * @ngdoc directive
       
 30661  * @name ngClass
       
 30662  * @restrict AC
       
 30663  *
       
 30664  * @description
       
 30665  * The `ngClass` directive allows you to dynamically set CSS classes on an HTML element by databinding
       
 30666  * an expression that represents all classes to be added.
       
 30667  *
       
 30668  * The directive operates in three different ways, depending on which of three types the expression
       
 30669  * evaluates to:
       
 30670  *
       
 30671  * 1. If the expression evaluates to a string, the string should be one or more space-delimited class
       
 30672  * names.
       
 30673  *
       
 30674  * 2. If the expression evaluates to an array, each element of the array should be a string that is
       
 30675  * one or more space-delimited class names.
       
 30676  *
       
 30677  * 3. If the expression evaluates to an object, then for each key-value pair of the
       
 30678  * object with a truthy value the corresponding key is used as a class name.
       
 30679  *
       
 30680  * The directive won't add duplicate classes if a particular class was already set.
       
 30681  *
       
 30682  * When the expression changes, the previously added classes are removed and only then the
       
 30683  * new classes are added.
       
 30684  *
       
 30685  * @animations
       
 30686  * add - happens just before the class is applied to the element
       
 30687  * remove - happens just before the class is removed from the element
       
 30688  *
       
 30689  * @element ANY
       
 30690  * @param {expression} ngClass {@link guide/expression Expression} to eval. The result
       
 30691  *   of the evaluation can be a string representing space delimited class
       
 30692  *   names, an array, or a map of class names to boolean values. In the case of a map, the
       
 30693  *   names of the properties whose values are truthy will be added as css classes to the
       
 30694  *   element.
       
 30695  *
       
 30696  * @example Example that demonstrates basic bindings via ngClass directive.
       
 30697    <example>
       
 30698      <file name="index.html">
       
 30699        <p ng-class="{strike: deleted, bold: important, red: error}">Map Syntax Example</p>
       
 30700        <input type="checkbox" ng-model="deleted"> deleted (apply "strike" class)<br>
       
 30701        <input type="checkbox" ng-model="important"> important (apply "bold" class)<br>
       
 30702        <input type="checkbox" ng-model="error"> error (apply "red" class)
       
 30703        <hr>
       
 30704        <p ng-class="style">Using String Syntax</p>
       
 30705        <input type="text" ng-model="style" placeholder="Type: bold strike red">
       
 30706        <hr>
       
 30707        <p ng-class="[style1, style2, style3]">Using Array Syntax</p>
       
 30708        <input ng-model="style1" placeholder="Type: bold, strike or red"><br>
       
 30709        <input ng-model="style2" placeholder="Type: bold, strike or red"><br>
       
 30710        <input ng-model="style3" placeholder="Type: bold, strike or red"><br>
       
 30711      </file>
       
 30712      <file name="style.css">
       
 30713        .strike {
       
 30714          text-decoration: line-through;
       
 30715        }
       
 30716        .bold {
       
 30717            font-weight: bold;
       
 30718        }
       
 30719        .red {
       
 30720            color: red;
       
 30721        }
       
 30722      </file>
       
 30723      <file name="protractor.js" type="protractor">
       
 30724        var ps = element.all(by.css('p'));
       
 30725 
       
 30726        it('should let you toggle the class', function() {
       
 30727 
       
 30728          expect(ps.first().getAttribute('class')).not.toMatch(/bold/);
       
 30729          expect(ps.first().getAttribute('class')).not.toMatch(/red/);
       
 30730 
       
 30731          element(by.model('important')).click();
       
 30732          expect(ps.first().getAttribute('class')).toMatch(/bold/);
       
 30733 
       
 30734          element(by.model('error')).click();
       
 30735          expect(ps.first().getAttribute('class')).toMatch(/red/);
       
 30736        });
       
 30737 
       
 30738        it('should let you toggle string example', function() {
       
 30739          expect(ps.get(1).getAttribute('class')).toBe('');
       
 30740          element(by.model('style')).clear();
       
 30741          element(by.model('style')).sendKeys('red');
       
 30742          expect(ps.get(1).getAttribute('class')).toBe('red');
       
 30743        });
       
 30744 
       
 30745        it('array example should have 3 classes', function() {
       
 30746          expect(ps.last().getAttribute('class')).toBe('');
       
 30747          element(by.model('style1')).sendKeys('bold');
       
 30748          element(by.model('style2')).sendKeys('strike');
       
 30749          element(by.model('style3')).sendKeys('red');
       
 30750          expect(ps.last().getAttribute('class')).toBe('bold strike red');
       
 30751        });
       
 30752      </file>
       
 30753    </example>
       
 30754 
       
 30755    ## Animations
       
 30756 
       
 30757    The example below demonstrates how to perform animations using ngClass.
       
 30758 
       
 30759    <example module="ngAnimate" deps="angular-animate.js" animations="true">
       
 30760      <file name="index.html">
       
 30761       <input id="setbtn" type="button" value="set" ng-click="myVar='my-class'">
       
 30762       <input id="clearbtn" type="button" value="clear" ng-click="myVar=''">
       
 30763       <br>
       
 30764       <span class="base-class" ng-class="myVar">Sample Text</span>
       
 30765      </file>
       
 30766      <file name="style.css">
       
 30767        .base-class {
       
 30768          -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
       
 30769          transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
       
 30770        }
       
 30771 
       
 30772        .base-class.my-class {
       
 30773          color: red;
       
 30774          font-size:3em;
       
 30775        }
       
 30776      </file>
       
 30777      <file name="protractor.js" type="protractor">
       
 30778        it('should check ng-class', function() {
       
 30779          expect(element(by.css('.base-class')).getAttribute('class')).not.
       
 30780            toMatch(/my-class/);
       
 30781 
       
 30782          element(by.id('setbtn')).click();
       
 30783 
       
 30784          expect(element(by.css('.base-class')).getAttribute('class')).
       
 30785            toMatch(/my-class/);
       
 30786 
       
 30787          element(by.id('clearbtn')).click();
       
 30788 
       
 30789          expect(element(by.css('.base-class')).getAttribute('class')).not.
       
 30790            toMatch(/my-class/);
       
 30791        });
       
 30792      </file>
       
 30793    </example>
       
 30794 
       
 30795 
       
 30796    ## ngClass and pre-existing CSS3 Transitions/Animations
       
 30797    The ngClass directive still supports CSS3 Transitions/Animations even if they do not follow the ngAnimate CSS naming structure.
       
 30798    Upon animation ngAnimate will apply supplementary CSS classes to track the start and end of an animation, but this will not hinder
       
 30799    any pre-existing CSS transitions already on the element. To get an idea of what happens during a class-based animation, be sure
       
 30800    to view the step by step details of {@link ngAnimate.$animate#addclass $animate.addClass} and
       
 30801    {@link ngAnimate.$animate#removeclass $animate.removeClass}.
       
 30802  */
       
 30803 var ngClassDirective = classDirective('', true);
       
 30804 
       
 30805 /**
       
 30806  * @ngdoc directive
       
 30807  * @name ngClassOdd
       
 30808  * @restrict AC
       
 30809  *
       
 30810  * @description
       
 30811  * The `ngClassOdd` and `ngClassEven` directives work exactly as
       
 30812  * {@link ng.directive:ngClass ngClass}, except they work in
       
 30813  * conjunction with `ngRepeat` and take effect only on odd (even) rows.
       
 30814  *
       
 30815  * This directive can be applied only within the scope of an
       
 30816  * {@link ng.directive:ngRepeat ngRepeat}.
       
 30817  *
       
 30818  * @element ANY
       
 30819  * @param {expression} ngClassOdd {@link guide/expression Expression} to eval. The result
       
 30820  *   of the evaluation can be a string representing space delimited class names or an array.
       
 30821  *
       
 30822  * @example
       
 30823    <example>
       
 30824      <file name="index.html">
       
 30825         <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
       
 30826           <li ng-repeat="name in names">
       
 30827            <span ng-class-odd="'odd'" ng-class-even="'even'">
       
 30828              {{name}}
       
 30829            </span>
       
 30830           </li>
       
 30831         </ol>
       
 30832      </file>
       
 30833      <file name="style.css">
       
 30834        .odd {
       
 30835          color: red;
       
 30836        }
       
 30837        .even {
       
 30838          color: blue;
       
 30839        }
       
 30840      </file>
       
 30841      <file name="protractor.js" type="protractor">
       
 30842        it('should check ng-class-odd and ng-class-even', function() {
       
 30843          expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
       
 30844            toMatch(/odd/);
       
 30845          expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
       
 30846            toMatch(/even/);
       
 30847        });
       
 30848      </file>
       
 30849    </example>
       
 30850  */
       
 30851 var ngClassOddDirective = classDirective('Odd', 0);
       
 30852 
       
 30853 /**
       
 30854  * @ngdoc directive
       
 30855  * @name ngClassEven
       
 30856  * @restrict AC
       
 30857  *
       
 30858  * @description
       
 30859  * The `ngClassOdd` and `ngClassEven` directives work exactly as
       
 30860  * {@link ng.directive:ngClass ngClass}, except they work in
       
 30861  * conjunction with `ngRepeat` and take effect only on odd (even) rows.
       
 30862  *
       
 30863  * This directive can be applied only within the scope of an
       
 30864  * {@link ng.directive:ngRepeat ngRepeat}.
       
 30865  *
       
 30866  * @element ANY
       
 30867  * @param {expression} ngClassEven {@link guide/expression Expression} to eval. The
       
 30868  *   result of the evaluation can be a string representing space delimited class names or an array.
       
 30869  *
       
 30870  * @example
       
 30871    <example>
       
 30872      <file name="index.html">
       
 30873         <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
       
 30874           <li ng-repeat="name in names">
       
 30875            <span ng-class-odd="'odd'" ng-class-even="'even'">
       
 30876              {{name}} &nbsp; &nbsp; &nbsp;
       
 30877            </span>
       
 30878           </li>
       
 30879         </ol>
       
 30880      </file>
       
 30881      <file name="style.css">
       
 30882        .odd {
       
 30883          color: red;
       
 30884        }
       
 30885        .even {
       
 30886          color: blue;
       
 30887        }
       
 30888      </file>
       
 30889      <file name="protractor.js" type="protractor">
       
 30890        it('should check ng-class-odd and ng-class-even', function() {
       
 30891          expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
       
 30892            toMatch(/odd/);
       
 30893          expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
       
 30894            toMatch(/even/);
       
 30895        });
       
 30896      </file>
       
 30897    </example>
       
 30898  */
       
 30899 var ngClassEvenDirective = classDirective('Even', 1);
       
 30900 
       
 30901 /**
       
 30902  * @ngdoc directive
       
 30903  * @name ngCloak
       
 30904  * @restrict AC
       
 30905  *
       
 30906  * @description
       
 30907  * The `ngCloak` directive is used to prevent the Angular html template from being briefly
       
 30908  * displayed by the browser in its raw (uncompiled) form while your application is loading. Use this
       
 30909  * directive to avoid the undesirable flicker effect caused by the html template display.
       
 30910  *
       
 30911  * The directive can be applied to the `<body>` element, but the preferred usage is to apply
       
 30912  * multiple `ngCloak` directives to small portions of the page to permit progressive rendering
       
 30913  * of the browser view.
       
 30914  *
       
 30915  * `ngCloak` works in cooperation with the following css rule embedded within `angular.js` and
       
 30916  * `angular.min.js`.
       
 30917  * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
       
 30918  *
       
 30919  * ```css
       
 30920  * [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
       
 30921  *   display: none !important;
       
 30922  * }
       
 30923  * ```
       
 30924  *
       
 30925  * When this css rule is loaded by the browser, all html elements (including their children) that
       
 30926  * are tagged with the `ngCloak` directive are hidden. When Angular encounters this directive
       
 30927  * during the compilation of the template it deletes the `ngCloak` element attribute, making
       
 30928  * the compiled element visible.
       
 30929  *
       
 30930  * For the best result, the `angular.js` script must be loaded in the head section of the html
       
 30931  * document; alternatively, the css rule above must be included in the external stylesheet of the
       
 30932  * application.
       
 30933  *
       
 30934  * Legacy browsers, like IE7, do not provide attribute selector support (added in CSS 2.1) so they
       
 30935  * cannot match the `[ng\:cloak]` selector. To work around this limitation, you must add the css
       
 30936  * class `ng-cloak` in addition to the `ngCloak` directive as shown in the example below.
       
 30937  *
       
 30938  * @element ANY
       
 30939  *
       
 30940  * @example
       
 30941    <example>
       
 30942      <file name="index.html">
       
 30943         <div id="template1" ng-cloak>{{ 'hello' }}</div>
       
 30944         <div id="template2" ng-cloak class="ng-cloak">{{ 'hello IE7' }}</div>
       
 30945      </file>
       
 30946      <file name="protractor.js" type="protractor">
       
 30947        it('should remove the template directive and css class', function() {
       
 30948          expect($('#template1').getAttribute('ng-cloak')).
       
 30949            toBeNull();
       
 30950          expect($('#template2').getAttribute('ng-cloak')).
       
 30951            toBeNull();
       
 30952        });
       
 30953      </file>
       
 30954    </example>
       
 30955  *
       
 30956  */
       
 30957 var ngCloakDirective = ngDirective({
       
 30958   compile: function(element, attr) {
       
 30959     attr.$set('ngCloak', undefined);
       
 30960     element.removeClass('ng-cloak');
       
 30961   }
       
 30962 });
       
 30963 
       
 30964 /**
       
 30965  * @ngdoc directive
       
 30966  * @name ngController
       
 30967  *
       
 30968  * @description
       
 30969  * The `ngController` directive attaches a controller class to the view. This is a key aspect of how angular
       
 30970  * supports the principles behind the Model-View-Controller design pattern.
       
 30971  *
       
 30972  * MVC components in angular:
       
 30973  *
       
 30974  * * Model — Models are the properties of a scope; scopes are attached to the DOM where scope properties
       
 30975  *   are accessed through bindings.
       
 30976  * * View — The template (HTML with data bindings) that is rendered into the View.
       
 30977  * * Controller — The `ngController` directive specifies a Controller class; the class contains business
       
 30978  *   logic behind the application to decorate the scope with functions and values
       
 30979  *
       
 30980  * Note that you can also attach controllers to the DOM by declaring it in a route definition
       
 30981  * via the {@link ngRoute.$route $route} service. A common mistake is to declare the controller
       
 30982  * again using `ng-controller` in the template itself.  This will cause the controller to be attached
       
 30983  * and executed twice.
       
 30984  *
       
 30985  * @element ANY
       
 30986  * @scope
       
 30987  * @priority 500
       
 30988  * @param {expression} ngController Name of a constructor function registered with the current
       
 30989  * {@link ng.$controllerProvider $controllerProvider} or an {@link guide/expression expression}
       
 30990  * that on the current scope evaluates to a constructor function.
       
 30991  *
       
 30992  * The controller instance can be published into a scope property by specifying
       
 30993  * `ng-controller="as propertyName"`.
       
 30994  *
       
 30995  * If the current `$controllerProvider` is configured to use globals (via
       
 30996  * {@link ng.$controllerProvider#allowGlobals `$controllerProvider.allowGlobals()` }), this may
       
 30997  * also be the name of a globally accessible constructor function (not recommended).
       
 30998  *
       
 30999  * @example
       
 31000  * Here is a simple form for editing user contact information. Adding, removing, clearing, and
       
 31001  * greeting are methods declared on the controller (see source tab). These methods can
       
 31002  * easily be called from the angular markup. Any changes to the data are automatically reflected
       
 31003  * in the View without the need for a manual update.
       
 31004  *
       
 31005  * Two different declaration styles are included below:
       
 31006  *
       
 31007  * * one binds methods and properties directly onto the controller using `this`:
       
 31008  * `ng-controller="SettingsController1 as settings"`
       
 31009  * * one injects `$scope` into the controller:
       
 31010  * `ng-controller="SettingsController2"`
       
 31011  *
       
 31012  * The second option is more common in the Angular community, and is generally used in boilerplates
       
 31013  * and in this guide. However, there are advantages to binding properties directly to the controller
       
 31014  * and avoiding scope.
       
 31015  *
       
 31016  * * Using `controller as` makes it obvious which controller you are accessing in the template when
       
 31017  * multiple controllers apply to an element.
       
 31018  * * If you are writing your controllers as classes you have easier access to the properties and
       
 31019  * methods, which will appear on the scope, from inside the controller code.
       
 31020  * * Since there is always a `.` in the bindings, you don't have to worry about prototypal
       
 31021  * inheritance masking primitives.
       
 31022  *
       
 31023  * This example demonstrates the `controller as` syntax.
       
 31024  *
       
 31025  * <example name="ngControllerAs" module="controllerAsExample">
       
 31026  *   <file name="index.html">
       
 31027  *    <div id="ctrl-as-exmpl" ng-controller="SettingsController1 as settings">
       
 31028  *      Name: <input type="text" ng-model="settings.name"/>
       
 31029  *      [ <a href="" ng-click="settings.greet()">greet</a> ]<br/>
       
 31030  *      Contact:
       
 31031  *      <ul>
       
 31032  *        <li ng-repeat="contact in settings.contacts">
       
 31033  *          <select ng-model="contact.type">
       
 31034  *             <option>phone</option>
       
 31035  *             <option>email</option>
       
 31036  *          </select>
       
 31037  *          <input type="text" ng-model="contact.value"/>
       
 31038  *          [ <a href="" ng-click="settings.clearContact(contact)">clear</a>
       
 31039  *          | <a href="" ng-click="settings.removeContact(contact)">X</a> ]
       
 31040  *        </li>
       
 31041  *        <li>[ <a href="" ng-click="settings.addContact()">add</a> ]</li>
       
 31042  *     </ul>
       
 31043  *    </div>
       
 31044  *   </file>
       
 31045  *   <file name="app.js">
       
 31046  *    angular.module('controllerAsExample', [])
       
 31047  *      .controller('SettingsController1', SettingsController1);
       
 31048  *
       
 31049  *    function SettingsController1() {
       
 31050  *      this.name = "John Smith";
       
 31051  *      this.contacts = [
       
 31052  *        {type: 'phone', value: '408 555 1212'},
       
 31053  *        {type: 'email', value: 'john.smith@example.org'} ];
       
 31054  *    }
       
 31055  *
       
 31056  *    SettingsController1.prototype.greet = function() {
       
 31057  *      alert(this.name);
       
 31058  *    };
       
 31059  *
       
 31060  *    SettingsController1.prototype.addContact = function() {
       
 31061  *      this.contacts.push({type: 'email', value: 'yourname@example.org'});
       
 31062  *    };
       
 31063  *
       
 31064  *    SettingsController1.prototype.removeContact = function(contactToRemove) {
       
 31065  *     var index = this.contacts.indexOf(contactToRemove);
       
 31066  *      this.contacts.splice(index, 1);
       
 31067  *    };
       
 31068  *
       
 31069  *    SettingsController1.prototype.clearContact = function(contact) {
       
 31070  *      contact.type = 'phone';
       
 31071  *      contact.value = '';
       
 31072  *    };
       
 31073  *   </file>
       
 31074  *   <file name="protractor.js" type="protractor">
       
 31075  *     it('should check controller as', function() {
       
 31076  *       var container = element(by.id('ctrl-as-exmpl'));
       
 31077  *         expect(container.element(by.model('settings.name'))
       
 31078  *           .getAttribute('value')).toBe('John Smith');
       
 31079  *
       
 31080  *       var firstRepeat =
       
 31081  *           container.element(by.repeater('contact in settings.contacts').row(0));
       
 31082  *       var secondRepeat =
       
 31083  *           container.element(by.repeater('contact in settings.contacts').row(1));
       
 31084  *
       
 31085  *       expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
       
 31086  *           .toBe('408 555 1212');
       
 31087  *
       
 31088  *       expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
       
 31089  *           .toBe('john.smith@example.org');
       
 31090  *
       
 31091  *       firstRepeat.element(by.linkText('clear')).click();
       
 31092  *
       
 31093  *       expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
       
 31094  *           .toBe('');
       
 31095  *
       
 31096  *       container.element(by.linkText('add')).click();
       
 31097  *
       
 31098  *       expect(container.element(by.repeater('contact in settings.contacts').row(2))
       
 31099  *           .element(by.model('contact.value'))
       
 31100  *           .getAttribute('value'))
       
 31101  *           .toBe('yourname@example.org');
       
 31102  *     });
       
 31103  *   </file>
       
 31104  * </example>
       
 31105  *
       
 31106  * This example demonstrates the "attach to `$scope`" style of controller.
       
 31107  *
       
 31108  * <example name="ngController" module="controllerExample">
       
 31109  *  <file name="index.html">
       
 31110  *   <div id="ctrl-exmpl" ng-controller="SettingsController2">
       
 31111  *     Name: <input type="text" ng-model="name"/>
       
 31112  *     [ <a href="" ng-click="greet()">greet</a> ]<br/>
       
 31113  *     Contact:
       
 31114  *     <ul>
       
 31115  *       <li ng-repeat="contact in contacts">
       
 31116  *         <select ng-model="contact.type">
       
 31117  *            <option>phone</option>
       
 31118  *            <option>email</option>
       
 31119  *         </select>
       
 31120  *         <input type="text" ng-model="contact.value"/>
       
 31121  *         [ <a href="" ng-click="clearContact(contact)">clear</a>
       
 31122  *         | <a href="" ng-click="removeContact(contact)">X</a> ]
       
 31123  *       </li>
       
 31124  *       <li>[ <a href="" ng-click="addContact()">add</a> ]</li>
       
 31125  *    </ul>
       
 31126  *   </div>
       
 31127  *  </file>
       
 31128  *  <file name="app.js">
       
 31129  *   angular.module('controllerExample', [])
       
 31130  *     .controller('SettingsController2', ['$scope', SettingsController2]);
       
 31131  *
       
 31132  *   function SettingsController2($scope) {
       
 31133  *     $scope.name = "John Smith";
       
 31134  *     $scope.contacts = [
       
 31135  *       {type:'phone', value:'408 555 1212'},
       
 31136  *       {type:'email', value:'john.smith@example.org'} ];
       
 31137  *
       
 31138  *     $scope.greet = function() {
       
 31139  *       alert($scope.name);
       
 31140  *     };
       
 31141  *
       
 31142  *     $scope.addContact = function() {
       
 31143  *       $scope.contacts.push({type:'email', value:'yourname@example.org'});
       
 31144  *     };
       
 31145  *
       
 31146  *     $scope.removeContact = function(contactToRemove) {
       
 31147  *       var index = $scope.contacts.indexOf(contactToRemove);
       
 31148  *       $scope.contacts.splice(index, 1);
       
 31149  *     };
       
 31150  *
       
 31151  *     $scope.clearContact = function(contact) {
       
 31152  *       contact.type = 'phone';
       
 31153  *       contact.value = '';
       
 31154  *     };
       
 31155  *   }
       
 31156  *  </file>
       
 31157  *  <file name="protractor.js" type="protractor">
       
 31158  *    it('should check controller', function() {
       
 31159  *      var container = element(by.id('ctrl-exmpl'));
       
 31160  *
       
 31161  *      expect(container.element(by.model('name'))
       
 31162  *          .getAttribute('value')).toBe('John Smith');
       
 31163  *
       
 31164  *      var firstRepeat =
       
 31165  *          container.element(by.repeater('contact in contacts').row(0));
       
 31166  *      var secondRepeat =
       
 31167  *          container.element(by.repeater('contact in contacts').row(1));
       
 31168  *
       
 31169  *      expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
       
 31170  *          .toBe('408 555 1212');
       
 31171  *      expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
       
 31172  *          .toBe('john.smith@example.org');
       
 31173  *
       
 31174  *      firstRepeat.element(by.linkText('clear')).click();
       
 31175  *
       
 31176  *      expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
       
 31177  *          .toBe('');
       
 31178  *
       
 31179  *      container.element(by.linkText('add')).click();
       
 31180  *
       
 31181  *      expect(container.element(by.repeater('contact in contacts').row(2))
       
 31182  *          .element(by.model('contact.value'))
       
 31183  *          .getAttribute('value'))
       
 31184  *          .toBe('yourname@example.org');
       
 31185  *    });
       
 31186  *  </file>
       
 31187  *</example>
       
 31188 
       
 31189  */
       
 31190 var ngControllerDirective = [function() {
       
 31191   return {
       
 31192     restrict: 'A',
       
 31193     scope: true,
       
 31194     controller: '@',
       
 31195     priority: 500
       
 31196   };
       
 31197 }];
       
 31198 
       
 31199 /**
       
 31200  * @ngdoc directive
       
 31201  * @name ngCsp
       
 31202  *
       
 31203  * @element html
       
 31204  * @description
       
 31205  * Enables [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) support.
       
 31206  *
       
 31207  * This is necessary when developing things like Google Chrome Extensions.
       
 31208  *
       
 31209  * CSP forbids apps to use `eval` or `Function(string)` generated functions (among other things).
       
 31210  * For Angular to be CSP compatible there are only two things that we need to do differently:
       
 31211  *
       
 31212  * - don't use `Function` constructor to generate optimized value getters
       
 31213  * - don't inject custom stylesheet into the document
       
 31214  *
       
 31215  * AngularJS uses `Function(string)` generated functions as a speed optimization. Applying the `ngCsp`
       
 31216  * directive will cause Angular to use CSP compatibility mode. When this mode is on AngularJS will
       
 31217  * evaluate all expressions up to 30% slower than in non-CSP mode, but no security violations will
       
 31218  * be raised.
       
 31219  *
       
 31220  * CSP forbids JavaScript to inline stylesheet rules. In non CSP mode Angular automatically
       
 31221  * includes some CSS rules (e.g. {@link ng.directive:ngCloak ngCloak}).
       
 31222  * To make those directives work in CSP mode, include the `angular-csp.css` manually.
       
 31223  *
       
 31224  * Angular tries to autodetect if CSP is active and automatically turn on the CSP-safe mode. This
       
 31225  * autodetection however triggers a CSP error to be logged in the console:
       
 31226  *
       
 31227  * ```
       
 31228  * Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of
       
 31229  * script in the following Content Security Policy directive: "default-src 'self'". Note that
       
 31230  * 'script-src' was not explicitly set, so 'default-src' is used as a fallback.
       
 31231  * ```
       
 31232  *
       
 31233  * This error is harmless but annoying. To prevent the error from showing up, put the `ngCsp`
       
 31234  * directive on the root element of the application or on the `angular.js` script tag, whichever
       
 31235  * appears first in the html document.
       
 31236  *
       
 31237  * *Note: This directive is only available in the `ng-csp` and `data-ng-csp` attribute form.*
       
 31238  *
       
 31239  * @example
       
 31240  * This example shows how to apply the `ngCsp` directive to the `html` tag.
       
 31241    ```html
       
 31242      <!doctype html>
       
 31243      <html ng-app ng-csp>
       
 31244      ...
       
 31245      ...
       
 31246      </html>
       
 31247    ```
       
 31248   * @example
       
 31249       // Note: the suffix `.csp` in the example name triggers
       
 31250       // csp mode in our http server!
       
 31251       <example name="example.csp" module="cspExample" ng-csp="true">
       
 31252         <file name="index.html">
       
 31253           <div ng-controller="MainController as ctrl">
       
 31254             <div>
       
 31255               <button ng-click="ctrl.inc()" id="inc">Increment</button>
       
 31256               <span id="counter">
       
 31257                 {{ctrl.counter}}
       
 31258               </span>
       
 31259             </div>
       
 31260 
       
 31261             <div>
       
 31262               <button ng-click="ctrl.evil()" id="evil">Evil</button>
       
 31263               <span id="evilError">
       
 31264                 {{ctrl.evilError}}
       
 31265               </span>
       
 31266             </div>
       
 31267           </div>
       
 31268         </file>
       
 31269         <file name="script.js">
       
 31270            angular.module('cspExample', [])
       
 31271              .controller('MainController', function() {
       
 31272                 this.counter = 0;
       
 31273                 this.inc = function() {
       
 31274                   this.counter++;
       
 31275                 };
       
 31276                 this.evil = function() {
       
 31277                   // jshint evil:true
       
 31278                   try {
       
 31279                     eval('1+2');
       
 31280                   } catch (e) {
       
 31281                     this.evilError = e.message;
       
 31282                   }
       
 31283                 };
       
 31284               });
       
 31285         </file>
       
 31286         <file name="protractor.js" type="protractor">
       
 31287           var util, webdriver;
       
 31288 
       
 31289           var incBtn = element(by.id('inc'));
       
 31290           var counter = element(by.id('counter'));
       
 31291           var evilBtn = element(by.id('evil'));
       
 31292           var evilError = element(by.id('evilError'));
       
 31293 
       
 31294           function getAndClearSevereErrors() {
       
 31295             return browser.manage().logs().get('browser').then(function(browserLog) {
       
 31296               return browserLog.filter(function(logEntry) {
       
 31297                 return logEntry.level.value > webdriver.logging.Level.WARNING.value;
       
 31298               });
       
 31299             });
       
 31300           }
       
 31301 
       
 31302           function clearErrors() {
       
 31303             getAndClearSevereErrors();
       
 31304           }
       
 31305 
       
 31306           function expectNoErrors() {
       
 31307             getAndClearSevereErrors().then(function(filteredLog) {
       
 31308               expect(filteredLog.length).toEqual(0);
       
 31309               if (filteredLog.length) {
       
 31310                 console.log('browser console errors: ' + util.inspect(filteredLog));
       
 31311               }
       
 31312             });
       
 31313           }
       
 31314 
       
 31315           function expectError(regex) {
       
 31316             getAndClearSevereErrors().then(function(filteredLog) {
       
 31317               var found = false;
       
 31318               filteredLog.forEach(function(log) {
       
 31319                 if (log.message.match(regex)) {
       
 31320                   found = true;
       
 31321                 }
       
 31322               });
       
 31323               if (!found) {
       
 31324                 throw new Error('expected an error that matches ' + regex);
       
 31325               }
       
 31326             });
       
 31327           }
       
 31328 
       
 31329           beforeEach(function() {
       
 31330             util = require('util');
       
 31331             webdriver = require('protractor/node_modules/selenium-webdriver');
       
 31332           });
       
 31333 
       
 31334           // For now, we only test on Chrome,
       
 31335           // as Safari does not load the page with Protractor's injected scripts,
       
 31336           // and Firefox webdriver always disables content security policy (#6358)
       
 31337           if (browser.params.browser !== 'chrome') {
       
 31338             return;
       
 31339           }
       
 31340 
       
 31341           it('should not report errors when the page is loaded', function() {
       
 31342             // clear errors so we are not dependent on previous tests
       
 31343             clearErrors();
       
 31344             // Need to reload the page as the page is already loaded when
       
 31345             // we come here
       
 31346             browser.driver.getCurrentUrl().then(function(url) {
       
 31347               browser.get(url);
       
 31348             });
       
 31349             expectNoErrors();
       
 31350           });
       
 31351 
       
 31352           it('should evaluate expressions', function() {
       
 31353             expect(counter.getText()).toEqual('0');
       
 31354             incBtn.click();
       
 31355             expect(counter.getText()).toEqual('1');
       
 31356             expectNoErrors();
       
 31357           });
       
 31358 
       
 31359           it('should throw and report an error when using "eval"', function() {
       
 31360             evilBtn.click();
       
 31361             expect(evilError.getText()).toMatch(/Content Security Policy/);
       
 31362             expectError(/Content Security Policy/);
       
 31363           });
       
 31364         </file>
       
 31365       </example>
       
 31366   */
       
 31367 
       
 31368 // ngCsp is not implemented as a proper directive any more, because we need it be processed while we
       
 31369 // bootstrap the system (before $parse is instantiated), for this reason we just have
       
 31370 // the csp.isActive() fn that looks for ng-csp attribute anywhere in the current doc
       
 31371 
       
 31372 /**
       
 31373  * @ngdoc directive
       
 31374  * @name ngClick
       
 31375  *
       
 31376  * @description
       
 31377  * The ngClick directive allows you to specify custom behavior when
       
 31378  * an element is clicked.
       
 31379  *
       
 31380  * @element ANY
       
 31381  * @priority 0
       
 31382  * @param {expression} ngClick {@link guide/expression Expression} to evaluate upon
       
 31383  * click. ({@link guide/expression#-event- Event object is available as `$event`})
       
 31384  *
       
 31385  * @example
       
 31386    <example>
       
 31387      <file name="index.html">
       
 31388       <button ng-click="count = count + 1" ng-init="count=0">
       
 31389         Increment
       
 31390       </button>
       
 31391       <span>
       
 31392         count: {{count}}
       
 31393       </span>
       
 31394      </file>
       
 31395      <file name="protractor.js" type="protractor">
       
 31396        it('should check ng-click', function() {
       
 31397          expect(element(by.binding('count')).getText()).toMatch('0');
       
 31398          element(by.css('button')).click();
       
 31399          expect(element(by.binding('count')).getText()).toMatch('1');
       
 31400        });
       
 31401      </file>
       
 31402    </example>
       
 31403  */
       
 31404 /*
       
 31405  * A directive that allows creation of custom onclick handlers that are defined as angular
       
 31406  * expressions and are compiled and executed within the current scope.
       
 31407  *
       
 31408  * Events that are handled via these handler are always configured not to propagate further.
       
 31409  */
       
 31410 var ngEventDirectives = {};
       
 31411 
       
 31412 // For events that might fire synchronously during DOM manipulation
       
 31413 // we need to execute their event handlers asynchronously using $evalAsync,
       
 31414 // so that they are not executed in an inconsistent state.
       
 31415 var forceAsyncEvents = {
       
 31416   'blur': true,
       
 31417   'focus': true
       
 31418 };
       
 31419 forEach(
       
 31420   'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste'.split(' '),
       
 31421   function(eventName) {
       
 31422     var directiveName = directiveNormalize('ng-' + eventName);
       
 31423     ngEventDirectives[directiveName] = ['$parse', '$rootScope', function($parse, $rootScope) {
       
 31424       return {
       
 31425         restrict: 'A',
       
 31426         compile: function($element, attr) {
       
 31427           var fn = $parse(attr[directiveName]);
       
 31428           return function ngEventHandler(scope, element) {
       
 31429             element.on(eventName, function(event) {
       
 31430               var callback = function() {
       
 31431                 fn(scope, {$event:event});
       
 31432               };
       
 31433               if (forceAsyncEvents[eventName] && $rootScope.$$phase) {
       
 31434                 scope.$evalAsync(callback);
       
 31435               } else {
       
 31436                 scope.$apply(callback);
       
 31437               }
       
 31438             });
       
 31439           };
       
 31440         }
       
 31441       };
       
 31442     }];
       
 31443   }
       
 31444 );
       
 31445 
       
 31446 /**
       
 31447  * @ngdoc directive
       
 31448  * @name ngDblclick
       
 31449  *
       
 31450  * @description
       
 31451  * The `ngDblclick` directive allows you to specify custom behavior on a dblclick event.
       
 31452  *
       
 31453  * @element ANY
       
 31454  * @priority 0
       
 31455  * @param {expression} ngDblclick {@link guide/expression Expression} to evaluate upon
       
 31456  * a dblclick. (The Event object is available as `$event`)
       
 31457  *
       
 31458  * @example
       
 31459    <example>
       
 31460      <file name="index.html">
       
 31461       <button ng-dblclick="count = count + 1" ng-init="count=0">
       
 31462         Increment (on double click)
       
 31463       </button>
       
 31464       count: {{count}}
       
 31465      </file>
       
 31466    </example>
       
 31467  */
       
 31468 
       
 31469 
       
 31470 /**
       
 31471  * @ngdoc directive
       
 31472  * @name ngMousedown
       
 31473  *
       
 31474  * @description
       
 31475  * The ngMousedown directive allows you to specify custom behavior on mousedown event.
       
 31476  *
       
 31477  * @element ANY
       
 31478  * @priority 0
       
 31479  * @param {expression} ngMousedown {@link guide/expression Expression} to evaluate upon
       
 31480  * mousedown. ({@link guide/expression#-event- Event object is available as `$event`})
       
 31481  *
       
 31482  * @example
       
 31483    <example>
       
 31484      <file name="index.html">
       
 31485       <button ng-mousedown="count = count + 1" ng-init="count=0">
       
 31486         Increment (on mouse down)
       
 31487       </button>
       
 31488       count: {{count}}
       
 31489      </file>
       
 31490    </example>
       
 31491  */
       
 31492 
       
 31493 
       
 31494 /**
       
 31495  * @ngdoc directive
       
 31496  * @name ngMouseup
       
 31497  *
       
 31498  * @description
       
 31499  * Specify custom behavior on mouseup event.
       
 31500  *
       
 31501  * @element ANY
       
 31502  * @priority 0
       
 31503  * @param {expression} ngMouseup {@link guide/expression Expression} to evaluate upon
       
 31504  * mouseup. ({@link guide/expression#-event- Event object is available as `$event`})
       
 31505  *
       
 31506  * @example
       
 31507    <example>
       
 31508      <file name="index.html">
       
 31509       <button ng-mouseup="count = count + 1" ng-init="count=0">
       
 31510         Increment (on mouse up)
       
 31511       </button>
       
 31512       count: {{count}}
       
 31513      </file>
       
 31514    </example>
       
 31515  */
       
 31516 
       
 31517 /**
       
 31518  * @ngdoc directive
       
 31519  * @name ngMouseover
       
 31520  *
       
 31521  * @description
       
 31522  * Specify custom behavior on mouseover event.
       
 31523  *
       
 31524  * @element ANY
       
 31525  * @priority 0
       
 31526  * @param {expression} ngMouseover {@link guide/expression Expression} to evaluate upon
       
 31527  * mouseover. ({@link guide/expression#-event- Event object is available as `$event`})
       
 31528  *
       
 31529  * @example
       
 31530    <example>
       
 31531      <file name="index.html">
       
 31532       <button ng-mouseover="count = count + 1" ng-init="count=0">
       
 31533         Increment (when mouse is over)
       
 31534       </button>
       
 31535       count: {{count}}
       
 31536      </file>
       
 31537    </example>
       
 31538  */
       
 31539 
       
 31540 
       
 31541 /**
       
 31542  * @ngdoc directive
       
 31543  * @name ngMouseenter
       
 31544  *
       
 31545  * @description
       
 31546  * Specify custom behavior on mouseenter event.
       
 31547  *
       
 31548  * @element ANY
       
 31549  * @priority 0
       
 31550  * @param {expression} ngMouseenter {@link guide/expression Expression} to evaluate upon
       
 31551  * mouseenter. ({@link guide/expression#-event- Event object is available as `$event`})
       
 31552  *
       
 31553  * @example
       
 31554    <example>
       
 31555      <file name="index.html">
       
 31556       <button ng-mouseenter="count = count + 1" ng-init="count=0">
       
 31557         Increment (when mouse enters)
       
 31558       </button>
       
 31559       count: {{count}}
       
 31560      </file>
       
 31561    </example>
       
 31562  */
       
 31563 
       
 31564 
       
 31565 /**
       
 31566  * @ngdoc directive
       
 31567  * @name ngMouseleave
       
 31568  *
       
 31569  * @description
       
 31570  * Specify custom behavior on mouseleave event.
       
 31571  *
       
 31572  * @element ANY
       
 31573  * @priority 0
       
 31574  * @param {expression} ngMouseleave {@link guide/expression Expression} to evaluate upon
       
 31575  * mouseleave. ({@link guide/expression#-event- Event object is available as `$event`})
       
 31576  *
       
 31577  * @example
       
 31578    <example>
       
 31579      <file name="index.html">
       
 31580       <button ng-mouseleave="count = count + 1" ng-init="count=0">
       
 31581         Increment (when mouse leaves)
       
 31582       </button>
       
 31583       count: {{count}}
       
 31584      </file>
       
 31585    </example>
       
 31586  */
       
 31587 
       
 31588 
       
 31589 /**
       
 31590  * @ngdoc directive
       
 31591  * @name ngMousemove
       
 31592  *
       
 31593  * @description
       
 31594  * Specify custom behavior on mousemove event.
       
 31595  *
       
 31596  * @element ANY
       
 31597  * @priority 0
       
 31598  * @param {expression} ngMousemove {@link guide/expression Expression} to evaluate upon
       
 31599  * mousemove. ({@link guide/expression#-event- Event object is available as `$event`})
       
 31600  *
       
 31601  * @example
       
 31602    <example>
       
 31603      <file name="index.html">
       
 31604       <button ng-mousemove="count = count + 1" ng-init="count=0">
       
 31605         Increment (when mouse moves)
       
 31606       </button>
       
 31607       count: {{count}}
       
 31608      </file>
       
 31609    </example>
       
 31610  */
       
 31611 
       
 31612 
       
 31613 /**
       
 31614  * @ngdoc directive
       
 31615  * @name ngKeydown
       
 31616  *
       
 31617  * @description
       
 31618  * Specify custom behavior on keydown event.
       
 31619  *
       
 31620  * @element ANY
       
 31621  * @priority 0
       
 31622  * @param {expression} ngKeydown {@link guide/expression Expression} to evaluate upon
       
 31623  * keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
       
 31624  *
       
 31625  * @example
       
 31626    <example>
       
 31627      <file name="index.html">
       
 31628       <input ng-keydown="count = count + 1" ng-init="count=0">
       
 31629       key down count: {{count}}
       
 31630      </file>
       
 31631    </example>
       
 31632  */
       
 31633 
       
 31634 
       
 31635 /**
       
 31636  * @ngdoc directive
       
 31637  * @name ngKeyup
       
 31638  *
       
 31639  * @description
       
 31640  * Specify custom behavior on keyup event.
       
 31641  *
       
 31642  * @element ANY
       
 31643  * @priority 0
       
 31644  * @param {expression} ngKeyup {@link guide/expression Expression} to evaluate upon
       
 31645  * keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
       
 31646  *
       
 31647  * @example
       
 31648    <example>
       
 31649      <file name="index.html">
       
 31650        <p>Typing in the input box below updates the key count</p>
       
 31651        <input ng-keyup="count = count + 1" ng-init="count=0"> key up count: {{count}}
       
 31652 
       
 31653        <p>Typing in the input box below updates the keycode</p>
       
 31654        <input ng-keyup="event=$event">
       
 31655        <p>event keyCode: {{ event.keyCode }}</p>
       
 31656        <p>event altKey: {{ event.altKey }}</p>
       
 31657      </file>
       
 31658    </example>
       
 31659  */
       
 31660 
       
 31661 
       
 31662 /**
       
 31663  * @ngdoc directive
       
 31664  * @name ngKeypress
       
 31665  *
       
 31666  * @description
       
 31667  * Specify custom behavior on keypress event.
       
 31668  *
       
 31669  * @element ANY
       
 31670  * @param {expression} ngKeypress {@link guide/expression Expression} to evaluate upon
       
 31671  * keypress. ({@link guide/expression#-event- Event object is available as `$event`}
       
 31672  * and can be interrogated for keyCode, altKey, etc.)
       
 31673  *
       
 31674  * @example
       
 31675    <example>
       
 31676      <file name="index.html">
       
 31677       <input ng-keypress="count = count + 1" ng-init="count=0">
       
 31678       key press count: {{count}}
       
 31679      </file>
       
 31680    </example>
       
 31681  */
       
 31682 
       
 31683 
       
 31684 /**
       
 31685  * @ngdoc directive
       
 31686  * @name ngSubmit
       
 31687  *
       
 31688  * @description
       
 31689  * Enables binding angular expressions to onsubmit events.
       
 31690  *
       
 31691  * Additionally it prevents the default action (which for form means sending the request to the
       
 31692  * server and reloading the current page), but only if the form does not contain `action`,
       
 31693  * `data-action`, or `x-action` attributes.
       
 31694  *
       
 31695  * <div class="alert alert-warning">
       
 31696  * **Warning:** Be careful not to cause "double-submission" by using both the `ngClick` and
       
 31697  * `ngSubmit` handlers together. See the
       
 31698  * {@link form#submitting-a-form-and-preventing-the-default-action `form` directive documentation}
       
 31699  * for a detailed discussion of when `ngSubmit` may be triggered.
       
 31700  * </div>
       
 31701  *
       
 31702  * @element form
       
 31703  * @priority 0
       
 31704  * @param {expression} ngSubmit {@link guide/expression Expression} to eval.
       
 31705  * ({@link guide/expression#-event- Event object is available as `$event`})
       
 31706  *
       
 31707  * @example
       
 31708    <example module="submitExample">
       
 31709      <file name="index.html">
       
 31710       <script>
       
 31711         angular.module('submitExample', [])
       
 31712           .controller('ExampleController', ['$scope', function($scope) {
       
 31713             $scope.list = [];
       
 31714             $scope.text = 'hello';
       
 31715             $scope.submit = function() {
       
 31716               if ($scope.text) {
       
 31717                 $scope.list.push(this.text);
       
 31718                 $scope.text = '';
       
 31719               }
       
 31720             };
       
 31721           }]);
       
 31722       </script>
       
 31723       <form ng-submit="submit()" ng-controller="ExampleController">
       
 31724         Enter text and hit enter:
       
 31725         <input type="text" ng-model="text" name="text" />
       
 31726         <input type="submit" id="submit" value="Submit" />
       
 31727         <pre>list={{list}}</pre>
       
 31728       </form>
       
 31729      </file>
       
 31730      <file name="protractor.js" type="protractor">
       
 31731        it('should check ng-submit', function() {
       
 31732          expect(element(by.binding('list')).getText()).toBe('list=[]');
       
 31733          element(by.css('#submit')).click();
       
 31734          expect(element(by.binding('list')).getText()).toContain('hello');
       
 31735          expect(element(by.model('text')).getAttribute('value')).toBe('');
       
 31736        });
       
 31737        it('should ignore empty strings', function() {
       
 31738          expect(element(by.binding('list')).getText()).toBe('list=[]');
       
 31739          element(by.css('#submit')).click();
       
 31740          element(by.css('#submit')).click();
       
 31741          expect(element(by.binding('list')).getText()).toContain('hello');
       
 31742         });
       
 31743      </file>
       
 31744    </example>
       
 31745  */
       
 31746 
       
 31747 /**
       
 31748  * @ngdoc directive
       
 31749  * @name ngFocus
       
 31750  *
       
 31751  * @description
       
 31752  * Specify custom behavior on focus event.
       
 31753  *
       
 31754  * Note: As the `focus` event is executed synchronously when calling `input.focus()`
       
 31755  * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
       
 31756  * during an `$apply` to ensure a consistent state.
       
 31757  *
       
 31758  * @element window, input, select, textarea, a
       
 31759  * @priority 0
       
 31760  * @param {expression} ngFocus {@link guide/expression Expression} to evaluate upon
       
 31761  * focus. ({@link guide/expression#-event- Event object is available as `$event`})
       
 31762  *
       
 31763  * @example
       
 31764  * See {@link ng.directive:ngClick ngClick}
       
 31765  */
       
 31766 
       
 31767 /**
       
 31768  * @ngdoc directive
       
 31769  * @name ngBlur
       
 31770  *
       
 31771  * @description
       
 31772  * Specify custom behavior on blur event.
       
 31773  *
       
 31774  * A [blur event](https://developer.mozilla.org/en-US/docs/Web/Events/blur) fires when
       
 31775  * an element has lost focus.
       
 31776  *
       
 31777  * Note: As the `blur` event is executed synchronously also during DOM manipulations
       
 31778  * (e.g. removing a focussed input),
       
 31779  * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
       
 31780  * during an `$apply` to ensure a consistent state.
       
 31781  *
       
 31782  * @element window, input, select, textarea, a
       
 31783  * @priority 0
       
 31784  * @param {expression} ngBlur {@link guide/expression Expression} to evaluate upon
       
 31785  * blur. ({@link guide/expression#-event- Event object is available as `$event`})
       
 31786  *
       
 31787  * @example
       
 31788  * See {@link ng.directive:ngClick ngClick}
       
 31789  */
       
 31790 
       
 31791 /**
       
 31792  * @ngdoc directive
       
 31793  * @name ngCopy
       
 31794  *
       
 31795  * @description
       
 31796  * Specify custom behavior on copy event.
       
 31797  *
       
 31798  * @element window, input, select, textarea, a
       
 31799  * @priority 0
       
 31800  * @param {expression} ngCopy {@link guide/expression Expression} to evaluate upon
       
 31801  * copy. ({@link guide/expression#-event- Event object is available as `$event`})
       
 31802  *
       
 31803  * @example
       
 31804    <example>
       
 31805      <file name="index.html">
       
 31806       <input ng-copy="copied=true" ng-init="copied=false; value='copy me'" ng-model="value">
       
 31807       copied: {{copied}}
       
 31808      </file>
       
 31809    </example>
       
 31810  */
       
 31811 
       
 31812 /**
       
 31813  * @ngdoc directive
       
 31814  * @name ngCut
       
 31815  *
       
 31816  * @description
       
 31817  * Specify custom behavior on cut event.
       
 31818  *
       
 31819  * @element window, input, select, textarea, a
       
 31820  * @priority 0
       
 31821  * @param {expression} ngCut {@link guide/expression Expression} to evaluate upon
       
 31822  * cut. ({@link guide/expression#-event- Event object is available as `$event`})
       
 31823  *
       
 31824  * @example
       
 31825    <example>
       
 31826      <file name="index.html">
       
 31827       <input ng-cut="cut=true" ng-init="cut=false; value='cut me'" ng-model="value">
       
 31828       cut: {{cut}}
       
 31829      </file>
       
 31830    </example>
       
 31831  */
       
 31832 
       
 31833 /**
       
 31834  * @ngdoc directive
       
 31835  * @name ngPaste
       
 31836  *
       
 31837  * @description
       
 31838  * Specify custom behavior on paste event.
       
 31839  *
       
 31840  * @element window, input, select, textarea, a
       
 31841  * @priority 0
       
 31842  * @param {expression} ngPaste {@link guide/expression Expression} to evaluate upon
       
 31843  * paste. ({@link guide/expression#-event- Event object is available as `$event`})
       
 31844  *
       
 31845  * @example
       
 31846    <example>
       
 31847      <file name="index.html">
       
 31848       <input ng-paste="paste=true" ng-init="paste=false" placeholder='paste here'>
       
 31849       pasted: {{paste}}
       
 31850      </file>
       
 31851    </example>
       
 31852  */
       
 31853 
       
 31854 /**
       
 31855  * @ngdoc directive
       
 31856  * @name ngIf
       
 31857  * @restrict A
       
 31858  *
       
 31859  * @description
       
 31860  * The `ngIf` directive removes or recreates a portion of the DOM tree based on an
       
 31861  * {expression}. If the expression assigned to `ngIf` evaluates to a false
       
 31862  * value then the element is removed from the DOM, otherwise a clone of the
       
 31863  * element is reinserted into the DOM.
       
 31864  *
       
 31865  * `ngIf` differs from `ngShow` and `ngHide` in that `ngIf` completely removes and recreates the
       
 31866  * element in the DOM rather than changing its visibility via the `display` css property.  A common
       
 31867  * case when this difference is significant is when using css selectors that rely on an element's
       
 31868  * position within the DOM, such as the `:first-child` or `:last-child` pseudo-classes.
       
 31869  *
       
 31870  * Note that when an element is removed using `ngIf` its scope is destroyed and a new scope
       
 31871  * is created when the element is restored.  The scope created within `ngIf` inherits from
       
 31872  * its parent scope using
       
 31873  * [prototypal inheritance](https://github.com/angular/angular.js/wiki/Understanding-Scopes#javascript-prototypal-inheritance).
       
 31874  * An important implication of this is if `ngModel` is used within `ngIf` to bind to
       
 31875  * a javascript primitive defined in the parent scope. In this case any modifications made to the
       
 31876  * variable within the child scope will override (hide) the value in the parent scope.
       
 31877  *
       
 31878  * Also, `ngIf` recreates elements using their compiled state. An example of this behavior
       
 31879  * is if an element's class attribute is directly modified after it's compiled, using something like
       
 31880  * jQuery's `.addClass()` method, and the element is later removed. When `ngIf` recreates the element
       
 31881  * the added class will be lost because the original compiled state is used to regenerate the element.
       
 31882  *
       
 31883  * Additionally, you can provide animations via the `ngAnimate` module to animate the `enter`
       
 31884  * and `leave` effects.
       
 31885  *
       
 31886  * @animations
       
 31887  * enter - happens just after the `ngIf` contents change and a new DOM element is created and injected into the `ngIf` container
       
 31888  * leave - happens just before the `ngIf` contents are removed from the DOM
       
 31889  *
       
 31890  * @element ANY
       
 31891  * @scope
       
 31892  * @priority 600
       
 31893  * @param {expression} ngIf If the {@link guide/expression expression} is falsy then
       
 31894  *     the element is removed from the DOM tree. If it is truthy a copy of the compiled
       
 31895  *     element is added to the DOM tree.
       
 31896  *
       
 31897  * @example
       
 31898   <example module="ngAnimate" deps="angular-animate.js" animations="true">
       
 31899     <file name="index.html">
       
 31900       Click me: <input type="checkbox" ng-model="checked" ng-init="checked=true" /><br/>
       
 31901       Show when checked:
       
 31902       <span ng-if="checked" class="animate-if">
       
 31903         I'm removed when the checkbox is unchecked.
       
 31904       </span>
       
 31905     </file>
       
 31906     <file name="animations.css">
       
 31907       .animate-if {
       
 31908         background:white;
       
 31909         border:1px solid black;
       
 31910         padding:10px;
       
 31911       }
       
 31912 
       
 31913       .animate-if.ng-enter, .animate-if.ng-leave {
       
 31914         -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
       
 31915         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
       
 31916       }
       
 31917 
       
 31918       .animate-if.ng-enter,
       
 31919       .animate-if.ng-leave.ng-leave-active {
       
 31920         opacity:0;
       
 31921       }
       
 31922 
       
 31923       .animate-if.ng-leave,
       
 31924       .animate-if.ng-enter.ng-enter-active {
       
 31925         opacity:1;
       
 31926       }
       
 31927     </file>
       
 31928   </example>
       
 31929  */
       
 31930 var ngIfDirective = ['$animate', function($animate) {
       
 31931   return {
       
 31932     multiElement: true,
       
 31933     transclude: 'element',
       
 31934     priority: 600,
       
 31935     terminal: true,
       
 31936     restrict: 'A',
       
 31937     $$tlb: true,
       
 31938     link: function ($scope, $element, $attr, ctrl, $transclude) {
       
 31939         var block, childScope, previousElements;
       
 31940         $scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
       
 31941 
       
 31942           if (value) {
       
 31943             if (!childScope) {
       
 31944               $transclude(function (clone, newScope) {
       
 31945                 childScope = newScope;
       
 31946                 clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ');
       
 31947                 // Note: We only need the first/last node of the cloned nodes.
       
 31948                 // However, we need to keep the reference to the jqlite wrapper as it might be changed later
       
 31949                 // by a directive with templateUrl when its template arrives.
       
 31950                 block = {
       
 31951                   clone: clone
       
 31952                 };
       
 31953                 $animate.enter(clone, $element.parent(), $element);
       
 31954               });
       
 31955             }
       
 31956           } else {
       
 31957             if(previousElements) {
       
 31958               previousElements.remove();
       
 31959               previousElements = null;
       
 31960             }
       
 31961             if(childScope) {
       
 31962               childScope.$destroy();
       
 31963               childScope = null;
       
 31964             }
       
 31965             if(block) {
       
 31966               previousElements = getBlockNodes(block.clone);
       
 31967               $animate.leave(previousElements).then(function() {
       
 31968                 previousElements = null;
       
 31969               });
       
 31970               block = null;
       
 31971             }
       
 31972           }
       
 31973         });
       
 31974     }
       
 31975   };
       
 31976 }];
       
 31977 
       
 31978 /**
       
 31979  * @ngdoc directive
       
 31980  * @name ngInclude
       
 31981  * @restrict ECA
       
 31982  *
       
 31983  * @description
       
 31984  * Fetches, compiles and includes an external HTML fragment.
       
 31985  *
       
 31986  * By default, the template URL is restricted to the same domain and protocol as the
       
 31987  * application document. This is done by calling {@link ng.$sce#getTrustedResourceUrl
       
 31988  * $sce.getTrustedResourceUrl} on it. To load templates from other domains or protocols
       
 31989  * you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist them} or
       
 31990  * [wrap them](ng.$sce#trustAsResourceUrl) as trusted values. Refer to Angular's {@link
       
 31991  * ng.$sce Strict Contextual Escaping}.
       
 31992  *
       
 31993  * In addition, the browser's
       
 31994  * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
       
 31995  * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
       
 31996  * policy may further restrict whether the template is successfully loaded.
       
 31997  * For example, `ngInclude` won't work for cross-domain requests on all browsers and for `file://`
       
 31998  * access on some browsers.
       
 31999  *
       
 32000  * @animations
       
 32001  * enter - animation is used to bring new content into the browser.
       
 32002  * leave - animation is used to animate existing content away.
       
 32003  *
       
 32004  * The enter and leave animation occur concurrently.
       
 32005  *
       
 32006  * @scope
       
 32007  * @priority 400
       
 32008  *
       
 32009  * @param {string} ngInclude|src angular expression evaluating to URL. If the source is a string constant,
       
 32010  *                 make sure you wrap it in **single** quotes, e.g. `src="'myPartialTemplate.html'"`.
       
 32011  * @param {string=} onload Expression to evaluate when a new partial is loaded.
       
 32012  *
       
 32013  * @param {string=} autoscroll Whether `ngInclude` should call {@link ng.$anchorScroll
       
 32014  *                  $anchorScroll} to scroll the viewport after the content is loaded.
       
 32015  *
       
 32016  *                  - If the attribute is not set, disable scrolling.
       
 32017  *                  - If the attribute is set without value, enable scrolling.
       
 32018  *                  - Otherwise enable scrolling only if the expression evaluates to truthy value.
       
 32019  *
       
 32020  * @example
       
 32021   <example module="includeExample" deps="angular-animate.js" animations="true">
       
 32022     <file name="index.html">
       
 32023      <div ng-controller="ExampleController">
       
 32024        <select ng-model="template" ng-options="t.name for t in templates">
       
 32025         <option value="">(blank)</option>
       
 32026        </select>
       
 32027        url of the template: <tt>{{template.url}}</tt>
       
 32028        <hr/>
       
 32029        <div class="slide-animate-container">
       
 32030          <div class="slide-animate" ng-include="template.url"></div>
       
 32031        </div>
       
 32032      </div>
       
 32033     </file>
       
 32034     <file name="script.js">
       
 32035       angular.module('includeExample', ['ngAnimate'])
       
 32036         .controller('ExampleController', ['$scope', function($scope) {
       
 32037           $scope.templates =
       
 32038             [ { name: 'template1.html', url: 'template1.html'},
       
 32039               { name: 'template2.html', url: 'template2.html'} ];
       
 32040           $scope.template = $scope.templates[0];
       
 32041         }]);
       
 32042      </file>
       
 32043     <file name="template1.html">
       
 32044       Content of template1.html
       
 32045     </file>
       
 32046     <file name="template2.html">
       
 32047       Content of template2.html
       
 32048     </file>
       
 32049     <file name="animations.css">
       
 32050       .slide-animate-container {
       
 32051         position:relative;
       
 32052         background:white;
       
 32053         border:1px solid black;
       
 32054         height:40px;
       
 32055         overflow:hidden;
       
 32056       }
       
 32057 
       
 32058       .slide-animate {
       
 32059         padding:10px;
       
 32060       }
       
 32061 
       
 32062       .slide-animate.ng-enter, .slide-animate.ng-leave {
       
 32063         -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
       
 32064         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
       
 32065 
       
 32066         position:absolute;
       
 32067         top:0;
       
 32068         left:0;
       
 32069         right:0;
       
 32070         bottom:0;
       
 32071         display:block;
       
 32072         padding:10px;
       
 32073       }
       
 32074 
       
 32075       .slide-animate.ng-enter {
       
 32076         top:-50px;
       
 32077       }
       
 32078       .slide-animate.ng-enter.ng-enter-active {
       
 32079         top:0;
       
 32080       }
       
 32081 
       
 32082       .slide-animate.ng-leave {
       
 32083         top:0;
       
 32084       }
       
 32085       .slide-animate.ng-leave.ng-leave-active {
       
 32086         top:50px;
       
 32087       }
       
 32088     </file>
       
 32089     <file name="protractor.js" type="protractor">
       
 32090       var templateSelect = element(by.model('template'));
       
 32091       var includeElem = element(by.css('[ng-include]'));
       
 32092 
       
 32093       it('should load template1.html', function() {
       
 32094         expect(includeElem.getText()).toMatch(/Content of template1.html/);
       
 32095       });
       
 32096 
       
 32097       it('should load template2.html', function() {
       
 32098         if (browser.params.browser == 'firefox') {
       
 32099           // Firefox can't handle using selects
       
 32100           // See https://github.com/angular/protractor/issues/480
       
 32101           return;
       
 32102         }
       
 32103         templateSelect.click();
       
 32104         templateSelect.all(by.css('option')).get(2).click();
       
 32105         expect(includeElem.getText()).toMatch(/Content of template2.html/);
       
 32106       });
       
 32107 
       
 32108       it('should change to blank', function() {
       
 32109         if (browser.params.browser == 'firefox') {
       
 32110           // Firefox can't handle using selects
       
 32111           return;
       
 32112         }
       
 32113         templateSelect.click();
       
 32114         templateSelect.all(by.css('option')).get(0).click();
       
 32115         expect(includeElem.isPresent()).toBe(false);
       
 32116       });
       
 32117     </file>
       
 32118   </example>
       
 32119  */
       
 32120 
       
 32121 
       
 32122 /**
       
 32123  * @ngdoc event
       
 32124  * @name ngInclude#$includeContentRequested
       
 32125  * @eventType emit on the scope ngInclude was declared in
       
 32126  * @description
       
 32127  * Emitted every time the ngInclude content is requested.
       
 32128  *
       
 32129  * @param {Object} angularEvent Synthetic event object.
       
 32130  * @param {String} src URL of content to load.
       
 32131  */
       
 32132 
       
 32133 
       
 32134 /**
       
 32135  * @ngdoc event
       
 32136  * @name ngInclude#$includeContentLoaded
       
 32137  * @eventType emit on the current ngInclude scope
       
 32138  * @description
       
 32139  * Emitted every time the ngInclude content is reloaded.
       
 32140  *
       
 32141  * @param {Object} angularEvent Synthetic event object.
       
 32142  * @param {String} src URL of content to load.
       
 32143  */
       
 32144 
       
 32145 
       
 32146 /**
       
 32147  * @ngdoc event
       
 32148  * @name ngInclude#$includeContentError
       
 32149  * @eventType emit on the scope ngInclude was declared in
       
 32150  * @description
       
 32151  * Emitted when a template HTTP request yields an erronous response (status < 200 || status > 299)
       
 32152  *
       
 32153  * @param {Object} angularEvent Synthetic event object.
       
 32154  * @param {String} src URL of content to load.
       
 32155  */
       
 32156 var ngIncludeDirective = ['$templateRequest', '$anchorScroll', '$animate', '$sce',
       
 32157                   function($templateRequest,   $anchorScroll,   $animate,   $sce) {
       
 32158   return {
       
 32159     restrict: 'ECA',
       
 32160     priority: 400,
       
 32161     terminal: true,
       
 32162     transclude: 'element',
       
 32163     controller: angular.noop,
       
 32164     compile: function(element, attr) {
       
 32165       var srcExp = attr.ngInclude || attr.src,
       
 32166           onloadExp = attr.onload || '',
       
 32167           autoScrollExp = attr.autoscroll;
       
 32168 
       
 32169       return function(scope, $element, $attr, ctrl, $transclude) {
       
 32170         var changeCounter = 0,
       
 32171             currentScope,
       
 32172             previousElement,
       
 32173             currentElement;
       
 32174 
       
 32175         var cleanupLastIncludeContent = function() {
       
 32176           if(previousElement) {
       
 32177             previousElement.remove();
       
 32178             previousElement = null;
       
 32179           }
       
 32180           if(currentScope) {
       
 32181             currentScope.$destroy();
       
 32182             currentScope = null;
       
 32183           }
       
 32184           if(currentElement) {
       
 32185             $animate.leave(currentElement).then(function() {
       
 32186               previousElement = null;
       
 32187             });
       
 32188             previousElement = currentElement;
       
 32189             currentElement = null;
       
 32190           }
       
 32191         };
       
 32192 
       
 32193         scope.$watch($sce.parseAsResourceUrl(srcExp), function ngIncludeWatchAction(src) {
       
 32194           var afterAnimation = function() {
       
 32195             if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) {
       
 32196               $anchorScroll();
       
 32197             }
       
 32198           };
       
 32199           var thisChangeId = ++changeCounter;
       
 32200 
       
 32201           if (src) {
       
 32202             //set the 2nd param to true to ignore the template request error so that the inner
       
 32203             //contents and scope can be cleaned up.
       
 32204             $templateRequest(src, true).then(function(response) {
       
 32205               if (thisChangeId !== changeCounter) return;
       
 32206               var newScope = scope.$new();
       
 32207               ctrl.template = response;
       
 32208 
       
 32209               // Note: This will also link all children of ng-include that were contained in the original
       
 32210               // html. If that content contains controllers, ... they could pollute/change the scope.
       
 32211               // However, using ng-include on an element with additional content does not make sense...
       
 32212               // Note: We can't remove them in the cloneAttchFn of $transclude as that
       
 32213               // function is called before linking the content, which would apply child
       
 32214               // directives to non existing elements.
       
 32215               var clone = $transclude(newScope, function(clone) {
       
 32216                 cleanupLastIncludeContent();
       
 32217                 $animate.enter(clone, null, $element).then(afterAnimation);
       
 32218               });
       
 32219 
       
 32220               currentScope = newScope;
       
 32221               currentElement = clone;
       
 32222 
       
 32223               currentScope.$emit('$includeContentLoaded', src);
       
 32224               scope.$eval(onloadExp);
       
 32225             }, function() {
       
 32226               if (thisChangeId === changeCounter) {
       
 32227                 cleanupLastIncludeContent();
       
 32228                 scope.$emit('$includeContentError', src);
       
 32229               }
       
 32230             });
       
 32231             scope.$emit('$includeContentRequested', src);
       
 32232           } else {
       
 32233             cleanupLastIncludeContent();
       
 32234             ctrl.template = null;
       
 32235           }
       
 32236         });
       
 32237       };
       
 32238     }
       
 32239   };
       
 32240 }];
       
 32241 
       
 32242 // This directive is called during the $transclude call of the first `ngInclude` directive.
       
 32243 // It will replace and compile the content of the element with the loaded template.
       
 32244 // We need this directive so that the element content is already filled when
       
 32245 // the link function of another directive on the same element as ngInclude
       
 32246 // is called.
       
 32247 var ngIncludeFillContentDirective = ['$compile',
       
 32248   function($compile) {
       
 32249     return {
       
 32250       restrict: 'ECA',
       
 32251       priority: -400,
       
 32252       require: 'ngInclude',
       
 32253       link: function(scope, $element, $attr, ctrl) {
       
 32254         if (/SVG/.test($element[0].toString())) {
       
 32255           // WebKit: https://bugs.webkit.org/show_bug.cgi?id=135698 --- SVG elements do not
       
 32256           // support innerHTML, so detect this here and try to generate the contents
       
 32257           // specially.
       
 32258           $element.empty();
       
 32259           $compile(jqLiteBuildFragment(ctrl.template, document).childNodes)(scope,
       
 32260               function namespaceAdaptedClone(clone) {
       
 32261             $element.append(clone);
       
 32262           }, undefined, undefined, $element);
       
 32263           return;
       
 32264         }
       
 32265 
       
 32266         $element.html(ctrl.template);
       
 32267         $compile($element.contents())(scope);
       
 32268       }
       
 32269     };
       
 32270   }];
       
 32271 
       
 32272 /**
       
 32273  * @ngdoc directive
       
 32274  * @name ngInit
       
 32275  * @restrict AC
       
 32276  *
       
 32277  * @description
       
 32278  * The `ngInit` directive allows you to evaluate an expression in the
       
 32279  * current scope.
       
 32280  *
       
 32281  * <div class="alert alert-error">
       
 32282  * The only appropriate use of `ngInit` is for aliasing special properties of
       
 32283  * {@link ng.directive:ngRepeat `ngRepeat`}, as seen in the demo below. Besides this case, you
       
 32284  * should use {@link guide/controller controllers} rather than `ngInit`
       
 32285  * to initialize values on a scope.
       
 32286  * </div>
       
 32287  * <div class="alert alert-warning">
       
 32288  * **Note**: If you have assignment in `ngInit` along with {@link ng.$filter `$filter`}, make
       
 32289  * sure you have parenthesis for correct precedence:
       
 32290  * <pre class="prettyprint">
       
 32291  *   <div ng-init="test1 = (data | orderBy:'name')"></div>
       
 32292  * </pre>
       
 32293  * </div>
       
 32294  *
       
 32295  * @priority 450
       
 32296  *
       
 32297  * @element ANY
       
 32298  * @param {expression} ngInit {@link guide/expression Expression} to eval.
       
 32299  *
       
 32300  * @example
       
 32301    <example module="initExample">
       
 32302      <file name="index.html">
       
 32303    <script>
       
 32304      angular.module('initExample', [])
       
 32305        .controller('ExampleController', ['$scope', function($scope) {
       
 32306          $scope.list = [['a', 'b'], ['c', 'd']];
       
 32307        }]);
       
 32308    </script>
       
 32309    <div ng-controller="ExampleController">
       
 32310      <div ng-repeat="innerList in list" ng-init="outerIndex = $index">
       
 32311        <div ng-repeat="value in innerList" ng-init="innerIndex = $index">
       
 32312           <span class="example-init">list[ {{outerIndex}} ][ {{innerIndex}} ] = {{value}};</span>
       
 32313        </div>
       
 32314      </div>
       
 32315    </div>
       
 32316      </file>
       
 32317      <file name="protractor.js" type="protractor">
       
 32318        it('should alias index positions', function() {
       
 32319          var elements = element.all(by.css('.example-init'));
       
 32320          expect(elements.get(0).getText()).toBe('list[ 0 ][ 0 ] = a;');
       
 32321          expect(elements.get(1).getText()).toBe('list[ 0 ][ 1 ] = b;');
       
 32322          expect(elements.get(2).getText()).toBe('list[ 1 ][ 0 ] = c;');
       
 32323          expect(elements.get(3).getText()).toBe('list[ 1 ][ 1 ] = d;');
       
 32324        });
       
 32325      </file>
       
 32326    </example>
       
 32327  */
       
 32328 var ngInitDirective = ngDirective({
       
 32329   priority: 450,
       
 32330   compile: function() {
       
 32331     return {
       
 32332       pre: function(scope, element, attrs) {
       
 32333         scope.$eval(attrs.ngInit);
       
 32334       }
       
 32335     };
       
 32336   }
       
 32337 });
       
 32338 
       
 32339 /**
       
 32340  * @ngdoc directive
       
 32341  * @name ngNonBindable
       
 32342  * @restrict AC
       
 32343  * @priority 1000
       
 32344  *
       
 32345  * @description
       
 32346  * The `ngNonBindable` directive tells Angular not to compile or bind the contents of the current
       
 32347  * DOM element. This is useful if the element contains what appears to be Angular directives and
       
 32348  * bindings but which should be ignored by Angular. This could be the case if you have a site that
       
 32349  * displays snippets of code, for instance.
       
 32350  *
       
 32351  * @element ANY
       
 32352  *
       
 32353  * @example
       
 32354  * In this example there are two locations where a simple interpolation binding (`{{}}`) is present,
       
 32355  * but the one wrapped in `ngNonBindable` is left alone.
       
 32356  *
       
 32357  * @example
       
 32358     <example>
       
 32359       <file name="index.html">
       
 32360         <div>Normal: {{1 + 2}}</div>
       
 32361         <div ng-non-bindable>Ignored: {{1 + 2}}</div>
       
 32362       </file>
       
 32363       <file name="protractor.js" type="protractor">
       
 32364        it('should check ng-non-bindable', function() {
       
 32365          expect(element(by.binding('1 + 2')).getText()).toContain('3');
       
 32366          expect(element.all(by.css('div')).last().getText()).toMatch(/1 \+ 2/);
       
 32367        });
       
 32368       </file>
       
 32369     </example>
       
 32370  */
       
 32371 var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
       
 32372 
       
 32373 /**
       
 32374  * @ngdoc directive
       
 32375  * @name ngPluralize
       
 32376  * @restrict EA
       
 32377  *
       
 32378  * @description
       
 32379  * `ngPluralize` is a directive that displays messages according to en-US localization rules.
       
 32380  * These rules are bundled with angular.js, but can be overridden
       
 32381  * (see {@link guide/i18n Angular i18n} dev guide). You configure ngPluralize directive
       
 32382  * by specifying the mappings between
       
 32383  * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
       
 32384  * and the strings to be displayed.
       
 32385  *
       
 32386  * # Plural categories and explicit number rules
       
 32387  * There are two
       
 32388  * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
       
 32389  * in Angular's default en-US locale: "one" and "other".
       
 32390  *
       
 32391  * While a plural category may match many numbers (for example, in en-US locale, "other" can match
       
 32392  * any number that is not 1), an explicit number rule can only match one number. For example, the
       
 32393  * explicit number rule for "3" matches the number 3. There are examples of plural categories
       
 32394  * and explicit number rules throughout the rest of this documentation.
       
 32395  *
       
 32396  * # Configuring ngPluralize
       
 32397  * You configure ngPluralize by providing 2 attributes: `count` and `when`.
       
 32398  * You can also provide an optional attribute, `offset`.
       
 32399  *
       
 32400  * The value of the `count` attribute can be either a string or an {@link guide/expression
       
 32401  * Angular expression}; these are evaluated on the current scope for its bound value.
       
 32402  *
       
 32403  * The `when` attribute specifies the mappings between plural categories and the actual
       
 32404  * string to be displayed. The value of the attribute should be a JSON object.
       
 32405  *
       
 32406  * The following example shows how to configure ngPluralize:
       
 32407  *
       
 32408  * ```html
       
 32409  * <ng-pluralize count="personCount"
       
 32410                  when="{'0': 'Nobody is viewing.',
       
 32411  *                      'one': '1 person is viewing.',
       
 32412  *                      'other': '{} people are viewing.'}">
       
 32413  * </ng-pluralize>
       
 32414  *```
       
 32415  *
       
 32416  * In the example, `"0: Nobody is viewing."` is an explicit number rule. If you did not
       
 32417  * specify this rule, 0 would be matched to the "other" category and "0 people are viewing"
       
 32418  * would be shown instead of "Nobody is viewing". You can specify an explicit number rule for
       
 32419  * other numbers, for example 12, so that instead of showing "12 people are viewing", you can
       
 32420  * show "a dozen people are viewing".
       
 32421  *
       
 32422  * You can use a set of closed braces (`{}`) as a placeholder for the number that you want substituted
       
 32423  * into pluralized strings. In the previous example, Angular will replace `{}` with
       
 32424  * <span ng-non-bindable>`{{personCount}}`</span>. The closed braces `{}` is a placeholder
       
 32425  * for <span ng-non-bindable>{{numberExpression}}</span>.
       
 32426  *
       
 32427  * # Configuring ngPluralize with offset
       
 32428  * The `offset` attribute allows further customization of pluralized text, which can result in
       
 32429  * a better user experience. For example, instead of the message "4 people are viewing this document",
       
 32430  * you might display "John, Kate and 2 others are viewing this document".
       
 32431  * The offset attribute allows you to offset a number by any desired value.
       
 32432  * Let's take a look at an example:
       
 32433  *
       
 32434  * ```html
       
 32435  * <ng-pluralize count="personCount" offset=2
       
 32436  *               when="{'0': 'Nobody is viewing.',
       
 32437  *                      '1': '{{person1}} is viewing.',
       
 32438  *                      '2': '{{person1}} and {{person2}} are viewing.',
       
 32439  *                      'one': '{{person1}}, {{person2}} and one other person are viewing.',
       
 32440  *                      'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
       
 32441  * </ng-pluralize>
       
 32442  * ```
       
 32443  *
       
 32444  * Notice that we are still using two plural categories(one, other), but we added
       
 32445  * three explicit number rules 0, 1 and 2.
       
 32446  * When one person, perhaps John, views the document, "John is viewing" will be shown.
       
 32447  * When three people view the document, no explicit number rule is found, so
       
 32448  * an offset of 2 is taken off 3, and Angular uses 1 to decide the plural category.
       
 32449  * In this case, plural category 'one' is matched and "John, Mary and one other person are viewing"
       
 32450  * is shown.
       
 32451  *
       
 32452  * Note that when you specify offsets, you must provide explicit number rules for
       
 32453  * numbers from 0 up to and including the offset. If you use an offset of 3, for example,
       
 32454  * you must provide explicit number rules for 0, 1, 2 and 3. You must also provide plural strings for
       
 32455  * plural categories "one" and "other".
       
 32456  *
       
 32457  * @param {string|expression} count The variable to be bound to.
       
 32458  * @param {string} when The mapping between plural category to its corresponding strings.
       
 32459  * @param {number=} offset Offset to deduct from the total number.
       
 32460  *
       
 32461  * @example
       
 32462     <example module="pluralizeExample">
       
 32463       <file name="index.html">
       
 32464         <script>
       
 32465           angular.module('pluralizeExample', [])
       
 32466             .controller('ExampleController', ['$scope', function($scope) {
       
 32467               $scope.person1 = 'Igor';
       
 32468               $scope.person2 = 'Misko';
       
 32469               $scope.personCount = 1;
       
 32470             }]);
       
 32471         </script>
       
 32472         <div ng-controller="ExampleController">
       
 32473           Person 1:<input type="text" ng-model="person1" value="Igor" /><br/>
       
 32474           Person 2:<input type="text" ng-model="person2" value="Misko" /><br/>
       
 32475           Number of People:<input type="text" ng-model="personCount" value="1" /><br/>
       
 32476 
       
 32477           <!--- Example with simple pluralization rules for en locale --->
       
 32478           Without Offset:
       
 32479           <ng-pluralize count="personCount"
       
 32480                         when="{'0': 'Nobody is viewing.',
       
 32481                                'one': '1 person is viewing.',
       
 32482                                'other': '{} people are viewing.'}">
       
 32483           </ng-pluralize><br>
       
 32484 
       
 32485           <!--- Example with offset --->
       
 32486           With Offset(2):
       
 32487           <ng-pluralize count="personCount" offset=2
       
 32488                         when="{'0': 'Nobody is viewing.',
       
 32489                                '1': '{{person1}} is viewing.',
       
 32490                                '2': '{{person1}} and {{person2}} are viewing.',
       
 32491                                'one': '{{person1}}, {{person2}} and one other person are viewing.',
       
 32492                                'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
       
 32493           </ng-pluralize>
       
 32494         </div>
       
 32495       </file>
       
 32496       <file name="protractor.js" type="protractor">
       
 32497         it('should show correct pluralized string', function() {
       
 32498           var withoutOffset = element.all(by.css('ng-pluralize')).get(0);
       
 32499           var withOffset = element.all(by.css('ng-pluralize')).get(1);
       
 32500           var countInput = element(by.model('personCount'));
       
 32501 
       
 32502           expect(withoutOffset.getText()).toEqual('1 person is viewing.');
       
 32503           expect(withOffset.getText()).toEqual('Igor is viewing.');
       
 32504 
       
 32505           countInput.clear();
       
 32506           countInput.sendKeys('0');
       
 32507 
       
 32508           expect(withoutOffset.getText()).toEqual('Nobody is viewing.');
       
 32509           expect(withOffset.getText()).toEqual('Nobody is viewing.');
       
 32510 
       
 32511           countInput.clear();
       
 32512           countInput.sendKeys('2');
       
 32513 
       
 32514           expect(withoutOffset.getText()).toEqual('2 people are viewing.');
       
 32515           expect(withOffset.getText()).toEqual('Igor and Misko are viewing.');
       
 32516 
       
 32517           countInput.clear();
       
 32518           countInput.sendKeys('3');
       
 32519 
       
 32520           expect(withoutOffset.getText()).toEqual('3 people are viewing.');
       
 32521           expect(withOffset.getText()).toEqual('Igor, Misko and one other person are viewing.');
       
 32522 
       
 32523           countInput.clear();
       
 32524           countInput.sendKeys('4');
       
 32525 
       
 32526           expect(withoutOffset.getText()).toEqual('4 people are viewing.');
       
 32527           expect(withOffset.getText()).toEqual('Igor, Misko and 2 other people are viewing.');
       
 32528         });
       
 32529         it('should show data-bound names', function() {
       
 32530           var withOffset = element.all(by.css('ng-pluralize')).get(1);
       
 32531           var personCount = element(by.model('personCount'));
       
 32532           var person1 = element(by.model('person1'));
       
 32533           var person2 = element(by.model('person2'));
       
 32534           personCount.clear();
       
 32535           personCount.sendKeys('4');
       
 32536           person1.clear();
       
 32537           person1.sendKeys('Di');
       
 32538           person2.clear();
       
 32539           person2.sendKeys('Vojta');
       
 32540           expect(withOffset.getText()).toEqual('Di, Vojta and 2 other people are viewing.');
       
 32541         });
       
 32542       </file>
       
 32543     </example>
       
 32544  */
       
 32545 var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interpolate) {
       
 32546   var BRACE = /{}/g;
       
 32547   return {
       
 32548     restrict: 'EA',
       
 32549     link: function(scope, element, attr) {
       
 32550       var numberExp = attr.count,
       
 32551           whenExp = attr.$attr.when && element.attr(attr.$attr.when), // we have {{}} in attrs
       
 32552           offset = attr.offset || 0,
       
 32553           whens = scope.$eval(whenExp) || {},
       
 32554           whensExpFns = {},
       
 32555           startSymbol = $interpolate.startSymbol(),
       
 32556           endSymbol = $interpolate.endSymbol(),
       
 32557           isWhen = /^when(Minus)?(.+)$/;
       
 32558 
       
 32559       forEach(attr, function(expression, attributeName) {
       
 32560         if (isWhen.test(attributeName)) {
       
 32561           whens[lowercase(attributeName.replace('when', '').replace('Minus', '-'))] =
       
 32562             element.attr(attr.$attr[attributeName]);
       
 32563         }
       
 32564       });
       
 32565       forEach(whens, function(expression, key) {
       
 32566         whensExpFns[key] =
       
 32567           $interpolate(expression.replace(BRACE, startSymbol + numberExp + '-' +
       
 32568             offset + endSymbol));
       
 32569       });
       
 32570 
       
 32571       scope.$watch(function ngPluralizeWatch() {
       
 32572         var value = parseFloat(scope.$eval(numberExp));
       
 32573 
       
 32574         if (!isNaN(value)) {
       
 32575           //if explicit number rule such as 1, 2, 3... is defined, just use it. Otherwise,
       
 32576           //check it against pluralization rules in $locale service
       
 32577           if (!(value in whens)) value = $locale.pluralCat(value - offset);
       
 32578            return whensExpFns[value](scope);
       
 32579         } else {
       
 32580           return '';
       
 32581         }
       
 32582       }, function ngPluralizeWatchAction(newVal) {
       
 32583         element.text(newVal);
       
 32584       });
       
 32585     }
       
 32586   };
       
 32587 }];
       
 32588 
       
 32589 /**
       
 32590  * @ngdoc directive
       
 32591  * @name ngRepeat
       
 32592  *
       
 32593  * @description
       
 32594  * The `ngRepeat` directive instantiates a template once per item from a collection. Each template
       
 32595  * instance gets its own scope, where the given loop variable is set to the current collection item,
       
 32596  * and `$index` is set to the item index or key.
       
 32597  *
       
 32598  * Special properties are exposed on the local scope of each template instance, including:
       
 32599  *
       
 32600  * | Variable  | Type            | Details                                                                     |
       
 32601  * |-----------|-----------------|-----------------------------------------------------------------------------|
       
 32602  * | `$index`  | {@type number}  | iterator offset of the repeated element (0..length-1)                       |
       
 32603  * | `$first`  | {@type boolean} | true if the repeated element is first in the iterator.                      |
       
 32604  * | `$middle` | {@type boolean} | true if the repeated element is between the first and last in the iterator. |
       
 32605  * | `$last`   | {@type boolean} | true if the repeated element is last in the iterator.                       |
       
 32606  * | `$even`   | {@type boolean} | true if the iterator position `$index` is even (otherwise false).           |
       
 32607  * | `$odd`    | {@type boolean} | true if the iterator position `$index` is odd (otherwise false).            |
       
 32608  *
       
 32609  * Creating aliases for these properties is possible with {@link ng.directive:ngInit `ngInit`}.
       
 32610  * This may be useful when, for instance, nesting ngRepeats.
       
 32611  *
       
 32612  * # Special repeat start and end points
       
 32613  * To repeat a series of elements instead of just one parent element, ngRepeat (as well as other ng directives) supports extending
       
 32614  * the range of the repeater by defining explicit start and end points by using **ng-repeat-start** and **ng-repeat-end** respectively.
       
 32615  * 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)
       
 32616  * up to and including the ending HTML tag where **ng-repeat-end** is placed.
       
 32617  *
       
 32618  * The example below makes use of this feature:
       
 32619  * ```html
       
 32620  *   <header ng-repeat-start="item in items">
       
 32621  *     Header {{ item }}
       
 32622  *   </header>
       
 32623  *   <div class="body">
       
 32624  *     Body {{ item }}
       
 32625  *   </div>
       
 32626  *   <footer ng-repeat-end>
       
 32627  *     Footer {{ item }}
       
 32628  *   </footer>
       
 32629  * ```
       
 32630  *
       
 32631  * And with an input of {@type ['A','B']} for the items variable in the example above, the output will evaluate to:
       
 32632  * ```html
       
 32633  *   <header>
       
 32634  *     Header A
       
 32635  *   </header>
       
 32636  *   <div class="body">
       
 32637  *     Body A
       
 32638  *   </div>
       
 32639  *   <footer>
       
 32640  *     Footer A
       
 32641  *   </footer>
       
 32642  *   <header>
       
 32643  *     Header B
       
 32644  *   </header>
       
 32645  *   <div class="body">
       
 32646  *     Body B
       
 32647  *   </div>
       
 32648  *   <footer>
       
 32649  *     Footer B
       
 32650  *   </footer>
       
 32651  * ```
       
 32652  *
       
 32653  * The custom start and end points for ngRepeat also support all other HTML directive syntax flavors provided in AngularJS (such
       
 32654  * as **data-ng-repeat-start**, **x-ng-repeat-start** and **ng:repeat-start**).
       
 32655  *
       
 32656  * @animations
       
 32657  * **.enter** - when a new item is added to the list or when an item is revealed after a filter
       
 32658  *
       
 32659  * **.leave** - when an item is removed from the list or when an item is filtered out
       
 32660  *
       
 32661  * **.move** - when an adjacent item is filtered out causing a reorder or when the item contents are reordered
       
 32662  *
       
 32663  * @element ANY
       
 32664  * @scope
       
 32665  * @priority 1000
       
 32666  * @param {repeat_expression} ngRepeat The expression indicating how to enumerate a collection. These
       
 32667  *   formats are currently supported:
       
 32668  *
       
 32669  *   * `variable in expression` – where variable is the user defined loop variable and `expression`
       
 32670  *     is a scope expression giving the collection to enumerate.
       
 32671  *
       
 32672  *     For example: `album in artist.albums`.
       
 32673  *
       
 32674  *   * `(key, value) in expression` – where `key` and `value` can be any user defined identifiers,
       
 32675  *     and `expression` is the scope expression giving the collection to enumerate.
       
 32676  *
       
 32677  *     For example: `(name, age) in {'adam':10, 'amalie':12}`.
       
 32678  *
       
 32679  *   * `variable in expression track by tracking_expression` – You can also provide an optional tracking function
       
 32680  *     which can be used to associate the objects in the collection with the DOM elements. If no tracking function
       
 32681  *     is specified the ng-repeat associates elements by identity in the collection. It is an error to have
       
 32682  *     more than one tracking function to resolve to the same key. (This would mean that two distinct objects are
       
 32683  *     mapped to the same DOM element, which is not possible.)  Filters should be applied to the expression,
       
 32684  *     before specifying a tracking expression.
       
 32685  *
       
 32686  *     For example: `item in items` is equivalent to `item in items track by $id(item)`. This implies that the DOM elements
       
 32687  *     will be associated by item identity in the array.
       
 32688  *
       
 32689  *   * `variable in expression as alias_expression` – You can also provide an optional alias expression which will then store the
       
 32690  *     intermediate results of the repeater after the filters have been applied. Typically this is used to render a special message
       
 32691  *     when a filter is active on the repeater, but the filtered result set is empty.
       
 32692  *
       
 32693  *     For example: `item in items | filter:x as results` will store the fragment of the repeated items as `results`, but only after
       
 32694  *     the items have been processed through the filter.
       
 32695  *
       
 32696  *     For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique
       
 32697  *     `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements
       
 32698  *     with the corresponding item in the array by identity. Moving the same object in array would move the DOM
       
 32699  *     element in the same way in the DOM.
       
 32700  *
       
 32701  *     For example: `item in items track by item.id` is a typical pattern when the items come from the database. In this
       
 32702  *     case the object identity does not matter. Two objects are considered equivalent as long as their `id`
       
 32703  *     property is same.
       
 32704  *
       
 32705  *     For example: `item in items | filter:searchText track by item.id` is a pattern that might be used to apply a filter
       
 32706  *     to items in conjunction with a tracking expression.
       
 32707  *
       
 32708  * @example
       
 32709  * This example initializes the scope to a list of names and
       
 32710  * then uses `ngRepeat` to display every person:
       
 32711   <example module="ngAnimate" deps="angular-animate.js" animations="true">
       
 32712     <file name="index.html">
       
 32713       <div ng-init="friends = [
       
 32714         {name:'John', age:25, gender:'boy'},
       
 32715         {name:'Jessie', age:30, gender:'girl'},
       
 32716         {name:'Johanna', age:28, gender:'girl'},
       
 32717         {name:'Joy', age:15, gender:'girl'},
       
 32718         {name:'Mary', age:28, gender:'girl'},
       
 32719         {name:'Peter', age:95, gender:'boy'},
       
 32720         {name:'Sebastian', age:50, gender:'boy'},
       
 32721         {name:'Erika', age:27, gender:'girl'},
       
 32722         {name:'Patrick', age:40, gender:'boy'},
       
 32723         {name:'Samantha', age:60, gender:'girl'}
       
 32724       ]">
       
 32725         I have {{friends.length}} friends. They are:
       
 32726         <input type="search" ng-model="q" placeholder="filter friends..." />
       
 32727         <ul class="example-animate-container">
       
 32728           <li class="animate-repeat" ng-repeat="friend in friends | filter:q as results">
       
 32729             [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.
       
 32730           </li>
       
 32731           <li class="animate-repeat" ng-if="results.length == 0">
       
 32732             <strong>No results found...</strong>
       
 32733           </li>
       
 32734         </ul>
       
 32735       </div>
       
 32736     </file>
       
 32737     <file name="animations.css">
       
 32738       .example-animate-container {
       
 32739         background:white;
       
 32740         border:1px solid black;
       
 32741         list-style:none;
       
 32742         margin:0;
       
 32743         padding:0 10px;
       
 32744       }
       
 32745 
       
 32746       .animate-repeat {
       
 32747         line-height:40px;
       
 32748         list-style:none;
       
 32749         box-sizing:border-box;
       
 32750       }
       
 32751 
       
 32752       .animate-repeat.ng-move,
       
 32753       .animate-repeat.ng-enter,
       
 32754       .animate-repeat.ng-leave {
       
 32755         -webkit-transition:all linear 0.5s;
       
 32756         transition:all linear 0.5s;
       
 32757       }
       
 32758 
       
 32759       .animate-repeat.ng-leave.ng-leave-active,
       
 32760       .animate-repeat.ng-move,
       
 32761       .animate-repeat.ng-enter {
       
 32762         opacity:0;
       
 32763         max-height:0;
       
 32764       }
       
 32765 
       
 32766       .animate-repeat.ng-leave,
       
 32767       .animate-repeat.ng-move.ng-move-active,
       
 32768       .animate-repeat.ng-enter.ng-enter-active {
       
 32769         opacity:1;
       
 32770         max-height:40px;
       
 32771       }
       
 32772     </file>
       
 32773     <file name="protractor.js" type="protractor">
       
 32774       var friends = element.all(by.repeater('friend in friends'));
       
 32775 
       
 32776       it('should render initial data set', function() {
       
 32777         expect(friends.count()).toBe(10);
       
 32778         expect(friends.get(0).getText()).toEqual('[1] John who is 25 years old.');
       
 32779         expect(friends.get(1).getText()).toEqual('[2] Jessie who is 30 years old.');
       
 32780         expect(friends.last().getText()).toEqual('[10] Samantha who is 60 years old.');
       
 32781         expect(element(by.binding('friends.length')).getText())
       
 32782             .toMatch("I have 10 friends. They are:");
       
 32783       });
       
 32784 
       
 32785        it('should update repeater when filter predicate changes', function() {
       
 32786          expect(friends.count()).toBe(10);
       
 32787 
       
 32788          element(by.model('q')).sendKeys('ma');
       
 32789 
       
 32790          expect(friends.count()).toBe(2);
       
 32791          expect(friends.get(0).getText()).toEqual('[1] Mary who is 28 years old.');
       
 32792          expect(friends.last().getText()).toEqual('[2] Samantha who is 60 years old.');
       
 32793        });
       
 32794       </file>
       
 32795     </example>
       
 32796  */
       
 32797 var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
       
 32798   var NG_REMOVED = '$$NG_REMOVED';
       
 32799   var ngRepeatMinErr = minErr('ngRepeat');
       
 32800 
       
 32801   var updateScope = function(scope, index, valueIdentifier, value, keyIdentifier, key, arrayLength) {
       
 32802     // TODO(perf): generate setters to shave off ~40ms or 1-1.5%
       
 32803     scope[valueIdentifier] = value;
       
 32804     if (keyIdentifier) scope[keyIdentifier] = key;
       
 32805     scope.$index = index;
       
 32806     scope.$first = (index === 0);
       
 32807     scope.$last = (index === (arrayLength - 1));
       
 32808     scope.$middle = !(scope.$first || scope.$last);
       
 32809     // jshint bitwise: false
       
 32810     scope.$odd = !(scope.$even = (index&1) === 0);
       
 32811     // jshint bitwise: true
       
 32812   };
       
 32813 
       
 32814   var getBlockStart = function(block) {
       
 32815     return block.clone[0];
       
 32816   };
       
 32817 
       
 32818   var getBlockEnd = function(block) {
       
 32819     return block.clone[block.clone.length - 1];
       
 32820   };
       
 32821 
       
 32822 
       
 32823   return {
       
 32824     restrict: 'A',
       
 32825     multiElement: true,
       
 32826     transclude: 'element',
       
 32827     priority: 1000,
       
 32828     terminal: true,
       
 32829     $$tlb: true,
       
 32830     compile: function ngRepeatCompile($element, $attr) {
       
 32831       var expression = $attr.ngRepeat;
       
 32832       var ngRepeatEndComment = document.createComment(' end ngRepeat: ' + expression + ' ');
       
 32833 
       
 32834       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*$/);
       
 32835 
       
 32836       if (!match) {
       
 32837         throw ngRepeatMinErr('iexp', "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.",
       
 32838             expression);
       
 32839       }
       
 32840 
       
 32841       var lhs = match[1];
       
 32842       var rhs = match[2];
       
 32843       var aliasAs = match[3];
       
 32844       var trackByExp = match[4];
       
 32845 
       
 32846       match = lhs.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);
       
 32847 
       
 32848       if (!match) {
       
 32849         throw ngRepeatMinErr('iidexp', "'_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.",
       
 32850             lhs);
       
 32851       }
       
 32852       var valueIdentifier = match[3] || match[1];
       
 32853       var keyIdentifier = match[2];
       
 32854 
       
 32855       if (aliasAs && (!/^[$a-zA-Z_][$a-zA-Z0-9_]*$/.test(aliasAs) ||
       
 32856           /^(null|undefined|this|\$index|\$first|\$middle|\$last|\$even|\$odd|\$parent)$/.test(aliasAs))) {
       
 32857         throw ngRepeatMinErr('badident', "alias '{0}' is invalid --- must be a valid JS identifier which is not a reserved name.",
       
 32858           aliasAs);
       
 32859       }
       
 32860 
       
 32861       var trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn;
       
 32862       var hashFnLocals = {$id: hashKey};
       
 32863 
       
 32864       if (trackByExp) {
       
 32865         trackByExpGetter = $parse(trackByExp);
       
 32866       } else {
       
 32867         trackByIdArrayFn = function (key, value) {
       
 32868           return hashKey(value);
       
 32869         };
       
 32870         trackByIdObjFn = function (key) {
       
 32871           return key;
       
 32872         };
       
 32873       }
       
 32874 
       
 32875       return function ngRepeatLink($scope, $element, $attr, ctrl, $transclude) {
       
 32876 
       
 32877         if (trackByExpGetter) {
       
 32878           trackByIdExpFn = function(key, value, index) {
       
 32879             // assign key, value, and $index to the locals so that they can be used in hash functions
       
 32880             if (keyIdentifier) hashFnLocals[keyIdentifier] = key;
       
 32881             hashFnLocals[valueIdentifier] = value;
       
 32882             hashFnLocals.$index = index;
       
 32883             return trackByExpGetter($scope, hashFnLocals);
       
 32884           };
       
 32885         }
       
 32886 
       
 32887         // Store a list of elements from previous run. This is a hash where key is the item from the
       
 32888         // iterator, and the value is objects with following properties.
       
 32889         //   - scope: bound scope
       
 32890         //   - element: previous element.
       
 32891         //   - index: position
       
 32892         //
       
 32893         // We are using no-proto object so that we don't need to guard against inherited props via
       
 32894         // hasOwnProperty.
       
 32895         var lastBlockMap = createMap();
       
 32896 
       
 32897         //watch props
       
 32898         $scope.$watchCollection(rhs, function ngRepeatAction(collection) {
       
 32899           var index, length,
       
 32900               previousNode = $element[0],     // node that cloned nodes should be inserted after
       
 32901                                               // initialized to the comment node anchor
       
 32902               nextNode,
       
 32903               // Same as lastBlockMap but it has the current state. It will become the
       
 32904               // lastBlockMap on the next iteration.
       
 32905               nextBlockMap = createMap(),
       
 32906               collectionLength,
       
 32907               key, value, // key/value of iteration
       
 32908               trackById,
       
 32909               trackByIdFn,
       
 32910               collectionKeys,
       
 32911               block,       // last object information {scope, element, id}
       
 32912               nextBlockOrder,
       
 32913               elementsToRemove;
       
 32914 
       
 32915           if (aliasAs) {
       
 32916             $scope[aliasAs] = collection;
       
 32917           }
       
 32918 
       
 32919           if (isArrayLike(collection)) {
       
 32920             collectionKeys = collection;
       
 32921             trackByIdFn = trackByIdExpFn || trackByIdArrayFn;
       
 32922           } else {
       
 32923             trackByIdFn = trackByIdExpFn || trackByIdObjFn;
       
 32924             // if object, extract keys, sort them and use to determine order of iteration over obj props
       
 32925             collectionKeys = [];
       
 32926             for (var itemKey in collection) {
       
 32927               if (collection.hasOwnProperty(itemKey) && itemKey.charAt(0) != '$') {
       
 32928                 collectionKeys.push(itemKey);
       
 32929               }
       
 32930             }
       
 32931             collectionKeys.sort();
       
 32932           }
       
 32933 
       
 32934           collectionLength = collectionKeys.length;
       
 32935           nextBlockOrder = new Array(collectionLength);
       
 32936 
       
 32937           // locate existing items
       
 32938           for (index = 0; index < collectionLength; index++) {
       
 32939             key = (collection === collectionKeys) ? index : collectionKeys[index];
       
 32940             value = collection[key];
       
 32941             trackById = trackByIdFn(key, value, index);
       
 32942             if (lastBlockMap[trackById]) {
       
 32943               // found previously seen block
       
 32944               block = lastBlockMap[trackById];
       
 32945               delete lastBlockMap[trackById];
       
 32946               nextBlockMap[trackById] = block;
       
 32947               nextBlockOrder[index] = block;
       
 32948             } else if (nextBlockMap[trackById]) {
       
 32949               // if collision detected. restore lastBlockMap and throw an error
       
 32950               forEach(nextBlockOrder, function (block) {
       
 32951                 if (block && block.scope) lastBlockMap[block.id] = block;
       
 32952               });
       
 32953               throw ngRepeatMinErr('dupes',
       
 32954                   "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}, Duplicate value: {2}",
       
 32955                   expression, trackById, toJson(value));
       
 32956             } else {
       
 32957               // new never before seen block
       
 32958               nextBlockOrder[index] = {id: trackById, scope: undefined, clone: undefined};
       
 32959               nextBlockMap[trackById] = true;
       
 32960             }
       
 32961           }
       
 32962 
       
 32963           // remove leftover items
       
 32964           for (var blockKey in lastBlockMap) {
       
 32965             block = lastBlockMap[blockKey];
       
 32966             elementsToRemove = getBlockNodes(block.clone);
       
 32967             $animate.leave(elementsToRemove);
       
 32968             if (elementsToRemove[0].parentNode) {
       
 32969               // if the element was not removed yet because of pending animation, mark it as deleted
       
 32970               // so that we can ignore it later
       
 32971               for (index = 0, length = elementsToRemove.length; index < length; index++) {
       
 32972                 elementsToRemove[index][NG_REMOVED] = true;
       
 32973               }
       
 32974             }
       
 32975             block.scope.$destroy();
       
 32976           }
       
 32977 
       
 32978           // we are not using forEach for perf reasons (trying to avoid #call)
       
 32979           for (index = 0; index < collectionLength; index++) {
       
 32980             key = (collection === collectionKeys) ? index : collectionKeys[index];
       
 32981             value = collection[key];
       
 32982             block = nextBlockOrder[index];
       
 32983 
       
 32984             if (block.scope) {
       
 32985               // if we have already seen this object, then we need to reuse the
       
 32986               // associated scope/element
       
 32987 
       
 32988               nextNode = previousNode;
       
 32989 
       
 32990               // skip nodes that are already pending removal via leave animation
       
 32991               do {
       
 32992                 nextNode = nextNode.nextSibling;
       
 32993               } while (nextNode && nextNode[NG_REMOVED]);
       
 32994 
       
 32995               if (getBlockStart(block) != nextNode) {
       
 32996                 // existing item which got moved
       
 32997                 $animate.move(getBlockNodes(block.clone), null, jqLite(previousNode));
       
 32998               }
       
 32999               previousNode = getBlockEnd(block);
       
 33000               updateScope(block.scope, index, valueIdentifier, value, keyIdentifier, key, collectionLength);
       
 33001             } else {
       
 33002               // new item which we don't know about
       
 33003               $transclude(function ngRepeatTransclude(clone, scope) {
       
 33004                 block.scope = scope;
       
 33005                 // http://jsperf.com/clone-vs-createcomment
       
 33006                 var endNode = ngRepeatEndComment.cloneNode(false);
       
 33007                 clone[clone.length++] = endNode;
       
 33008 
       
 33009                 // TODO(perf): support naked previousNode in `enter` to avoid creation of jqLite wrapper?
       
 33010                 $animate.enter(clone, null, jqLite(previousNode));
       
 33011                 previousNode = endNode;
       
 33012                 // Note: We only need the first/last node of the cloned nodes.
       
 33013                 // However, we need to keep the reference to the jqlite wrapper as it might be changed later
       
 33014                 // by a directive with templateUrl when its template arrives.
       
 33015                 block.clone = clone;
       
 33016                 nextBlockMap[block.id] = block;
       
 33017                 updateScope(block.scope, index, valueIdentifier, value, keyIdentifier, key, collectionLength);
       
 33018               });
       
 33019             }
       
 33020           }
       
 33021           lastBlockMap = nextBlockMap;
       
 33022         });
       
 33023       };
       
 33024     }
       
 33025   };
       
 33026 }];
       
 33027 
       
 33028 var NG_HIDE_CLASS = 'ng-hide';
       
 33029 var NG_HIDE_IN_PROGRESS_CLASS = 'ng-hide-animate';
       
 33030 /**
       
 33031  * @ngdoc directive
       
 33032  * @name ngShow
       
 33033  *
       
 33034  * @description
       
 33035  * The `ngShow` directive shows or hides the given HTML element based on the expression
       
 33036  * provided to the `ngShow` attribute. The element is shown or hidden by removing or adding
       
 33037  * the `.ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
       
 33038  * in AngularJS and sets the display style to none (using an !important flag).
       
 33039  * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
       
 33040  *
       
 33041  * ```html
       
 33042  * <!-- when $scope.myValue is truthy (element is visible) -->
       
 33043  * <div ng-show="myValue"></div>
       
 33044  *
       
 33045  * <!-- when $scope.myValue is falsy (element is hidden) -->
       
 33046  * <div ng-show="myValue" class="ng-hide"></div>
       
 33047  * ```
       
 33048  *
       
 33049  * When the `ngShow` expression evaluates to a falsy value then the `.ng-hide` CSS class is added to the class
       
 33050  * attribute on the element causing it to become hidden. When truthy, the `.ng-hide` CSS class is removed
       
 33051  * from the element causing the element not to appear hidden.
       
 33052  *
       
 33053  * ## Why is !important used?
       
 33054  *
       
 33055  * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector
       
 33056  * can be easily overridden by heavier selectors. For example, something as simple
       
 33057  * as changing the display style on a HTML list item would make hidden elements appear visible.
       
 33058  * This also becomes a bigger issue when dealing with CSS frameworks.
       
 33059  *
       
 33060  * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
       
 33061  * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
       
 33062  * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
       
 33063  *
       
 33064  * ### Overriding `.ng-hide`
       
 33065  *
       
 33066  * By default, the `.ng-hide` class will style the element with `display:none!important`. If you wish to change
       
 33067  * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
       
 33068  * class in CSS:
       
 33069  *
       
 33070  * ```css
       
 33071  * .ng-hide {
       
 33072  *   /&#42; this is just another form of hiding an element &#42;/
       
 33073  *   display:block!important;
       
 33074  *   position:absolute;
       
 33075  *   top:-9999px;
       
 33076  *   left:-9999px;
       
 33077  * }
       
 33078  * ```
       
 33079  *
       
 33080  * By default you don't need to override in CSS anything and the animations will work around the display style.
       
 33081  *
       
 33082  * ## A note about animations with `ngShow`
       
 33083  *
       
 33084  * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
       
 33085  * is true and false. This system works like the animation system present with ngClass except that
       
 33086  * you must also include the !important flag to override the display property
       
 33087  * so that you can perform an animation when the element is hidden during the time of the animation.
       
 33088  *
       
 33089  * ```css
       
 33090  * //
       
 33091  * //a working example can be found at the bottom of this page
       
 33092  * //
       
 33093  * .my-element.ng-hide-add, .my-element.ng-hide-remove {
       
 33094  *   /&#42; this is required as of 1.3x to properly
       
 33095  *      apply all styling in a show/hide animation &#42;/
       
 33096  *   transition:0s linear all;
       
 33097  * }
       
 33098  *
       
 33099  * .my-element.ng-hide-add-active,
       
 33100  * .my-element.ng-hide-remove-active {
       
 33101  *   /&#42; the transition is defined in the active class &#42;/
       
 33102  *   transition:1s linear all;
       
 33103  * }
       
 33104  *
       
 33105  * .my-element.ng-hide-add { ... }
       
 33106  * .my-element.ng-hide-add.ng-hide-add-active { ... }
       
 33107  * .my-element.ng-hide-remove { ... }
       
 33108  * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
       
 33109  * ```
       
 33110  *
       
 33111  * Keep in mind that, as of AngularJS version 1.3.0-beta.11, there is no need to change the display
       
 33112  * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
       
 33113  *
       
 33114  * @animations
       
 33115  * addClass: `.ng-hide` - happens after the `ngShow` expression evaluates to a truthy value and the just before contents are set to visible
       
 33116  * removeClass: `.ng-hide` - happens after the `ngShow` expression evaluates to a non truthy value and just before the contents are set to hidden
       
 33117  *
       
 33118  * @element ANY
       
 33119  * @param {expression} ngShow If the {@link guide/expression expression} is truthy
       
 33120  *     then the element is shown or hidden respectively.
       
 33121  *
       
 33122  * @example
       
 33123   <example module="ngAnimate" deps="angular-animate.js" animations="true">
       
 33124     <file name="index.html">
       
 33125       Click me: <input type="checkbox" ng-model="checked"><br/>
       
 33126       <div>
       
 33127         Show:
       
 33128         <div class="check-element animate-show" ng-show="checked">
       
 33129           <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
       
 33130         </div>
       
 33131       </div>
       
 33132       <div>
       
 33133         Hide:
       
 33134         <div class="check-element animate-show" ng-hide="checked">
       
 33135           <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
       
 33136         </div>
       
 33137       </div>
       
 33138     </file>
       
 33139     <file name="glyphicons.css">
       
 33140       @import url(//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-glyphicons.css);
       
 33141     </file>
       
 33142     <file name="animations.css">
       
 33143       .animate-show {
       
 33144         line-height:20px;
       
 33145         opacity:1;
       
 33146         padding:10px;
       
 33147         border:1px solid black;
       
 33148         background:white;
       
 33149       }
       
 33150 
       
 33151       .animate-show.ng-hide-add.ng-hide-add-active,
       
 33152       .animate-show.ng-hide-remove.ng-hide-remove-active {
       
 33153         -webkit-transition:all linear 0.5s;
       
 33154         transition:all linear 0.5s;
       
 33155       }
       
 33156 
       
 33157       .animate-show.ng-hide {
       
 33158         line-height:0;
       
 33159         opacity:0;
       
 33160         padding:0 10px;
       
 33161       }
       
 33162 
       
 33163       .check-element {
       
 33164         padding:10px;
       
 33165         border:1px solid black;
       
 33166         background:white;
       
 33167       }
       
 33168     </file>
       
 33169     <file name="protractor.js" type="protractor">
       
 33170       var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
       
 33171       var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
       
 33172 
       
 33173       it('should check ng-show / ng-hide', function() {
       
 33174         expect(thumbsUp.isDisplayed()).toBeFalsy();
       
 33175         expect(thumbsDown.isDisplayed()).toBeTruthy();
       
 33176 
       
 33177         element(by.model('checked')).click();
       
 33178 
       
 33179         expect(thumbsUp.isDisplayed()).toBeTruthy();
       
 33180         expect(thumbsDown.isDisplayed()).toBeFalsy();
       
 33181       });
       
 33182     </file>
       
 33183   </example>
       
 33184  */
       
 33185 var ngShowDirective = ['$animate', function($animate) {
       
 33186   return {
       
 33187     restrict: 'A',
       
 33188     multiElement: true,
       
 33189     link: function(scope, element, attr) {
       
 33190       scope.$watch(attr.ngShow, function ngShowWatchAction(value){
       
 33191         // we're adding a temporary, animation-specific class for ng-hide since this way
       
 33192         // we can control when the element is actually displayed on screen without having
       
 33193         // to have a global/greedy CSS selector that breaks when other animations are run.
       
 33194         // Read: https://github.com/angular/angular.js/issues/9103#issuecomment-58335845
       
 33195         $animate[value ? 'removeClass' : 'addClass'](element, NG_HIDE_CLASS, NG_HIDE_IN_PROGRESS_CLASS);
       
 33196       });
       
 33197     }
       
 33198   };
       
 33199 }];
       
 33200 
       
 33201 
       
 33202 /**
       
 33203  * @ngdoc directive
       
 33204  * @name ngHide
       
 33205  *
       
 33206  * @description
       
 33207  * The `ngHide` directive shows or hides the given HTML element based on the expression
       
 33208  * provided to the `ngHide` attribute. The element is shown or hidden by removing or adding
       
 33209  * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
       
 33210  * in AngularJS and sets the display style to none (using an !important flag).
       
 33211  * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
       
 33212  *
       
 33213  * ```html
       
 33214  * <!-- when $scope.myValue is truthy (element is hidden) -->
       
 33215  * <div ng-hide="myValue" class="ng-hide"></div>
       
 33216  *
       
 33217  * <!-- when $scope.myValue is falsy (element is visible) -->
       
 33218  * <div ng-hide="myValue"></div>
       
 33219  * ```
       
 33220  *
       
 33221  * When the `ngHide` expression evaluates to a truthy value then the `.ng-hide` CSS class is added to the class
       
 33222  * attribute on the element causing it to become hidden. When falsy, the `.ng-hide` CSS class is removed
       
 33223  * from the element causing the element not to appear hidden.
       
 33224  *
       
 33225  * ## Why is !important used?
       
 33226  *
       
 33227  * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector
       
 33228  * can be easily overridden by heavier selectors. For example, something as simple
       
 33229  * as changing the display style on a HTML list item would make hidden elements appear visible.
       
 33230  * This also becomes a bigger issue when dealing with CSS frameworks.
       
 33231  *
       
 33232  * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
       
 33233  * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
       
 33234  * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
       
 33235  *
       
 33236  * ### Overriding `.ng-hide`
       
 33237  *
       
 33238  * By default, the `.ng-hide` class will style the element with `display:none!important`. If you wish to change
       
 33239  * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
       
 33240  * class in CSS:
       
 33241  *
       
 33242  * ```css
       
 33243  * .ng-hide {
       
 33244  *   /&#42; this is just another form of hiding an element &#42;/
       
 33245  *   display:block!important;
       
 33246  *   position:absolute;
       
 33247  *   top:-9999px;
       
 33248  *   left:-9999px;
       
 33249  * }
       
 33250  * ```
       
 33251  *
       
 33252  * By default you don't need to override in CSS anything and the animations will work around the display style.
       
 33253  *
       
 33254  * ## A note about animations with `ngHide`
       
 33255  *
       
 33256  * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
       
 33257  * is true and false. This system works like the animation system present with ngClass, except that the `.ng-hide`
       
 33258  * CSS class is added and removed for you instead of your own CSS class.
       
 33259  *
       
 33260  * ```css
       
 33261  * //
       
 33262  * //a working example can be found at the bottom of this page
       
 33263  * //
       
 33264  * .my-element.ng-hide-add, .my-element.ng-hide-remove {
       
 33265  *   transition:0.5s linear all;
       
 33266  * }
       
 33267  *
       
 33268  * .my-element.ng-hide-add { ... }
       
 33269  * .my-element.ng-hide-add.ng-hide-add-active { ... }
       
 33270  * .my-element.ng-hide-remove { ... }
       
 33271  * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
       
 33272  * ```
       
 33273  *
       
 33274  * Keep in mind that, as of AngularJS version 1.3.0-beta.11, there is no need to change the display
       
 33275  * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
       
 33276  *
       
 33277  * @animations
       
 33278  * removeClass: `.ng-hide` - happens after the `ngHide` expression evaluates to a truthy value and just before the contents are set to hidden
       
 33279  * addClass: `.ng-hide` - happens after the `ngHide` expression evaluates to a non truthy value and just before the contents are set to visible
       
 33280  *
       
 33281  * @element ANY
       
 33282  * @param {expression} ngHide If the {@link guide/expression expression} is truthy then
       
 33283  *     the element is shown or hidden respectively.
       
 33284  *
       
 33285  * @example
       
 33286   <example module="ngAnimate" deps="angular-animate.js" animations="true">
       
 33287     <file name="index.html">
       
 33288       Click me: <input type="checkbox" ng-model="checked"><br/>
       
 33289       <div>
       
 33290         Show:
       
 33291         <div class="check-element animate-hide" ng-show="checked">
       
 33292           <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
       
 33293         </div>
       
 33294       </div>
       
 33295       <div>
       
 33296         Hide:
       
 33297         <div class="check-element animate-hide" ng-hide="checked">
       
 33298           <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
       
 33299         </div>
       
 33300       </div>
       
 33301     </file>
       
 33302     <file name="glyphicons.css">
       
 33303       @import url(//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-glyphicons.css);
       
 33304     </file>
       
 33305     <file name="animations.css">
       
 33306       .animate-hide {
       
 33307         -webkit-transition:all linear 0.5s;
       
 33308         transition:all linear 0.5s;
       
 33309         line-height:20px;
       
 33310         opacity:1;
       
 33311         padding:10px;
       
 33312         border:1px solid black;
       
 33313         background:white;
       
 33314       }
       
 33315 
       
 33316       .animate-hide.ng-hide {
       
 33317         line-height:0;
       
 33318         opacity:0;
       
 33319         padding:0 10px;
       
 33320       }
       
 33321 
       
 33322       .check-element {
       
 33323         padding:10px;
       
 33324         border:1px solid black;
       
 33325         background:white;
       
 33326       }
       
 33327     </file>
       
 33328     <file name="protractor.js" type="protractor">
       
 33329       var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
       
 33330       var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
       
 33331 
       
 33332       it('should check ng-show / ng-hide', function() {
       
 33333         expect(thumbsUp.isDisplayed()).toBeFalsy();
       
 33334         expect(thumbsDown.isDisplayed()).toBeTruthy();
       
 33335 
       
 33336         element(by.model('checked')).click();
       
 33337 
       
 33338         expect(thumbsUp.isDisplayed()).toBeTruthy();
       
 33339         expect(thumbsDown.isDisplayed()).toBeFalsy();
       
 33340       });
       
 33341     </file>
       
 33342   </example>
       
 33343  */
       
 33344 var ngHideDirective = ['$animate', function($animate) {
       
 33345   return {
       
 33346     restrict: 'A',
       
 33347     multiElement: true,
       
 33348     link: function(scope, element, attr) {
       
 33349       scope.$watch(attr.ngHide, function ngHideWatchAction(value){
       
 33350         // The comment inside of the ngShowDirective explains why we add and
       
 33351         // remove a temporary class for the show/hide animation
       
 33352         $animate[value ? 'addClass' : 'removeClass'](element,NG_HIDE_CLASS, NG_HIDE_IN_PROGRESS_CLASS);
       
 33353       });
       
 33354     }
       
 33355   };
       
 33356 }];
       
 33357 
       
 33358 /**
       
 33359  * @ngdoc directive
       
 33360  * @name ngStyle
       
 33361  * @restrict AC
       
 33362  *
       
 33363  * @description
       
 33364  * The `ngStyle` directive allows you to set CSS style on an HTML element conditionally.
       
 33365  *
       
 33366  * @element ANY
       
 33367  * @param {expression} ngStyle
       
 33368  *
       
 33369  * {@link guide/expression Expression} which evals to an
       
 33370  * object whose keys are CSS style names and values are corresponding values for those CSS
       
 33371  * keys.
       
 33372  *
       
 33373  * Since some CSS style names are not valid keys for an object, they must be quoted.
       
 33374  * See the 'background-color' style in the example below.
       
 33375  *
       
 33376  * @example
       
 33377    <example>
       
 33378      <file name="index.html">
       
 33379         <input type="button" value="set color" ng-click="myStyle={color:'red'}">
       
 33380         <input type="button" value="set background" ng-click="myStyle={'background-color':'blue'}">
       
 33381         <input type="button" value="clear" ng-click="myStyle={}">
       
 33382         <br/>
       
 33383         <span ng-style="myStyle">Sample Text</span>
       
 33384         <pre>myStyle={{myStyle}}</pre>
       
 33385      </file>
       
 33386      <file name="style.css">
       
 33387        span {
       
 33388          color: black;
       
 33389        }
       
 33390      </file>
       
 33391      <file name="protractor.js" type="protractor">
       
 33392        var colorSpan = element(by.css('span'));
       
 33393 
       
 33394        it('should check ng-style', function() {
       
 33395          expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
       
 33396          element(by.css('input[value=\'set color\']')).click();
       
 33397          expect(colorSpan.getCssValue('color')).toBe('rgba(255, 0, 0, 1)');
       
 33398          element(by.css('input[value=clear]')).click();
       
 33399          expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
       
 33400        });
       
 33401      </file>
       
 33402    </example>
       
 33403  */
       
 33404 var ngStyleDirective = ngDirective(function(scope, element, attr) {
       
 33405   scope.$watch(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) {
       
 33406     if (oldStyles && (newStyles !== oldStyles)) {
       
 33407       forEach(oldStyles, function(val, style) { element.css(style, '');});
       
 33408     }
       
 33409     if (newStyles) element.css(newStyles);
       
 33410   }, true);
       
 33411 });
       
 33412 
       
 33413 /**
       
 33414  * @ngdoc directive
       
 33415  * @name ngSwitch
       
 33416  * @restrict EA
       
 33417  *
       
 33418  * @description
       
 33419  * The `ngSwitch` directive is used to conditionally swap DOM structure on your template based on a scope expression.
       
 33420  * Elements within `ngSwitch` but without `ngSwitchWhen` or `ngSwitchDefault` directives will be preserved at the location
       
 33421  * as specified in the template.
       
 33422  *
       
 33423  * The directive itself works similar to ngInclude, however, instead of downloading template code (or loading it
       
 33424  * from the template cache), `ngSwitch` simply chooses one of the nested elements and makes it visible based on which element
       
 33425  * matches the value obtained from the evaluated expression. In other words, you define a container element
       
 33426  * (where you place the directive), place an expression on the **`on="..."` attribute**
       
 33427  * (or the **`ng-switch="..."` attribute**), define any inner elements inside of the directive and place
       
 33428  * a when attribute per element. The when attribute is used to inform ngSwitch which element to display when the on
       
 33429  * expression is evaluated. If a matching expression is not found via a when attribute then an element with the default
       
 33430  * attribute is displayed.
       
 33431  *
       
 33432  * <div class="alert alert-info">
       
 33433  * Be aware that the attribute values to match against cannot be expressions. They are interpreted
       
 33434  * as literal string values to match against.
       
 33435  * For example, **`ng-switch-when="someVal"`** will match against the string `"someVal"` not against the
       
 33436  * value of the expression `$scope.someVal`.
       
 33437  * </div>
       
 33438 
       
 33439  * @animations
       
 33440  * enter - happens after the ngSwitch contents change and the matched child element is placed inside the container
       
 33441  * leave - happens just after the ngSwitch contents change and just before the former contents are removed from the DOM
       
 33442  *
       
 33443  * @usage
       
 33444  *
       
 33445  * ```
       
 33446  * <ANY ng-switch="expression">
       
 33447  *   <ANY ng-switch-when="matchValue1">...</ANY>
       
 33448  *   <ANY ng-switch-when="matchValue2">...</ANY>
       
 33449  *   <ANY ng-switch-default>...</ANY>
       
 33450  * </ANY>
       
 33451  * ```
       
 33452  *
       
 33453  *
       
 33454  * @scope
       
 33455  * @priority 1200
       
 33456  * @param {*} ngSwitch|on expression to match against <tt>ng-switch-when</tt>.
       
 33457  * On child elements add:
       
 33458  *
       
 33459  * * `ngSwitchWhen`: the case statement to match against. If match then this
       
 33460  *   case will be displayed. If the same match appears multiple times, all the
       
 33461  *   elements will be displayed.
       
 33462  * * `ngSwitchDefault`: the default case when no other case match. If there
       
 33463  *   are multiple default cases, all of them will be displayed when no other
       
 33464  *   case match.
       
 33465  *
       
 33466  *
       
 33467  * @example
       
 33468   <example module="switchExample" deps="angular-animate.js" animations="true">
       
 33469     <file name="index.html">
       
 33470       <div ng-controller="ExampleController">
       
 33471         <select ng-model="selection" ng-options="item for item in items">
       
 33472         </select>
       
 33473         <tt>selection={{selection}}</tt>
       
 33474         <hr/>
       
 33475         <div class="animate-switch-container"
       
 33476           ng-switch on="selection">
       
 33477             <div class="animate-switch" ng-switch-when="settings">Settings Div</div>
       
 33478             <div class="animate-switch" ng-switch-when="home">Home Span</div>
       
 33479             <div class="animate-switch" ng-switch-default>default</div>
       
 33480         </div>
       
 33481       </div>
       
 33482     </file>
       
 33483     <file name="script.js">
       
 33484       angular.module('switchExample', ['ngAnimate'])
       
 33485         .controller('ExampleController', ['$scope', function($scope) {
       
 33486           $scope.items = ['settings', 'home', 'other'];
       
 33487           $scope.selection = $scope.items[0];
       
 33488         }]);
       
 33489     </file>
       
 33490     <file name="animations.css">
       
 33491       .animate-switch-container {
       
 33492         position:relative;
       
 33493         background:white;
       
 33494         border:1px solid black;
       
 33495         height:40px;
       
 33496         overflow:hidden;
       
 33497       }
       
 33498 
       
 33499       .animate-switch {
       
 33500         padding:10px;
       
 33501       }
       
 33502 
       
 33503       .animate-switch.ng-animate {
       
 33504         -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
       
 33505         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
       
 33506 
       
 33507         position:absolute;
       
 33508         top:0;
       
 33509         left:0;
       
 33510         right:0;
       
 33511         bottom:0;
       
 33512       }
       
 33513 
       
 33514       .animate-switch.ng-leave.ng-leave-active,
       
 33515       .animate-switch.ng-enter {
       
 33516         top:-50px;
       
 33517       }
       
 33518       .animate-switch.ng-leave,
       
 33519       .animate-switch.ng-enter.ng-enter-active {
       
 33520         top:0;
       
 33521       }
       
 33522     </file>
       
 33523     <file name="protractor.js" type="protractor">
       
 33524       var switchElem = element(by.css('[ng-switch]'));
       
 33525       var select = element(by.model('selection'));
       
 33526 
       
 33527       it('should start in settings', function() {
       
 33528         expect(switchElem.getText()).toMatch(/Settings Div/);
       
 33529       });
       
 33530       it('should change to home', function() {
       
 33531         select.all(by.css('option')).get(1).click();
       
 33532         expect(switchElem.getText()).toMatch(/Home Span/);
       
 33533       });
       
 33534       it('should select default', function() {
       
 33535         select.all(by.css('option')).get(2).click();
       
 33536         expect(switchElem.getText()).toMatch(/default/);
       
 33537       });
       
 33538     </file>
       
 33539   </example>
       
 33540  */
       
 33541 var ngSwitchDirective = ['$animate', function($animate) {
       
 33542   return {
       
 33543     restrict: 'EA',
       
 33544     require: 'ngSwitch',
       
 33545 
       
 33546     // asks for $scope to fool the BC controller module
       
 33547     controller: ['$scope', function ngSwitchController() {
       
 33548      this.cases = {};
       
 33549     }],
       
 33550     link: function(scope, element, attr, ngSwitchController) {
       
 33551       var watchExpr = attr.ngSwitch || attr.on,
       
 33552           selectedTranscludes = [],
       
 33553           selectedElements = [],
       
 33554           previousLeaveAnimations = [],
       
 33555           selectedScopes = [];
       
 33556 
       
 33557       var spliceFactory = function(array, index) {
       
 33558           return function() { array.splice(index, 1); };
       
 33559       };
       
 33560 
       
 33561       scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
       
 33562         var i, ii;
       
 33563         for (i = 0, ii = previousLeaveAnimations.length; i < ii; ++i) {
       
 33564           $animate.cancel(previousLeaveAnimations[i]);
       
 33565         }
       
 33566         previousLeaveAnimations.length = 0;
       
 33567 
       
 33568         for (i = 0, ii = selectedScopes.length; i < ii; ++i) {
       
 33569           var selected = getBlockNodes(selectedElements[i].clone);
       
 33570           selectedScopes[i].$destroy();
       
 33571           var promise = previousLeaveAnimations[i] = $animate.leave(selected);
       
 33572           promise.then(spliceFactory(previousLeaveAnimations, i));
       
 33573         }
       
 33574 
       
 33575         selectedElements.length = 0;
       
 33576         selectedScopes.length = 0;
       
 33577 
       
 33578         if ((selectedTranscludes = ngSwitchController.cases['!' + value] || ngSwitchController.cases['?'])) {
       
 33579           forEach(selectedTranscludes, function(selectedTransclude) {
       
 33580             selectedTransclude.transclude(function(caseElement, selectedScope) {
       
 33581               selectedScopes.push(selectedScope);
       
 33582               var anchor = selectedTransclude.element;
       
 33583               caseElement[caseElement.length++] = document.createComment(' end ngSwitchWhen: ');
       
 33584               var block = { clone: caseElement };
       
 33585 
       
 33586               selectedElements.push(block);
       
 33587               $animate.enter(caseElement, anchor.parent(), anchor);
       
 33588             });
       
 33589           });
       
 33590         }
       
 33591       });
       
 33592     }
       
 33593   };
       
 33594 }];
       
 33595 
       
 33596 var ngSwitchWhenDirective = ngDirective({
       
 33597   transclude: 'element',
       
 33598   priority: 1200,
       
 33599   require: '^ngSwitch',
       
 33600   multiElement: true,
       
 33601   link: function(scope, element, attrs, ctrl, $transclude) {
       
 33602     ctrl.cases['!' + attrs.ngSwitchWhen] = (ctrl.cases['!' + attrs.ngSwitchWhen] || []);
       
 33603     ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: $transclude, element: element });
       
 33604   }
       
 33605 });
       
 33606 
       
 33607 var ngSwitchDefaultDirective = ngDirective({
       
 33608   transclude: 'element',
       
 33609   priority: 1200,
       
 33610   require: '^ngSwitch',
       
 33611   multiElement: true,
       
 33612   link: function(scope, element, attr, ctrl, $transclude) {
       
 33613     ctrl.cases['?'] = (ctrl.cases['?'] || []);
       
 33614     ctrl.cases['?'].push({ transclude: $transclude, element: element });
       
 33615    }
       
 33616 });
       
 33617 
       
 33618 /**
       
 33619  * @ngdoc directive
       
 33620  * @name ngTransclude
       
 33621  * @restrict EAC
       
 33622  *
       
 33623  * @description
       
 33624  * Directive that marks the insertion point for the transcluded DOM of the nearest parent directive that uses transclusion.
       
 33625  *
       
 33626  * Any existing content of the element that this directive is placed on will be removed before the transcluded content is inserted.
       
 33627  *
       
 33628  * @element ANY
       
 33629  *
       
 33630  * @example
       
 33631    <example module="transcludeExample">
       
 33632      <file name="index.html">
       
 33633        <script>
       
 33634          angular.module('transcludeExample', [])
       
 33635           .directive('pane', function(){
       
 33636              return {
       
 33637                restrict: 'E',
       
 33638                transclude: true,
       
 33639                scope: { title:'@' },
       
 33640                template: '<div style="border: 1px solid black;">' +
       
 33641                            '<div style="background-color: gray">{{title}}</div>' +
       
 33642                            '<ng-transclude></ng-transclude>' +
       
 33643                          '</div>'
       
 33644              };
       
 33645          })
       
 33646          .controller('ExampleController', ['$scope', function($scope) {
       
 33647            $scope.title = 'Lorem Ipsum';
       
 33648            $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
       
 33649          }]);
       
 33650        </script>
       
 33651        <div ng-controller="ExampleController">
       
 33652          <input ng-model="title"><br>
       
 33653          <textarea ng-model="text"></textarea> <br/>
       
 33654          <pane title="{{title}}">{{text}}</pane>
       
 33655        </div>
       
 33656      </file>
       
 33657      <file name="protractor.js" type="protractor">
       
 33658         it('should have transcluded', function() {
       
 33659           var titleElement = element(by.model('title'));
       
 33660           titleElement.clear();
       
 33661           titleElement.sendKeys('TITLE');
       
 33662           var textElement = element(by.model('text'));
       
 33663           textElement.clear();
       
 33664           textElement.sendKeys('TEXT');
       
 33665           expect(element(by.binding('title')).getText()).toEqual('TITLE');
       
 33666           expect(element(by.binding('text')).getText()).toEqual('TEXT');
       
 33667         });
       
 33668      </file>
       
 33669    </example>
       
 33670  *
       
 33671  */
       
 33672 var ngTranscludeDirective = ngDirective({
       
 33673   restrict: 'EAC',
       
 33674   link: function($scope, $element, $attrs, controller, $transclude) {
       
 33675     if (!$transclude) {
       
 33676       throw minErr('ngTransclude')('orphan',
       
 33677        'Illegal use of ngTransclude directive in the template! ' +
       
 33678        'No parent directive that requires a transclusion found. ' +
       
 33679        'Element: {0}',
       
 33680        startingTag($element));
       
 33681     }
       
 33682 
       
 33683     $transclude(function(clone) {
       
 33684       $element.empty();
       
 33685       $element.append(clone);
       
 33686     });
       
 33687   }
       
 33688 });
       
 33689 
       
 33690 /**
       
 33691  * @ngdoc directive
       
 33692  * @name script
       
 33693  * @restrict E
       
 33694  *
       
 33695  * @description
       
 33696  * Load the content of a `<script>` element into {@link ng.$templateCache `$templateCache`}, so that the
       
 33697  * template can be used by {@link ng.directive:ngInclude `ngInclude`},
       
 33698  * {@link ngRoute.directive:ngView `ngView`}, or {@link guide/directive directives}. The type of the
       
 33699  * `<script>` element must be specified as `text/ng-template`, and a cache name for the template must be
       
 33700  * assigned through the element's `id`, which can then be used as a directive's `templateUrl`.
       
 33701  *
       
 33702  * @param {string} type Must be set to `'text/ng-template'`.
       
 33703  * @param {string} id Cache name of the template.
       
 33704  *
       
 33705  * @example
       
 33706   <example>
       
 33707     <file name="index.html">
       
 33708       <script type="text/ng-template" id="/tpl.html">
       
 33709         Content of the template.
       
 33710       </script>
       
 33711 
       
 33712       <a ng-click="currentTpl='/tpl.html'" id="tpl-link">Load inlined template</a>
       
 33713       <div id="tpl-content" ng-include src="currentTpl"></div>
       
 33714     </file>
       
 33715     <file name="protractor.js" type="protractor">
       
 33716       it('should load template defined inside script tag', function() {
       
 33717         element(by.css('#tpl-link')).click();
       
 33718         expect(element(by.css('#tpl-content')).getText()).toMatch(/Content of the template/);
       
 33719       });
       
 33720     </file>
       
 33721   </example>
       
 33722  */
       
 33723 var scriptDirective = ['$templateCache', function($templateCache) {
       
 33724   return {
       
 33725     restrict: 'E',
       
 33726     terminal: true,
       
 33727     compile: function(element, attr) {
       
 33728       if (attr.type == 'text/ng-template') {
       
 33729         var templateUrl = attr.id,
       
 33730             // IE is not consistent, in scripts we have to read .text but in other nodes we have to read .textContent
       
 33731             text = element[0].text;
       
 33732 
       
 33733         $templateCache.put(templateUrl, text);
       
 33734       }
       
 33735     }
       
 33736   };
       
 33737 }];
       
 33738 
       
 33739 var ngOptionsMinErr = minErr('ngOptions');
       
 33740 /**
       
 33741  * @ngdoc directive
       
 33742  * @name select
       
 33743  * @restrict E
       
 33744  *
       
 33745  * @description
       
 33746  * HTML `SELECT` element with angular data-binding.
       
 33747  *
       
 33748  * # `ngOptions`
       
 33749  *
       
 33750  * The `ngOptions` attribute can be used to dynamically generate a list of `<option>`
       
 33751  * elements for the `<select>` element using the array or object obtained by evaluating the
       
 33752  * `ngOptions` comprehension_expression.
       
 33753  *
       
 33754  * When an item in the `<select>` menu is selected, the array element or object property
       
 33755  * represented by the selected option will be bound to the model identified by the `ngModel`
       
 33756  * directive.
       
 33757  *
       
 33758  * <div class="alert alert-warning">
       
 33759  * **Note:** `ngModel` compares by reference, not value. This is important when binding to an
       
 33760  * array of objects. See an example [in this jsfiddle](http://jsfiddle.net/qWzTb/).
       
 33761  * </div>
       
 33762  *
       
 33763  * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
       
 33764  * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
       
 33765  * option. See example below for demonstration.
       
 33766  *
       
 33767  * <div class="alert alert-warning">
       
 33768  * **Note:** `ngOptions` provides an iterator facility for the `<option>` element which should be used instead
       
 33769  * of {@link ng.directive:ngRepeat ngRepeat} when you want the
       
 33770  * `select` model to be bound to a non-string value. This is because an option element can only
       
 33771  * be bound to string values at present.
       
 33772  * </div>
       
 33773  *
       
 33774  * <div class="alert alert-info">
       
 33775  * **Note:** Using `select as` will bind the result of the `select as` expression to the model, but
       
 33776  * the value of the `<select>` and `<option>` html elements will be either the index (for array data sources)
       
 33777  * or property name (for object data sources) of the value  within the collection.
       
 33778  * </div>
       
 33779  *
       
 33780  * @param {string} ngModel Assignable angular expression to data-bind to.
       
 33781  * @param {string=} name Property name of the form under which the control is published.
       
 33782  * @param {string=} required The control is considered valid only if value is entered.
       
 33783  * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
       
 33784  *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
       
 33785  *    `required` when you want to data-bind to the `required` attribute.
       
 33786  * @param {comprehension_expression=} ngOptions in one of the following forms:
       
 33787  *
       
 33788  *   * for array data sources:
       
 33789  *     * `label` **`for`** `value` **`in`** `array`
       
 33790  *     * `select` **`as`** `label` **`for`** `value` **`in`** `array`
       
 33791  *     * `label`  **`group by`** `group` **`for`** `value` **`in`** `array`
       
 33792  *     * `select` **`as`** `label` **`group by`** `group` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
       
 33793  *   * for object data sources:
       
 33794  *     * `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
       
 33795  *     * `select` **`as`** `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
       
 33796  *     * `label` **`group by`** `group` **`for (`**`key`**`,`** `value`**`) in`** `object`
       
 33797  *     * `select` **`as`** `label` **`group by`** `group`
       
 33798  *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
       
 33799  *
       
 33800  * Where:
       
 33801  *
       
 33802  *   * `array` / `object`: an expression which evaluates to an array / object to iterate over.
       
 33803  *   * `value`: local variable which will refer to each item in the `array` or each property value
       
 33804  *      of `object` during iteration.
       
 33805  *   * `key`: local variable which will refer to a property name in `object` during iteration.
       
 33806  *   * `label`: The result of this expression will be the label for `<option>` element. The
       
 33807  *     `expression` will most likely refer to the `value` variable (e.g. `value.propertyName`).
       
 33808  *   * `select`: The result of this expression will be bound to the model of the parent `<select>`
       
 33809  *      element. If not specified, `select` expression will default to `value`.
       
 33810  *   * `group`: The result of this expression will be used to group options using the `<optgroup>`
       
 33811  *      DOM element.
       
 33812  *   * `trackexpr`: Used when working with an array of objects. The result of this expression will be
       
 33813  *      used to identify the objects in the array. The `trackexpr` will most likely refer to the
       
 33814  *     `value` variable (e.g. `value.propertyName`). With this the selection is preserved
       
 33815  *      even when the options are recreated (e.g. reloaded from the server).
       
 33816 
       
 33817  * <div class="alert alert-info">
       
 33818  * **Note:** Using `select as` together with `trackexpr` is not possible (and will throw).
       
 33819  * Reasoning:
       
 33820  * - Example: <select ng-options="item.subItem as item.label for item in values track by item.id" ng-model="selected">
       
 33821  *   values: [{id: 1, label: 'aLabel', subItem: {name: 'aSubItem'}}, {id: 2, label: 'bLabel', subItem: {name: 'bSubItemß'}}],
       
 33822  *   $scope.selected = {name: 'aSubItem'};
       
 33823  * - track by is always applied to `value`, with purpose to preserve the selection,
       
 33824  *   (to `item` in this case)
       
 33825  * - to calculate whether an item is selected we do the following:
       
 33826  *   1. apply `track by` to the values in the array, e.g.
       
 33827  *      In the example: [1,2]
       
 33828  *   2. apply `track by` to the already selected value in `ngModel`:
       
 33829  *      In the example: this is not possible, as `track by` refers to `item.id`, but the selected
       
 33830  *      value from `ngModel` is `{name: aSubItem}`.
       
 33831  *
       
 33832  * </div>
       
 33833  *
       
 33834  * @example
       
 33835     <example module="selectExample">
       
 33836       <file name="index.html">
       
 33837         <script>
       
 33838         angular.module('selectExample', [])
       
 33839           .controller('ExampleController', ['$scope', function($scope) {
       
 33840             $scope.colors = [
       
 33841               {name:'black', shade:'dark'},
       
 33842               {name:'white', shade:'light'},
       
 33843               {name:'red', shade:'dark'},
       
 33844               {name:'blue', shade:'dark'},
       
 33845               {name:'yellow', shade:'light'}
       
 33846             ];
       
 33847             $scope.myColor = $scope.colors[2]; // red
       
 33848           }]);
       
 33849         </script>
       
 33850         <div ng-controller="ExampleController">
       
 33851           <ul>
       
 33852             <li ng-repeat="color in colors">
       
 33853               Name: <input ng-model="color.name">
       
 33854               [<a href ng-click="colors.splice($index, 1)">X</a>]
       
 33855             </li>
       
 33856             <li>
       
 33857               [<a href ng-click="colors.push({})">add</a>]
       
 33858             </li>
       
 33859           </ul>
       
 33860           <hr/>
       
 33861           Color (null not allowed):
       
 33862           <select ng-model="myColor" ng-options="color.name for color in colors"></select><br>
       
 33863 
       
 33864           Color (null allowed):
       
 33865           <span  class="nullable">
       
 33866             <select ng-model="myColor" ng-options="color.name for color in colors">
       
 33867               <option value="">-- choose color --</option>
       
 33868             </select>
       
 33869           </span><br/>
       
 33870 
       
 33871           Color grouped by shade:
       
 33872           <select ng-model="myColor" ng-options="color.name group by color.shade for color in colors">
       
 33873           </select><br/>
       
 33874 
       
 33875 
       
 33876           Select <a href ng-click="myColor = { name:'not in list', shade: 'other' }">bogus</a>.<br>
       
 33877           <hr/>
       
 33878           Currently selected: {{ {selected_color:myColor} }}
       
 33879           <div style="border:solid 1px black; height:20px"
       
 33880                ng-style="{'background-color':myColor.name}">
       
 33881           </div>
       
 33882         </div>
       
 33883       </file>
       
 33884       <file name="protractor.js" type="protractor">
       
 33885          it('should check ng-options', function() {
       
 33886            expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('red');
       
 33887            element.all(by.model('myColor')).first().click();
       
 33888            element.all(by.css('select[ng-model="myColor"] option')).first().click();
       
 33889            expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('black');
       
 33890            element(by.css('.nullable select[ng-model="myColor"]')).click();
       
 33891            element.all(by.css('.nullable select[ng-model="myColor"] option')).first().click();
       
 33892            expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('null');
       
 33893          });
       
 33894       </file>
       
 33895     </example>
       
 33896  */
       
 33897 
       
 33898 var ngOptionsDirective = valueFn({
       
 33899   restrict: 'A',
       
 33900   terminal: true
       
 33901 });
       
 33902 
       
 33903 // jshint maxlen: false
       
 33904 var selectDirective = ['$compile', '$parse', function($compile,   $parse) {
       
 33905                          //000011111111110000000000022222222220000000000000000000003333333333000000000000004444444444444440000000005555555555555550000000666666666666666000000000000000777777777700000000000000000008888888888
       
 33906   var NG_OPTIONS_REGEXP = /^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?$/,
       
 33907       nullModelCtrl = {$setViewValue: noop};
       
 33908 // jshint maxlen: 100
       
 33909 
       
 33910   return {
       
 33911     restrict: 'E',
       
 33912     require: ['select', '?ngModel'],
       
 33913     controller: ['$element', '$scope', '$attrs', function($element, $scope, $attrs) {
       
 33914       var self = this,
       
 33915           optionsMap = {},
       
 33916           ngModelCtrl = nullModelCtrl,
       
 33917           nullOption,
       
 33918           unknownOption;
       
 33919 
       
 33920 
       
 33921       self.databound = $attrs.ngModel;
       
 33922 
       
 33923 
       
 33924       self.init = function(ngModelCtrl_, nullOption_, unknownOption_) {
       
 33925         ngModelCtrl = ngModelCtrl_;
       
 33926         nullOption = nullOption_;
       
 33927         unknownOption = unknownOption_;
       
 33928       };
       
 33929 
       
 33930 
       
 33931       self.addOption = function(value, element) {
       
 33932         assertNotHasOwnProperty(value, '"option value"');
       
 33933         optionsMap[value] = true;
       
 33934 
       
 33935         if (ngModelCtrl.$viewValue == value) {
       
 33936           $element.val(value);
       
 33937           if (unknownOption.parent()) unknownOption.remove();
       
 33938         }
       
 33939         // Workaround for https://code.google.com/p/chromium/issues/detail?id=381459
       
 33940         // Adding an <option selected="selected"> element to a <select required="required"> should
       
 33941         // automatically select the new element
       
 33942         if (element[0].hasAttribute('selected')) {
       
 33943           element[0].selected = true;
       
 33944         }
       
 33945       };
       
 33946 
       
 33947 
       
 33948       self.removeOption = function(value) {
       
 33949         if (this.hasOption(value)) {
       
 33950           delete optionsMap[value];
       
 33951           if (ngModelCtrl.$viewValue == value) {
       
 33952             this.renderUnknownOption(value);
       
 33953           }
       
 33954         }
       
 33955       };
       
 33956 
       
 33957 
       
 33958       self.renderUnknownOption = function(val) {
       
 33959         var unknownVal = '? ' + hashKey(val) + ' ?';
       
 33960         unknownOption.val(unknownVal);
       
 33961         $element.prepend(unknownOption);
       
 33962         $element.val(unknownVal);
       
 33963         unknownOption.prop('selected', true); // needed for IE
       
 33964       };
       
 33965 
       
 33966 
       
 33967       self.hasOption = function(value) {
       
 33968         return optionsMap.hasOwnProperty(value);
       
 33969       };
       
 33970 
       
 33971       $scope.$on('$destroy', function() {
       
 33972         // disable unknown option so that we don't do work when the whole select is being destroyed
       
 33973         self.renderUnknownOption = noop;
       
 33974       });
       
 33975     }],
       
 33976 
       
 33977     link: function(scope, element, attr, ctrls) {
       
 33978       // if ngModel is not defined, we don't need to do anything
       
 33979       if (!ctrls[1]) return;
       
 33980 
       
 33981       var selectCtrl = ctrls[0],
       
 33982           ngModelCtrl = ctrls[1],
       
 33983           multiple = attr.multiple,
       
 33984           optionsExp = attr.ngOptions,
       
 33985           nullOption = false, // if false, user will not be able to select it (used by ngOptions)
       
 33986           emptyOption,
       
 33987           renderScheduled = false,
       
 33988           // we can't just jqLite('<option>') since jqLite is not smart enough
       
 33989           // to create it in <select> and IE barfs otherwise.
       
 33990           optionTemplate = jqLite(document.createElement('option')),
       
 33991           optGroupTemplate =jqLite(document.createElement('optgroup')),
       
 33992           unknownOption = optionTemplate.clone();
       
 33993 
       
 33994       // find "null" option
       
 33995       for(var i = 0, children = element.children(), ii = children.length; i < ii; i++) {
       
 33996         if (children[i].value === '') {
       
 33997           emptyOption = nullOption = children.eq(i);
       
 33998           break;
       
 33999         }
       
 34000       }
       
 34001 
       
 34002       selectCtrl.init(ngModelCtrl, nullOption, unknownOption);
       
 34003 
       
 34004       // required validator
       
 34005       if (multiple) {
       
 34006         ngModelCtrl.$isEmpty = function(value) {
       
 34007           return !value || value.length === 0;
       
 34008         };
       
 34009       }
       
 34010 
       
 34011       if (optionsExp) setupAsOptions(scope, element, ngModelCtrl);
       
 34012       else if (multiple) setupAsMultiple(scope, element, ngModelCtrl);
       
 34013       else setupAsSingle(scope, element, ngModelCtrl, selectCtrl);
       
 34014 
       
 34015 
       
 34016       ////////////////////////////
       
 34017 
       
 34018 
       
 34019 
       
 34020       function setupAsSingle(scope, selectElement, ngModelCtrl, selectCtrl) {
       
 34021         ngModelCtrl.$render = function() {
       
 34022           var viewValue = ngModelCtrl.$viewValue;
       
 34023 
       
 34024           if (selectCtrl.hasOption(viewValue)) {
       
 34025             if (unknownOption.parent()) unknownOption.remove();
       
 34026             selectElement.val(viewValue);
       
 34027             if (viewValue === '') emptyOption.prop('selected', true); // to make IE9 happy
       
 34028           } else {
       
 34029             if (isUndefined(viewValue) && emptyOption) {
       
 34030               selectElement.val('');
       
 34031             } else {
       
 34032               selectCtrl.renderUnknownOption(viewValue);
       
 34033             }
       
 34034           }
       
 34035         };
       
 34036 
       
 34037         selectElement.on('change', function() {
       
 34038           scope.$apply(function() {
       
 34039             if (unknownOption.parent()) unknownOption.remove();
       
 34040             ngModelCtrl.$setViewValue(selectElement.val());
       
 34041           });
       
 34042         });
       
 34043       }
       
 34044 
       
 34045       function setupAsMultiple(scope, selectElement, ctrl) {
       
 34046         var lastView;
       
 34047         ctrl.$render = function() {
       
 34048           var items = new HashMap(ctrl.$viewValue);
       
 34049           forEach(selectElement.find('option'), function(option) {
       
 34050             option.selected = isDefined(items.get(option.value));
       
 34051           });
       
 34052         };
       
 34053 
       
 34054         // we have to do it on each watch since ngModel watches reference, but
       
 34055         // we need to work of an array, so we need to see if anything was inserted/removed
       
 34056         scope.$watch(function selectMultipleWatch() {
       
 34057           if (!equals(lastView, ctrl.$viewValue)) {
       
 34058             lastView = shallowCopy(ctrl.$viewValue);
       
 34059             ctrl.$render();
       
 34060           }
       
 34061         });
       
 34062 
       
 34063         selectElement.on('change', function() {
       
 34064           scope.$apply(function() {
       
 34065             var array = [];
       
 34066             forEach(selectElement.find('option'), function(option) {
       
 34067               if (option.selected) {
       
 34068                 array.push(option.value);
       
 34069               }
       
 34070             });
       
 34071             ctrl.$setViewValue(array);
       
 34072           });
       
 34073         });
       
 34074       }
       
 34075 
       
 34076       function setupAsOptions(scope, selectElement, ctrl) {
       
 34077         var match;
       
 34078 
       
 34079         if (!(match = optionsExp.match(NG_OPTIONS_REGEXP))) {
       
 34080           throw ngOptionsMinErr('iexp',
       
 34081             "Expected expression in form of " +
       
 34082             "'_select_ (as _label_)? for (_key_,)?_value_ in _collection_'" +
       
 34083             " but got '{0}'. Element: {1}",
       
 34084             optionsExp, startingTag(selectElement));
       
 34085         }
       
 34086 
       
 34087         var displayFn = $parse(match[2] || match[1]),
       
 34088             valueName = match[4] || match[6],
       
 34089             selectAs = / as /.test(match[0]) && match[1],
       
 34090             selectAsFn = selectAs ? $parse(selectAs) : null,
       
 34091             keyName = match[5],
       
 34092             groupByFn = $parse(match[3] || ''),
       
 34093             valueFn = $parse(match[2] ? match[1] : valueName),
       
 34094             valuesFn = $parse(match[7]),
       
 34095             track = match[8],
       
 34096             trackFn = track ? $parse(match[8]) : null,
       
 34097             // This is an array of array of existing option groups in DOM.
       
 34098             // We try to reuse these if possible
       
 34099             // - optionGroupsCache[0] is the options with no option group
       
 34100             // - optionGroupsCache[?][0] is the parent: either the SELECT or OPTGROUP element
       
 34101             optionGroupsCache = [[{element: selectElement, label:''}]],
       
 34102             //re-usable object to represent option's locals
       
 34103             locals = {};
       
 34104 
       
 34105         if (trackFn && selectAsFn) {
       
 34106           throw ngOptionsMinErr('trkslct',
       
 34107             "Comprehension expression cannot contain both selectAs '{0}' " +
       
 34108             "and trackBy '{1}' expressions.",
       
 34109             selectAs, track);
       
 34110         }
       
 34111 
       
 34112         if (nullOption) {
       
 34113           // compile the element since there might be bindings in it
       
 34114           $compile(nullOption)(scope);
       
 34115 
       
 34116           // remove the class, which is added automatically because we recompile the element and it
       
 34117           // becomes the compilation root
       
 34118           nullOption.removeClass('ng-scope');
       
 34119 
       
 34120           // we need to remove it before calling selectElement.empty() because otherwise IE will
       
 34121           // remove the label from the element. wtf?
       
 34122           nullOption.remove();
       
 34123         }
       
 34124 
       
 34125         // clear contents, we'll add what's needed based on the model
       
 34126         selectElement.empty();
       
 34127 
       
 34128         selectElement.on('change', selectionChanged);
       
 34129 
       
 34130         ctrl.$render = render;
       
 34131 
       
 34132         scope.$watchCollection(valuesFn, scheduleRendering);
       
 34133         scope.$watchCollection(getLabels, scheduleRendering);
       
 34134 
       
 34135         if (multiple) {
       
 34136           scope.$watchCollection(function() { return ctrl.$modelValue; }, scheduleRendering);
       
 34137         }
       
 34138 
       
 34139         // ------------------------------------------------------------------ //
       
 34140 
       
 34141         function callExpression(exprFn, key, value) {
       
 34142           locals[valueName] = value;
       
 34143           if (keyName) locals[keyName] = key;
       
 34144           return exprFn(scope, locals);
       
 34145         }
       
 34146 
       
 34147         function selectionChanged() {
       
 34148           scope.$apply(function() {
       
 34149             var optionGroup,
       
 34150                 collection = valuesFn(scope) || [],
       
 34151                 key, value, optionElement, index, groupIndex, length, groupLength, trackIndex;
       
 34152             var viewValue;
       
 34153             if (multiple) {
       
 34154               viewValue = [];
       
 34155               forEach(selectElement.val(), function(selectedKey) {
       
 34156                 viewValue.push(getViewValue(selectedKey, collection[selectedKey]));
       
 34157               });
       
 34158             } else {
       
 34159               var selectedKey = selectElement.val();
       
 34160               viewValue = getViewValue(selectedKey, collection[selectedKey]);
       
 34161             }
       
 34162             ctrl.$setViewValue(viewValue);
       
 34163             render();
       
 34164           });
       
 34165         }
       
 34166 
       
 34167         function getViewValue(key, value) {
       
 34168           if (key === '?') {
       
 34169             return undefined;
       
 34170           } else if (key === '') {
       
 34171             return null;
       
 34172           } else {
       
 34173             var viewValueFn = selectAsFn ? selectAsFn : valueFn;
       
 34174             return callExpression(viewValueFn, key, value);
       
 34175           }
       
 34176         }
       
 34177 
       
 34178         function getLabels() {
       
 34179           var values = valuesFn(scope);
       
 34180           var toDisplay;
       
 34181           if (values && isArray(values)) {
       
 34182             toDisplay = new Array(values.length);
       
 34183             for (var i = 0, ii = values.length; i < ii; i++) {
       
 34184               toDisplay[i] = callExpression(displayFn, i, values[i]);
       
 34185             }
       
 34186             return toDisplay;
       
 34187           } else if (values) {
       
 34188             // TODO: Add a test for this case
       
 34189             toDisplay = {};
       
 34190             for (var prop in values) {
       
 34191               if (values.hasOwnProperty(prop)) {
       
 34192                 toDisplay[prop] = callExpression(displayFn, prop, values[prop]);
       
 34193               }
       
 34194             }
       
 34195           }
       
 34196           return toDisplay;
       
 34197         }
       
 34198 
       
 34199         function createIsSelectedFn(viewValue) {
       
 34200           var selectedSet;
       
 34201           if (multiple) {
       
 34202             if (!selectAs && trackFn && isArray(viewValue)) {
       
 34203 
       
 34204               selectedSet = new HashMap([]);
       
 34205               for (var trackIndex = 0; trackIndex < viewValue.length; trackIndex++) {
       
 34206                 // tracking by key
       
 34207                 selectedSet.put(callExpression(trackFn, null, viewValue[trackIndex]), true);
       
 34208               }
       
 34209             } else {
       
 34210               selectedSet = new HashMap(viewValue);
       
 34211             }
       
 34212           } else if (!selectAsFn && trackFn) {
       
 34213             viewValue = callExpression(trackFn, null, viewValue);
       
 34214           }
       
 34215           return function isSelected(key, value) {
       
 34216             var compareValueFn;
       
 34217             if (selectAsFn) {
       
 34218               compareValueFn = selectAsFn;
       
 34219             } else if (trackFn) {
       
 34220               compareValueFn = trackFn;
       
 34221             } else {
       
 34222               compareValueFn = valueFn;
       
 34223             }
       
 34224 
       
 34225             if (multiple) {
       
 34226               return isDefined(selectedSet.remove(callExpression(compareValueFn, key, value)));
       
 34227             } else {
       
 34228               return viewValue == callExpression(compareValueFn, key, value);
       
 34229             }
       
 34230           };
       
 34231         }
       
 34232 
       
 34233         function scheduleRendering() {
       
 34234           if (!renderScheduled) {
       
 34235             scope.$$postDigest(render);
       
 34236             renderScheduled = true;
       
 34237           }
       
 34238         }
       
 34239 
       
 34240         function render() {
       
 34241           renderScheduled = false;
       
 34242 
       
 34243           // Temporary location for the option groups before we render them
       
 34244           var optionGroups = {'':[]},
       
 34245               optionGroupNames = [''],
       
 34246               optionGroupName,
       
 34247               optionGroup,
       
 34248               option,
       
 34249               existingParent, existingOptions, existingOption,
       
 34250               viewValue = ctrl.$viewValue,
       
 34251               values = valuesFn(scope) || [],
       
 34252               keys = keyName ? sortedKeys(values) : values,
       
 34253               key,
       
 34254               value,
       
 34255               groupLength, length,
       
 34256               groupIndex, index,
       
 34257               selected,
       
 34258               isSelected = createIsSelectedFn(viewValue),
       
 34259               anySelected = false,
       
 34260               lastElement,
       
 34261               element,
       
 34262               label;
       
 34263 
       
 34264           // We now build up the list of options we need (we merge later)
       
 34265           for (index = 0; length = keys.length, index < length; index++) {
       
 34266             key = index;
       
 34267             if (keyName) {
       
 34268               key = keys[index];
       
 34269               if ( key.charAt(0) === '$' ) continue;
       
 34270             }
       
 34271             value = values[key];
       
 34272 
       
 34273             optionGroupName = callExpression(groupByFn, key, value) || '';
       
 34274             if (!(optionGroup = optionGroups[optionGroupName])) {
       
 34275               optionGroup = optionGroups[optionGroupName] = [];
       
 34276               optionGroupNames.push(optionGroupName);
       
 34277             }
       
 34278 
       
 34279             selected = isSelected(key, value);
       
 34280             anySelected = anySelected || selected;
       
 34281 
       
 34282             label = callExpression(displayFn, key, value); // what will be seen by the user
       
 34283 
       
 34284             // doing displayFn(scope, locals) || '' overwrites zero values
       
 34285             label = isDefined(label) ? label : '';
       
 34286             optionGroup.push({
       
 34287               // either the index into array or key from object
       
 34288               id: (keyName ? keys[index] : index),
       
 34289               label: label,
       
 34290               selected: selected                   // determine if we should be selected
       
 34291             });
       
 34292           }
       
 34293           if (!multiple) {
       
 34294             if (nullOption || viewValue === null) {
       
 34295               // insert null option if we have a placeholder, or the model is null
       
 34296               optionGroups[''].unshift({id:'', label:'', selected:!anySelected});
       
 34297             } else if (!anySelected) {
       
 34298               // option could not be found, we have to insert the undefined item
       
 34299               optionGroups[''].unshift({id:'?', label:'', selected:true});
       
 34300             }
       
 34301           }
       
 34302 
       
 34303           // Now we need to update the list of DOM nodes to match the optionGroups we computed above
       
 34304           for (groupIndex = 0, groupLength = optionGroupNames.length;
       
 34305                groupIndex < groupLength;
       
 34306                groupIndex++) {
       
 34307             // current option group name or '' if no group
       
 34308             optionGroupName = optionGroupNames[groupIndex];
       
 34309 
       
 34310             // list of options for that group. (first item has the parent)
       
 34311             optionGroup = optionGroups[optionGroupName];
       
 34312 
       
 34313             if (optionGroupsCache.length <= groupIndex) {
       
 34314               // we need to grow the optionGroups
       
 34315               existingParent = {
       
 34316                 element: optGroupTemplate.clone().attr('label', optionGroupName),
       
 34317                 label: optionGroup.label
       
 34318               };
       
 34319               existingOptions = [existingParent];
       
 34320               optionGroupsCache.push(existingOptions);
       
 34321               selectElement.append(existingParent.element);
       
 34322             } else {
       
 34323               existingOptions = optionGroupsCache[groupIndex];
       
 34324               existingParent = existingOptions[0];  // either SELECT (no group) or OPTGROUP element
       
 34325 
       
 34326               // update the OPTGROUP label if not the same.
       
 34327               if (existingParent.label != optionGroupName) {
       
 34328                 existingParent.element.attr('label', existingParent.label = optionGroupName);
       
 34329               }
       
 34330             }
       
 34331 
       
 34332             lastElement = null;  // start at the beginning
       
 34333             for(index = 0, length = optionGroup.length; index < length; index++) {
       
 34334               option = optionGroup[index];
       
 34335               if ((existingOption = existingOptions[index+1])) {
       
 34336                 // reuse elements
       
 34337                 lastElement = existingOption.element;
       
 34338                 if (existingOption.label !== option.label) {
       
 34339                   lastElement.text(existingOption.label = option.label);
       
 34340                 }
       
 34341                 if (existingOption.id !== option.id) {
       
 34342                   lastElement.val(existingOption.id = option.id);
       
 34343                 }
       
 34344                 // lastElement.prop('selected') provided by jQuery has side-effects
       
 34345                 if (lastElement[0].selected !== option.selected) {
       
 34346                   lastElement.prop('selected', (existingOption.selected = option.selected));
       
 34347                   if (msie) {
       
 34348                     // See #7692
       
 34349                     // The selected item wouldn't visually update on IE without this.
       
 34350                     // Tested on Win7: IE9, IE10 and IE11. Future IEs should be tested as well
       
 34351                     lastElement.prop('selected', existingOption.selected);
       
 34352                   }
       
 34353                 }
       
 34354               } else {
       
 34355                 // grow elements
       
 34356 
       
 34357                 // if it's a null option
       
 34358                 if (option.id === '' && nullOption) {
       
 34359                   // put back the pre-compiled element
       
 34360                   element = nullOption;
       
 34361                 } else {
       
 34362                   // jQuery(v1.4.2) Bug: We should be able to chain the method calls, but
       
 34363                   // in this version of jQuery on some browser the .text() returns a string
       
 34364                   // rather then the element.
       
 34365                   (element = optionTemplate.clone())
       
 34366                       .val(option.id)
       
 34367                       .prop('selected', option.selected)
       
 34368                       .attr('selected', option.selected)
       
 34369                       .text(option.label);
       
 34370                 }
       
 34371 
       
 34372                 existingOptions.push(existingOption = {
       
 34373                     element: element,
       
 34374                     label: option.label,
       
 34375                     id: option.id,
       
 34376                     selected: option.selected
       
 34377                 });
       
 34378                 selectCtrl.addOption(option.label, element);
       
 34379                 if (lastElement) {
       
 34380                   lastElement.after(element);
       
 34381                 } else {
       
 34382                   existingParent.element.append(element);
       
 34383                 }
       
 34384                 lastElement = element;
       
 34385               }
       
 34386             }
       
 34387             // remove any excessive OPTIONs in a group
       
 34388             index++; // increment since the existingOptions[0] is parent element not OPTION
       
 34389             while(existingOptions.length > index) {
       
 34390               option = existingOptions.pop();
       
 34391               selectCtrl.removeOption(option.label);
       
 34392               option.element.remove();
       
 34393             }
       
 34394           }
       
 34395           // remove any excessive OPTGROUPs from select
       
 34396           while(optionGroupsCache.length > groupIndex) {
       
 34397             optionGroupsCache.pop()[0].element.remove();
       
 34398           }
       
 34399         }
       
 34400       }
       
 34401     }
       
 34402   };
       
 34403 }];
       
 34404 
       
 34405 var optionDirective = ['$interpolate', function($interpolate) {
       
 34406   var nullSelectCtrl = {
       
 34407     addOption: noop,
       
 34408     removeOption: noop
       
 34409   };
       
 34410 
       
 34411   return {
       
 34412     restrict: 'E',
       
 34413     priority: 100,
       
 34414     compile: function(element, attr) {
       
 34415       if (isUndefined(attr.value)) {
       
 34416         var interpolateFn = $interpolate(element.text(), true);
       
 34417         if (!interpolateFn) {
       
 34418           attr.$set('value', element.text());
       
 34419         }
       
 34420       }
       
 34421 
       
 34422       return function (scope, element, attr) {
       
 34423         var selectCtrlName = '$selectController',
       
 34424             parent = element.parent(),
       
 34425             selectCtrl = parent.data(selectCtrlName) ||
       
 34426               parent.parent().data(selectCtrlName); // in case we are in optgroup
       
 34427 
       
 34428         if (!selectCtrl || !selectCtrl.databound) {
       
 34429           selectCtrl = nullSelectCtrl;
       
 34430         }
       
 34431 
       
 34432         if (interpolateFn) {
       
 34433           scope.$watch(interpolateFn, function interpolateWatchAction(newVal, oldVal) {
       
 34434             attr.$set('value', newVal);
       
 34435             if (oldVal !== newVal) {
       
 34436               selectCtrl.removeOption(oldVal);
       
 34437             }
       
 34438             selectCtrl.addOption(newVal, element);
       
 34439           });
       
 34440         } else {
       
 34441           selectCtrl.addOption(attr.value, element);
       
 34442         }
       
 34443 
       
 34444         element.on('$destroy', function() {
       
 34445           selectCtrl.removeOption(attr.value);
       
 34446         });
       
 34447       };
       
 34448     }
       
 34449   };
       
 34450 }];
       
 34451 
       
 34452 var styleDirective = valueFn({
       
 34453   restrict: 'E',
       
 34454   terminal: false
       
 34455 });
       
 34456 
       
 34457   if (window.angular.bootstrap) {
       
 34458     //AngularJS is already loaded, so we can return here...
       
 34459     console.log('WARNING: Tried to load angular more than once.');
       
 34460     return;
       
 34461   }
       
 34462 
       
 34463   //try to bind to jquery now so that one can write jqLite(document).ready()
       
 34464   //but we will rebind on bootstrap again.
       
 34465   bindJQuery();
       
 34466 
       
 34467   publishExternalAPI(angular);
       
 34468 
       
 34469   jqLite(document).ready(function() {
       
 34470     angularInit(document, bootstrap);
       
 34471   });
       
 34472 
       
 34473 })(window, document);
       
 34474 
       
 34475 !window.angular.$$csp() && window.angular.element(document).find('head').prepend('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide:not(.ng-hide-animate){display:none !important;}ng\\:form{display:block;}</style>');
       
 34476 /*
       
 34477  * angular-ui-bootstrap
       
 34478  * http://angular-ui.github.io/bootstrap/
       
 34479 
       
 34480  * Version: 0.11.2 - 2014-09-26
       
 34481  * License: MIT
       
 34482  */
       
 34483 angular.module("ui.bootstrap", ["ui.bootstrap.tpls", "ui.bootstrap.transition","ui.bootstrap.collapse","ui.bootstrap.accordion","ui.bootstrap.alert","ui.bootstrap.bindHtml","ui.bootstrap.buttons","ui.bootstrap.carousel","ui.bootstrap.dateparser","ui.bootstrap.position","ui.bootstrap.datepicker","ui.bootstrap.dropdown","ui.bootstrap.modal","ui.bootstrap.pagination","ui.bootstrap.tooltip","ui.bootstrap.popover","ui.bootstrap.progressbar","ui.bootstrap.rating","ui.bootstrap.tabs","ui.bootstrap.timepicker","ui.bootstrap.typeahead"]);
       
 34484 angular.module("ui.bootstrap.tpls", ["template/accordion/accordion-group.html","template/accordion/accordion.html","template/alert/alert.html","template/carousel/carousel.html","template/carousel/slide.html","template/datepicker/datepicker.html","template/datepicker/day.html","template/datepicker/month.html","template/datepicker/popup.html","template/datepicker/year.html","template/modal/backdrop.html","template/modal/window.html","template/pagination/pager.html","template/pagination/pagination.html","template/tooltip/tooltip-html-unsafe-popup.html","template/tooltip/tooltip-popup.html","template/popover/popover.html","template/progressbar/bar.html","template/progressbar/progress.html","template/progressbar/progressbar.html","template/rating/rating.html","template/tabs/tab.html","template/tabs/tabset.html","template/timepicker/timepicker.html","template/typeahead/typeahead-match.html","template/typeahead/typeahead-popup.html"]);
       
 34485 angular.module('ui.bootstrap.transition', [])
       
 34486 
       
 34487 /**
       
 34488  * $transition service provides a consistent interface to trigger CSS 3 transitions and to be informed when they complete.
       
 34489  * @param  {DOMElement} element  The DOMElement that will be animated.
       
 34490  * @param  {string|object|function} trigger  The thing that will cause the transition to start:
       
 34491  *   - As a string, it represents the css class to be added to the element.
       
 34492  *   - As an object, it represents a hash of style attributes to be applied to the element.
       
 34493  *   - As a function, it represents a function to be called that will cause the transition to occur.
       
 34494  * @return {Promise}  A promise that is resolved when the transition finishes.
       
 34495  */
       
 34496 .factory('$transition', ['$q', '$timeout', '$rootScope', function($q, $timeout, $rootScope) {
       
 34497 
       
 34498   var $transition = function(element, trigger, options) {
       
 34499     options = options || {};
       
 34500     var deferred = $q.defer();
       
 34501     var endEventName = $transition[options.animation ? 'animationEndEventName' : 'transitionEndEventName'];
       
 34502 
       
 34503     var transitionEndHandler = function(event) {
       
 34504       $rootScope.$apply(function() {
       
 34505         element.unbind(endEventName, transitionEndHandler);
       
 34506         deferred.resolve(element);
       
 34507       });
       
 34508     };
       
 34509 
       
 34510     if (endEventName) {
       
 34511       element.bind(endEventName, transitionEndHandler);
       
 34512     }
       
 34513 
       
 34514     // Wrap in a timeout to allow the browser time to update the DOM before the transition is to occur
       
 34515     $timeout(function() {
       
 34516       if ( angular.isString(trigger) ) {
       
 34517         element.addClass(trigger);
       
 34518       } else if ( angular.isFunction(trigger) ) {
       
 34519         trigger(element);
       
 34520       } else if ( angular.isObject(trigger) ) {
       
 34521         element.css(trigger);
       
 34522       }
       
 34523       //If browser does not support transitions, instantly resolve
       
 34524       if ( !endEventName ) {
       
 34525         deferred.resolve(element);
       
 34526       }
       
 34527     });
       
 34528 
       
 34529     // Add our custom cancel function to the promise that is returned
       
 34530     // We can call this if we are about to run a new transition, which we know will prevent this transition from ending,
       
 34531     // i.e. it will therefore never raise a transitionEnd event for that transition
       
 34532     deferred.promise.cancel = function() {
       
 34533       if ( endEventName ) {
       
 34534         element.unbind(endEventName, transitionEndHandler);
       
 34535       }
       
 34536       deferred.reject('Transition cancelled');
       
 34537     };
       
 34538 
       
 34539     return deferred.promise;
       
 34540   };
       
 34541 
       
 34542   // Work out the name of the transitionEnd event
       
 34543   var transElement = document.createElement('trans');
       
 34544   var transitionEndEventNames = {
       
 34545     'WebkitTransition': 'webkitTransitionEnd',
       
 34546     'MozTransition': 'transitionend',
       
 34547     'OTransition': 'oTransitionEnd',
       
 34548     'transition': 'transitionend'
       
 34549   };
       
 34550   var animationEndEventNames = {
       
 34551     'WebkitTransition': 'webkitAnimationEnd',
       
 34552     'MozTransition': 'animationend',
       
 34553     'OTransition': 'oAnimationEnd',
       
 34554     'transition': 'animationend'
       
 34555   };
       
 34556   function findEndEventName(endEventNames) {
       
 34557     for (var name in endEventNames){
       
 34558       if (transElement.style[name] !== undefined) {
       
 34559         return endEventNames[name];
       
 34560       }
       
 34561     }
       
 34562   }
       
 34563   $transition.transitionEndEventName = findEndEventName(transitionEndEventNames);
       
 34564   $transition.animationEndEventName = findEndEventName(animationEndEventNames);
       
 34565   return $transition;
       
 34566 }]);
       
 34567 
       
 34568 angular.module('ui.bootstrap.collapse', ['ui.bootstrap.transition'])
       
 34569 
       
 34570   .directive('collapse', ['$transition', function ($transition) {
       
 34571 
       
 34572     return {
       
 34573       link: function (scope, element, attrs) {
       
 34574 
       
 34575         var initialAnimSkip = true;
       
 34576         var currentTransition;
       
 34577 
       
 34578         function doTransition(change) {
       
 34579           var newTransition = $transition(element, change);
       
 34580           if (currentTransition) {
       
 34581             currentTransition.cancel();
       
 34582           }
       
 34583           currentTransition = newTransition;
       
 34584           newTransition.then(newTransitionDone, newTransitionDone);
       
 34585           return newTransition;
       
 34586 
       
 34587           function newTransitionDone() {
       
 34588             // Make sure it's this transition, otherwise, leave it alone.
       
 34589             if (currentTransition === newTransition) {
       
 34590               currentTransition = undefined;
       
 34591             }
       
 34592           }
       
 34593         }
       
 34594 
       
 34595         function expand() {
       
 34596           if (initialAnimSkip) {
       
 34597             initialAnimSkip = false;
       
 34598             expandDone();
       
 34599           } else {
       
 34600             element.removeClass('collapse').addClass('collapsing');
       
 34601             doTransition({ height: element[0].scrollHeight + 'px' }).then(expandDone);
       
 34602           }
       
 34603         }
       
 34604 
       
 34605         function expandDone() {
       
 34606           element.removeClass('collapsing');
       
 34607           element.addClass('collapse in');
       
 34608           element.css({height: 'auto'});
       
 34609         }
       
 34610 
       
 34611         function collapse() {
       
 34612           if (initialAnimSkip) {
       
 34613             initialAnimSkip = false;
       
 34614             collapseDone();
       
 34615             element.css({height: 0});
       
 34616           } else {
       
 34617             // CSS transitions don't work with height: auto, so we have to manually change the height to a specific value
       
 34618             element.css({ height: element[0].scrollHeight + 'px' });
       
 34619             //trigger reflow so a browser realizes that height was updated from auto to a specific value
       
 34620             var x = element[0].offsetWidth;
       
 34621 
       
 34622             element.removeClass('collapse in').addClass('collapsing');
       
 34623 
       
 34624             doTransition({ height: 0 }).then(collapseDone);
       
 34625           }
       
 34626         }
       
 34627 
       
 34628         function collapseDone() {
       
 34629           element.removeClass('collapsing');
       
 34630           element.addClass('collapse');
       
 34631         }
       
 34632 
       
 34633         scope.$watch(attrs.collapse, function (shouldCollapse) {
       
 34634           if (shouldCollapse) {
       
 34635             collapse();
       
 34636           } else {
       
 34637             expand();
       
 34638           }
       
 34639         });
       
 34640       }
       
 34641     };
       
 34642   }]);
       
 34643 
       
 34644 angular.module('ui.bootstrap.accordion', ['ui.bootstrap.collapse'])
       
 34645 
       
 34646 .constant('accordionConfig', {
       
 34647   closeOthers: true
       
 34648 })
       
 34649 
       
 34650 .controller('AccordionController', ['$scope', '$attrs', 'accordionConfig', function ($scope, $attrs, accordionConfig) {
       
 34651 
       
 34652   // This array keeps track of the accordion groups
       
 34653   this.groups = [];
       
 34654 
       
 34655   // Ensure that all the groups in this accordion are closed, unless close-others explicitly says not to
       
 34656   this.closeOthers = function(openGroup) {
       
 34657     var closeOthers = angular.isDefined($attrs.closeOthers) ? $scope.$eval($attrs.closeOthers) : accordionConfig.closeOthers;
       
 34658     if ( closeOthers ) {
       
 34659       angular.forEach(this.groups, function (group) {
       
 34660         if ( group !== openGroup ) {
       
 34661           group.isOpen = false;
       
 34662         }
       
 34663       });
       
 34664     }
       
 34665   };
       
 34666 
       
 34667   // This is called from the accordion-group directive to add itself to the accordion
       
 34668   this.addGroup = function(groupScope) {
       
 34669     var that = this;
       
 34670     this.groups.push(groupScope);
       
 34671 
       
 34672     groupScope.$on('$destroy', function (event) {
       
 34673       that.removeGroup(groupScope);
       
 34674     });
       
 34675   };
       
 34676 
       
 34677   // This is called from the accordion-group directive when to remove itself
       
 34678   this.removeGroup = function(group) {
       
 34679     var index = this.groups.indexOf(group);
       
 34680     if ( index !== -1 ) {
       
 34681       this.groups.splice(index, 1);
       
 34682     }
       
 34683   };
       
 34684 
       
 34685 }])
       
 34686 
       
 34687 // The accordion directive simply sets up the directive controller
       
 34688 // and adds an accordion CSS class to itself element.
       
 34689 .directive('accordion', function () {
       
 34690   return {
       
 34691     restrict:'EA',
       
 34692     controller:'AccordionController',
       
 34693     transclude: true,
       
 34694     replace: false,
       
 34695     templateUrl: 'template/accordion/accordion.html'
       
 34696   };
       
 34697 })
       
 34698 
       
 34699 // The accordion-group directive indicates a block of html that will expand and collapse in an accordion
       
 34700 .directive('accordionGroup', function() {
       
 34701   return {
       
 34702     require:'^accordion',         // We need this directive to be inside an accordion
       
 34703     restrict:'EA',
       
 34704     transclude:true,              // It transcludes the contents of the directive into the template
       
 34705     replace: true,                // The element containing the directive will be replaced with the template
       
 34706     templateUrl:'template/accordion/accordion-group.html',
       
 34707     scope: {
       
 34708       heading: '@',               // Interpolate the heading attribute onto this scope
       
 34709       isOpen: '=?',
       
 34710       isDisabled: '=?'
       
 34711     },
       
 34712     controller: function() {
       
 34713       this.setHeading = function(element) {
       
 34714         this.heading = element;
       
 34715       };
       
 34716     },
       
 34717     link: function(scope, element, attrs, accordionCtrl) {
       
 34718       accordionCtrl.addGroup(scope);
       
 34719 
       
 34720       scope.$watch('isOpen', function(value) {
       
 34721         if ( value ) {
       
 34722           accordionCtrl.closeOthers(scope);
       
 34723         }
       
 34724       });
       
 34725 
       
 34726       scope.toggleOpen = function() {
       
 34727         if ( !scope.isDisabled ) {
       
 34728           scope.isOpen = !scope.isOpen;
       
 34729         }
       
 34730       };
       
 34731     }
       
 34732   };
       
 34733 })
       
 34734 
       
 34735 // Use accordion-heading below an accordion-group to provide a heading containing HTML
       
 34736 // <accordion-group>
       
 34737 //   <accordion-heading>Heading containing HTML - <img src="..."></accordion-heading>
       
 34738 // </accordion-group>
       
 34739 .directive('accordionHeading', function() {
       
 34740   return {
       
 34741     restrict: 'EA',
       
 34742     transclude: true,   // Grab the contents to be used as the heading
       
 34743     template: '',       // In effect remove this element!
       
 34744     replace: true,
       
 34745     require: '^accordionGroup',
       
 34746     link: function(scope, element, attr, accordionGroupCtrl, transclude) {
       
 34747       // Pass the heading to the accordion-group controller
       
 34748       // so that it can be transcluded into the right place in the template
       
 34749       // [The second parameter to transclude causes the elements to be cloned so that they work in ng-repeat]
       
 34750       accordionGroupCtrl.setHeading(transclude(scope, function() {}));
       
 34751     }
       
 34752   };
       
 34753 })
       
 34754 
       
 34755 // Use in the accordion-group template to indicate where you want the heading to be transcluded
       
 34756 // You must provide the property on the accordion-group controller that will hold the transcluded element
       
 34757 // <div class="accordion-group">
       
 34758 //   <div class="accordion-heading" ><a ... accordion-transclude="heading">...</a></div>
       
 34759 //   ...
       
 34760 // </div>
       
 34761 .directive('accordionTransclude', function() {
       
 34762   return {
       
 34763     require: '^accordionGroup',
       
 34764     link: function(scope, element, attr, controller) {
       
 34765       scope.$watch(function() { return controller[attr.accordionTransclude]; }, function(heading) {
       
 34766         if ( heading ) {
       
 34767           element.html('');
       
 34768           element.append(heading);
       
 34769         }
       
 34770       });
       
 34771     }
       
 34772   };
       
 34773 });
       
 34774 
       
 34775 angular.module('ui.bootstrap.alert', [])
       
 34776 
       
 34777 .controller('AlertController', ['$scope', '$attrs', function ($scope, $attrs) {
       
 34778   $scope.closeable = 'close' in $attrs;
       
 34779 }])
       
 34780 
       
 34781 .directive('alert', function () {
       
 34782   return {
       
 34783     restrict:'EA',
       
 34784     controller:'AlertController',
       
 34785     templateUrl:'template/alert/alert.html',
       
 34786     transclude:true,
       
 34787     replace:true,
       
 34788     scope: {
       
 34789       type: '@',
       
 34790       close: '&'
       
 34791     }
       
 34792   };
       
 34793 });
       
 34794 
       
 34795 angular.module('ui.bootstrap.bindHtml', [])
       
 34796 
       
 34797   .directive('bindHtmlUnsafe', function () {
       
 34798     return function (scope, element, attr) {
       
 34799       element.addClass('ng-binding').data('$binding', attr.bindHtmlUnsafe);
       
 34800       scope.$watch(attr.bindHtmlUnsafe, function bindHtmlUnsafeWatchAction(value) {
       
 34801         element.html(value || '');
       
 34802       });
       
 34803     };
       
 34804   });
       
 34805 angular.module('ui.bootstrap.buttons', [])
       
 34806 
       
 34807 .constant('buttonConfig', {
       
 34808   activeClass: 'active',
       
 34809   toggleEvent: 'click'
       
 34810 })
       
 34811 
       
 34812 .controller('ButtonsController', ['buttonConfig', function(buttonConfig) {
       
 34813   this.activeClass = buttonConfig.activeClass || 'active';
       
 34814   this.toggleEvent = buttonConfig.toggleEvent || 'click';
       
 34815 }])
       
 34816 
       
 34817 .directive('btnRadio', function () {
       
 34818   return {
       
 34819     require: ['btnRadio', 'ngModel'],
       
 34820     controller: 'ButtonsController',
       
 34821     link: function (scope, element, attrs, ctrls) {
       
 34822       var buttonsCtrl = ctrls[0], ngModelCtrl = ctrls[1];
       
 34823 
       
 34824       //model -> UI
       
 34825       ngModelCtrl.$render = function () {
       
 34826         element.toggleClass(buttonsCtrl.activeClass, angular.equals(ngModelCtrl.$modelValue, scope.$eval(attrs.btnRadio)));
       
 34827       };
       
 34828 
       
 34829       //ui->model
       
 34830       element.bind(buttonsCtrl.toggleEvent, function () {
       
 34831         var isActive = element.hasClass(buttonsCtrl.activeClass);
       
 34832 
       
 34833         if (!isActive || angular.isDefined(attrs.uncheckable)) {
       
 34834           scope.$apply(function () {
       
 34835             ngModelCtrl.$setViewValue(isActive ? null : scope.$eval(attrs.btnRadio));
       
 34836             ngModelCtrl.$render();
       
 34837           });
       
 34838         }
       
 34839       });
       
 34840     }
       
 34841   };
       
 34842 })
       
 34843 
       
 34844 .directive('btnCheckbox', function () {
       
 34845   return {
       
 34846     require: ['btnCheckbox', 'ngModel'],
       
 34847     controller: 'ButtonsController',
       
 34848     link: function (scope, element, attrs, ctrls) {
       
 34849       var buttonsCtrl = ctrls[0], ngModelCtrl = ctrls[1];
       
 34850 
       
 34851       function getTrueValue() {
       
 34852         return getCheckboxValue(attrs.btnCheckboxTrue, true);
       
 34853       }
       
 34854 
       
 34855       function getFalseValue() {
       
 34856         return getCheckboxValue(attrs.btnCheckboxFalse, false);
       
 34857       }
       
 34858 
       
 34859       function getCheckboxValue(attributeValue, defaultValue) {
       
 34860         var val = scope.$eval(attributeValue);
       
 34861         return angular.isDefined(val) ? val : defaultValue;
       
 34862       }
       
 34863 
       
 34864       //model -> UI
       
 34865       ngModelCtrl.$render = function () {
       
 34866         element.toggleClass(buttonsCtrl.activeClass, angular.equals(ngModelCtrl.$modelValue, getTrueValue()));
       
 34867       };
       
 34868 
       
 34869       //ui->model
       
 34870       element.bind(buttonsCtrl.toggleEvent, function () {
       
 34871         scope.$apply(function () {
       
 34872           ngModelCtrl.$setViewValue(element.hasClass(buttonsCtrl.activeClass) ? getFalseValue() : getTrueValue());
       
 34873           ngModelCtrl.$render();
       
 34874         });
       
 34875       });
       
 34876     }
       
 34877   };
       
 34878 });
       
 34879 
       
 34880 /**
       
 34881 * @ngdoc overview
       
 34882 * @name ui.bootstrap.carousel
       
 34883 *
       
 34884 * @description
       
 34885 * AngularJS version of an image carousel.
       
 34886 *
       
 34887 */
       
 34888 angular.module('ui.bootstrap.carousel', ['ui.bootstrap.transition'])
       
 34889 .controller('CarouselController', ['$scope', '$timeout', '$transition', function ($scope, $timeout, $transition) {
       
 34890   var self = this,
       
 34891     slides = self.slides = $scope.slides = [],
       
 34892     currentIndex = -1,
       
 34893     currentTimeout, isPlaying;
       
 34894   self.currentSlide = null;
       
 34895 
       
 34896   var destroyed = false;
       
 34897   /* direction: "prev" or "next" */
       
 34898   self.select = $scope.select = function(nextSlide, direction) {
       
 34899     var nextIndex = slides.indexOf(nextSlide);
       
 34900     //Decide direction if it's not given
       
 34901     if (direction === undefined) {
       
 34902       direction = nextIndex > currentIndex ? 'next' : 'prev';
       
 34903     }
       
 34904     if (nextSlide && nextSlide !== self.currentSlide) {
       
 34905       if ($scope.$currentTransition) {
       
 34906         $scope.$currentTransition.cancel();
       
 34907         //Timeout so ng-class in template has time to fix classes for finished slide
       
 34908         $timeout(goNext);
       
 34909       } else {
       
 34910         goNext();
       
 34911       }
       
 34912     }
       
 34913     function goNext() {
       
 34914       // Scope has been destroyed, stop here.
       
 34915       if (destroyed) { return; }
       
 34916       //If we have a slide to transition from and we have a transition type and we're allowed, go
       
 34917       if (self.currentSlide && angular.isString(direction) && !$scope.noTransition && nextSlide.$element) {
       
 34918         //We shouldn't do class manip in here, but it's the same weird thing bootstrap does. need to fix sometime
       
 34919         nextSlide.$element.addClass(direction);
       
 34920         var reflow = nextSlide.$element[0].offsetWidth; //force reflow
       
 34921 
       
 34922         //Set all other slides to stop doing their stuff for the new transition
       
 34923         angular.forEach(slides, function(slide) {
       
 34924           angular.extend(slide, {direction: '', entering: false, leaving: false, active: false});
       
 34925         });
       
 34926         angular.extend(nextSlide, {direction: direction, active: true, entering: true});
       
 34927         angular.extend(self.currentSlide||{}, {direction: direction, leaving: true});
       
 34928 
       
 34929         $scope.$currentTransition = $transition(nextSlide.$element, {});
       
 34930         //We have to create new pointers inside a closure since next & current will change
       
 34931         (function(next,current) {
       
 34932           $scope.$currentTransition.then(
       
 34933             function(){ transitionDone(next, current); },
       
 34934             function(){ transitionDone(next, current); }
       
 34935           );
       
 34936         }(nextSlide, self.currentSlide));
       
 34937       } else {
       
 34938         transitionDone(nextSlide, self.currentSlide);
       
 34939       }
       
 34940       self.currentSlide = nextSlide;
       
 34941       currentIndex = nextIndex;
       
 34942       //every time you change slides, reset the timer
       
 34943       restartTimer();
       
 34944     }
       
 34945     function transitionDone(next, current) {
       
 34946       angular.extend(next, {direction: '', active: true, leaving: false, entering: false});
       
 34947       angular.extend(current||{}, {direction: '', active: false, leaving: false, entering: false});
       
 34948       $scope.$currentTransition = null;
       
 34949     }
       
 34950   };
       
 34951   $scope.$on('$destroy', function () {
       
 34952     destroyed = true;
       
 34953   });
       
 34954 
       
 34955   /* Allow outside people to call indexOf on slides array */
       
 34956   self.indexOfSlide = function(slide) {
       
 34957     return slides.indexOf(slide);
       
 34958   };
       
 34959 
       
 34960   $scope.next = function() {
       
 34961     var newIndex = (currentIndex + 1) % slides.length;
       
 34962 
       
 34963     //Prevent this user-triggered transition from occurring if there is already one in progress
       
 34964     if (!$scope.$currentTransition) {
       
 34965       return self.select(slides[newIndex], 'next');
       
 34966     }
       
 34967   };
       
 34968 
       
 34969   $scope.prev = function() {
       
 34970     var newIndex = currentIndex - 1 < 0 ? slides.length - 1 : currentIndex - 1;
       
 34971 
       
 34972     //Prevent this user-triggered transition from occurring if there is already one in progress
       
 34973     if (!$scope.$currentTransition) {
       
 34974       return self.select(slides[newIndex], 'prev');
       
 34975     }
       
 34976   };
       
 34977 
       
 34978   $scope.isActive = function(slide) {
       
 34979      return self.currentSlide === slide;
       
 34980   };
       
 34981 
       
 34982   $scope.$watch('interval', restartTimer);
       
 34983   $scope.$on('$destroy', resetTimer);
       
 34984 
       
 34985   function restartTimer() {
       
 34986     resetTimer();
       
 34987     var interval = +$scope.interval;
       
 34988     if (!isNaN(interval) && interval>=0) {
       
 34989       currentTimeout = $timeout(timerFn, interval);
       
 34990     }
       
 34991   }
       
 34992 
       
 34993   function resetTimer() {
       
 34994     if (currentTimeout) {
       
 34995       $timeout.cancel(currentTimeout);
       
 34996       currentTimeout = null;
       
 34997     }
       
 34998   }
       
 34999 
       
 35000   function timerFn() {
       
 35001     if (isPlaying) {
       
 35002       $scope.next();
       
 35003       restartTimer();
       
 35004     } else {
       
 35005       $scope.pause();
       
 35006     }
       
 35007   }
       
 35008 
       
 35009   $scope.play = function() {
       
 35010     if (!isPlaying) {
       
 35011       isPlaying = true;
       
 35012       restartTimer();
       
 35013     }
       
 35014   };
       
 35015   $scope.pause = function() {
       
 35016     if (!$scope.noPause) {
       
 35017       isPlaying = false;
       
 35018       resetTimer();
       
 35019     }
       
 35020   };
       
 35021 
       
 35022   self.addSlide = function(slide, element) {
       
 35023     slide.$element = element;
       
 35024     slides.push(slide);
       
 35025     //if this is the first slide or the slide is set to active, select it
       
 35026     if(slides.length === 1 || slide.active) {
       
 35027       self.select(slides[slides.length-1]);
       
 35028       if (slides.length == 1) {
       
 35029         $scope.play();
       
 35030       }
       
 35031     } else {
       
 35032       slide.active = false;
       
 35033     }
       
 35034   };
       
 35035 
       
 35036   self.removeSlide = function(slide) {
       
 35037     //get the index of the slide inside the carousel
       
 35038     var index = slides.indexOf(slide);
       
 35039     slides.splice(index, 1);
       
 35040     if (slides.length > 0 && slide.active) {
       
 35041       if (index >= slides.length) {
       
 35042         self.select(slides[index-1]);
       
 35043       } else {
       
 35044         self.select(slides[index]);
       
 35045       }
       
 35046     } else if (currentIndex > index) {
       
 35047       currentIndex--;
       
 35048     }
       
 35049   };
       
 35050 
       
 35051 }])
       
 35052 
       
 35053 /**
       
 35054  * @ngdoc directive
       
 35055  * @name ui.bootstrap.carousel.directive:carousel
       
 35056  * @restrict EA
       
 35057  *
       
 35058  * @description
       
 35059  * Carousel is the outer container for a set of image 'slides' to showcase.
       
 35060  *
       
 35061  * @param {number=} interval The time, in milliseconds, that it will take the carousel to go to the next slide.
       
 35062  * @param {boolean=} noTransition Whether to disable transitions on the carousel.
       
 35063  * @param {boolean=} noPause Whether to disable pausing on the carousel (by default, the carousel interval pauses on hover).
       
 35064  *
       
 35065  * @example
       
 35066 <example module="ui.bootstrap">
       
 35067   <file name="index.html">
       
 35068     <carousel>
       
 35069       <slide>
       
 35070         <img src="http://placekitten.com/150/150" style="margin:auto;">
       
 35071         <div class="carousel-caption">
       
 35072           <p>Beautiful!</p>
       
 35073         </div>
       
 35074       </slide>
       
 35075       <slide>
       
 35076         <img src="http://placekitten.com/100/150" style="margin:auto;">
       
 35077         <div class="carousel-caption">
       
 35078           <p>D'aww!</p>
       
 35079         </div>
       
 35080       </slide>
       
 35081     </carousel>
       
 35082   </file>
       
 35083   <file name="demo.css">
       
 35084     .carousel-indicators {
       
 35085       top: auto;
       
 35086       bottom: 15px;
       
 35087     }
       
 35088   </file>
       
 35089 </example>
       
 35090  */
       
 35091 .directive('carousel', [function() {
       
 35092   return {
       
 35093     restrict: 'EA',
       
 35094     transclude: true,
       
 35095     replace: true,
       
 35096     controller: 'CarouselController',
       
 35097     require: 'carousel',
       
 35098     templateUrl: 'template/carousel/carousel.html',
       
 35099     scope: {
       
 35100       interval: '=',
       
 35101       noTransition: '=',
       
 35102       noPause: '='
       
 35103     }
       
 35104   };
       
 35105 }])
       
 35106 
       
 35107 /**
       
 35108  * @ngdoc directive
       
 35109  * @name ui.bootstrap.carousel.directive:slide
       
 35110  * @restrict EA
       
 35111  *
       
 35112  * @description
       
 35113  * Creates a slide inside a {@link ui.bootstrap.carousel.directive:carousel carousel}.  Must be placed as a child of a carousel element.
       
 35114  *
       
 35115  * @param {boolean=} active Model binding, whether or not this slide is currently active.
       
 35116  *
       
 35117  * @example
       
 35118 <example module="ui.bootstrap">
       
 35119   <file name="index.html">
       
 35120 <div ng-controller="CarouselDemoCtrl">
       
 35121   <carousel>
       
 35122     <slide ng-repeat="slide in slides" active="slide.active">
       
 35123       <img ng-src="{{slide.image}}" style="margin:auto;">
       
 35124       <div class="carousel-caption">
       
 35125         <h4>Slide {{$index}}</h4>
       
 35126         <p>{{slide.text}}</p>
       
 35127       </div>
       
 35128     </slide>
       
 35129   </carousel>
       
 35130   Interval, in milliseconds: <input type="number" ng-model="myInterval">
       
 35131   <br />Enter a negative number to stop the interval.
       
 35132 </div>
       
 35133   </file>
       
 35134   <file name="script.js">
       
 35135 function CarouselDemoCtrl($scope) {
       
 35136   $scope.myInterval = 5000;
       
 35137 }
       
 35138   </file>
       
 35139   <file name="demo.css">
       
 35140     .carousel-indicators {
       
 35141       top: auto;
       
 35142       bottom: 15px;
       
 35143     }
       
 35144   </file>
       
 35145 </example>
       
 35146 */
       
 35147 
       
 35148 .directive('slide', function() {
       
 35149   return {
       
 35150     require: '^carousel',
       
 35151     restrict: 'EA',
       
 35152     transclude: true,
       
 35153     replace: true,
       
 35154     templateUrl: 'template/carousel/slide.html',
       
 35155     scope: {
       
 35156       active: '=?'
       
 35157     },
       
 35158     link: function (scope, element, attrs, carouselCtrl) {
       
 35159       carouselCtrl.addSlide(scope, element);
       
 35160       //when the scope is destroyed then remove the slide from the current slides array
       
 35161       scope.$on('$destroy', function() {
       
 35162         carouselCtrl.removeSlide(scope);
       
 35163       });
       
 35164 
       
 35165       scope.$watch('active', function(active) {
       
 35166         if (active) {
       
 35167           carouselCtrl.select(scope);
       
 35168         }
       
 35169       });
       
 35170     }
       
 35171   };
       
 35172 });
       
 35173 
       
 35174 angular.module('ui.bootstrap.dateparser', [])
       
 35175 
       
 35176 .service('dateParser', ['$locale', 'orderByFilter', function($locale, orderByFilter) {
       
 35177 
       
 35178   this.parsers = {};
       
 35179 
       
 35180   var formatCodeToRegex = {
       
 35181     'yyyy': {
       
 35182       regex: '\\d{4}',
       
 35183       apply: function(value) { this.year = +value; }
       
 35184     },
       
 35185     'yy': {
       
 35186       regex: '\\d{2}',
       
 35187       apply: function(value) { this.year = +value + 2000; }
       
 35188     },
       
 35189     'y': {
       
 35190       regex: '\\d{1,4}',
       
 35191       apply: function(value) { this.year = +value; }
       
 35192     },
       
 35193     'MMMM': {
       
 35194       regex: $locale.DATETIME_FORMATS.MONTH.join('|'),
       
 35195       apply: function(value) { this.month = $locale.DATETIME_FORMATS.MONTH.indexOf(value); }
       
 35196     },
       
 35197     'MMM': {
       
 35198       regex: $locale.DATETIME_FORMATS.SHORTMONTH.join('|'),
       
 35199       apply: function(value) { this.month = $locale.DATETIME_FORMATS.SHORTMONTH.indexOf(value); }
       
 35200     },
       
 35201     'MM': {
       
 35202       regex: '0[1-9]|1[0-2]',
       
 35203       apply: function(value) { this.month = value - 1; }
       
 35204     },
       
 35205     'M': {
       
 35206       regex: '[1-9]|1[0-2]',
       
 35207       apply: function(value) { this.month = value - 1; }
       
 35208     },
       
 35209     'dd': {
       
 35210       regex: '[0-2][0-9]{1}|3[0-1]{1}',
       
 35211       apply: function(value) { this.date = +value; }
       
 35212     },
       
 35213     'd': {
       
 35214       regex: '[1-2]?[0-9]{1}|3[0-1]{1}',
       
 35215       apply: function(value) { this.date = +value; }
       
 35216     },
       
 35217     'EEEE': {
       
 35218       regex: $locale.DATETIME_FORMATS.DAY.join('|')
       
 35219     },
       
 35220     'EEE': {
       
 35221       regex: $locale.DATETIME_FORMATS.SHORTDAY.join('|')
       
 35222     }
       
 35223   };
       
 35224 
       
 35225   function createParser(format) {
       
 35226     var map = [], regex = format.split('');
       
 35227 
       
 35228     angular.forEach(formatCodeToRegex, function(data, code) {
       
 35229       var index = format.indexOf(code);
       
 35230 
       
 35231       if (index > -1) {
       
 35232         format = format.split('');
       
 35233 
       
 35234         regex[index] = '(' + data.regex + ')';
       
 35235         format[index] = '$'; // Custom symbol to define consumed part of format
       
 35236         for (var i = index + 1, n = index + code.length; i < n; i++) {
       
 35237           regex[i] = '';
       
 35238           format[i] = '$';
       
 35239         }
       
 35240         format = format.join('');
       
 35241 
       
 35242         map.push({ index: index, apply: data.apply });
       
 35243       }
       
 35244     });
       
 35245 
       
 35246     return {
       
 35247       regex: new RegExp('^' + regex.join('') + '$'),
       
 35248       map: orderByFilter(map, 'index')
       
 35249     };
       
 35250   }
       
 35251 
       
 35252   this.parse = function(input, format) {
       
 35253     if ( !angular.isString(input) || !format ) {
       
 35254       return input;
       
 35255     }
       
 35256 
       
 35257     format = $locale.DATETIME_FORMATS[format] || format;
       
 35258 
       
 35259     if ( !this.parsers[format] ) {
       
 35260       this.parsers[format] = createParser(format);
       
 35261     }
       
 35262 
       
 35263     var parser = this.parsers[format],
       
 35264         regex = parser.regex,
       
 35265         map = parser.map,
       
 35266         results = input.match(regex);
       
 35267 
       
 35268     if ( results && results.length ) {
       
 35269       var fields = { year: 1900, month: 0, date: 1, hours: 0 }, dt;
       
 35270 
       
 35271       for( var i = 1, n = results.length; i < n; i++ ) {
       
 35272         var mapper = map[i-1];
       
 35273         if ( mapper.apply ) {
       
 35274           mapper.apply.call(fields, results[i]);
       
 35275         }
       
 35276       }
       
 35277 
       
 35278       if ( isValid(fields.year, fields.month, fields.date) ) {
       
 35279         dt = new Date( fields.year, fields.month, fields.date, fields.hours);
       
 35280       }
       
 35281 
       
 35282       return dt;
       
 35283     }
       
 35284   };
       
 35285 
       
 35286   // Check if date is valid for specific month (and year for February).
       
 35287   // Month: 0 = Jan, 1 = Feb, etc
       
 35288   function isValid(year, month, date) {
       
 35289     if ( month === 1 && date > 28) {
       
 35290         return date === 29 && ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0);
       
 35291     }
       
 35292 
       
 35293     if ( month === 3 || month === 5 || month === 8 || month === 10) {
       
 35294         return date < 31;
       
 35295     }
       
 35296 
       
 35297     return true;
       
 35298   }
       
 35299 }]);
       
 35300 
       
 35301 angular.module('ui.bootstrap.position', [])
       
 35302 
       
 35303 /**
       
 35304  * A set of utility methods that can be use to retrieve position of DOM elements.
       
 35305  * It is meant to be used where we need to absolute-position DOM elements in
       
 35306  * relation to other, existing elements (this is the case for tooltips, popovers,
       
 35307  * typeahead suggestions etc.).
       
 35308  */
       
 35309   .factory('$position', ['$document', '$window', function ($document, $window) {
       
 35310 
       
 35311     function getStyle(el, cssprop) {
       
 35312       if (el.currentStyle) { //IE
       
 35313         return el.currentStyle[cssprop];
       
 35314       } else if ($window.getComputedStyle) {
       
 35315         return $window.getComputedStyle(el)[cssprop];
       
 35316       }
       
 35317       // finally try and get inline style
       
 35318       return el.style[cssprop];
       
 35319     }
       
 35320 
       
 35321     /**
       
 35322      * Checks if a given element is statically positioned
       
 35323      * @param element - raw DOM element
       
 35324      */
       
 35325     function isStaticPositioned(element) {
       
 35326       return (getStyle(element, 'position') || 'static' ) === 'static';
       
 35327     }
       
 35328 
       
 35329     /**
       
 35330      * returns the closest, non-statically positioned parentOffset of a given element
       
 35331      * @param element
       
 35332      */
       
 35333     var parentOffsetEl = function (element) {
       
 35334       var docDomEl = $document[0];
       
 35335       var offsetParent = element.offsetParent || docDomEl;
       
 35336       while (offsetParent && offsetParent !== docDomEl && isStaticPositioned(offsetParent) ) {
       
 35337         offsetParent = offsetParent.offsetParent;
       
 35338       }
       
 35339       return offsetParent || docDomEl;
       
 35340     };
       
 35341 
       
 35342     return {
       
 35343       /**
       
 35344        * Provides read-only equivalent of jQuery's position function:
       
 35345        * http://api.jquery.com/position/
       
 35346        */
       
 35347       position: function (element) {
       
 35348         var elBCR = this.offset(element);
       
 35349         var offsetParentBCR = { top: 0, left: 0 };
       
 35350         var offsetParentEl = parentOffsetEl(element[0]);
       
 35351         if (offsetParentEl != $document[0]) {
       
 35352           offsetParentBCR = this.offset(angular.element(offsetParentEl));
       
 35353           offsetParentBCR.top += offsetParentEl.clientTop - offsetParentEl.scrollTop;
       
 35354           offsetParentBCR.left += offsetParentEl.clientLeft - offsetParentEl.scrollLeft;
       
 35355         }
       
 35356 
       
 35357         var boundingClientRect = element[0].getBoundingClientRect();
       
 35358         return {
       
 35359           width: boundingClientRect.width || element.prop('offsetWidth'),
       
 35360           height: boundingClientRect.height || element.prop('offsetHeight'),
       
 35361           top: elBCR.top - offsetParentBCR.top,
       
 35362           left: elBCR.left - offsetParentBCR.left
       
 35363         };
       
 35364       },
       
 35365 
       
 35366       /**
       
 35367        * Provides read-only equivalent of jQuery's offset function:
       
 35368        * http://api.jquery.com/offset/
       
 35369        */
       
 35370       offset: function (element) {
       
 35371         var boundingClientRect = element[0].getBoundingClientRect();
       
 35372         return {
       
 35373           width: boundingClientRect.width || element.prop('offsetWidth'),
       
 35374           height: boundingClientRect.height || element.prop('offsetHeight'),
       
 35375           top: boundingClientRect.top + ($window.pageYOffset || $document[0].documentElement.scrollTop),
       
 35376           left: boundingClientRect.left + ($window.pageXOffset || $document[0].documentElement.scrollLeft)
       
 35377         };
       
 35378       },
       
 35379 
       
 35380       /**
       
 35381        * Provides coordinates for the targetEl in relation to hostEl
       
 35382        */
       
 35383       positionElements: function (hostEl, targetEl, positionStr, appendToBody) {
       
 35384 
       
 35385         var positionStrParts = positionStr.split('-');
       
 35386         var pos0 = positionStrParts[0], pos1 = positionStrParts[1] || 'center';
       
 35387 
       
 35388         var hostElPos,
       
 35389           targetElWidth,
       
 35390           targetElHeight,
       
 35391           targetElPos;
       
 35392 
       
 35393         hostElPos = appendToBody ? this.offset(hostEl) : this.position(hostEl);
       
 35394 
       
 35395         targetElWidth = targetEl.prop('offsetWidth');
       
 35396         targetElHeight = targetEl.prop('offsetHeight');
       
 35397 
       
 35398         var shiftWidth = {
       
 35399           center: function () {
       
 35400             return hostElPos.left + hostElPos.width / 2 - targetElWidth / 2;
       
 35401           },
       
 35402           left: function () {
       
 35403             return hostElPos.left;
       
 35404           },
       
 35405           right: function () {
       
 35406             return hostElPos.left + hostElPos.width;
       
 35407           }
       
 35408         };
       
 35409 
       
 35410         var shiftHeight = {
       
 35411           center: function () {
       
 35412             return hostElPos.top + hostElPos.height / 2 - targetElHeight / 2;
       
 35413           },
       
 35414           top: function () {
       
 35415             return hostElPos.top;
       
 35416           },
       
 35417           bottom: function () {
       
 35418             return hostElPos.top + hostElPos.height;
       
 35419           }
       
 35420         };
       
 35421 
       
 35422         switch (pos0) {
       
 35423           case 'right':
       
 35424             targetElPos = {
       
 35425               top: shiftHeight[pos1](),
       
 35426               left: shiftWidth[pos0]()
       
 35427             };
       
 35428             break;
       
 35429           case 'left':
       
 35430             targetElPos = {
       
 35431               top: shiftHeight[pos1](),
       
 35432               left: hostElPos.left - targetElWidth
       
 35433             };
       
 35434             break;
       
 35435           case 'bottom':
       
 35436             targetElPos = {
       
 35437               top: shiftHeight[pos0](),
       
 35438               left: shiftWidth[pos1]()
       
 35439             };
       
 35440             break;
       
 35441           default:
       
 35442             targetElPos = {
       
 35443               top: hostElPos.top - targetElHeight,
       
 35444               left: shiftWidth[pos1]()
       
 35445             };
       
 35446             break;
       
 35447         }
       
 35448 
       
 35449         return targetElPos;
       
 35450       }
       
 35451     };
       
 35452   }]);
       
 35453 
       
 35454 angular.module('ui.bootstrap.datepicker', ['ui.bootstrap.dateparser', 'ui.bootstrap.position'])
       
 35455 
       
 35456 .constant('datepickerConfig', {
       
 35457   formatDay: 'dd',
       
 35458   formatMonth: 'MMMM',
       
 35459   formatYear: 'yyyy',
       
 35460   formatDayHeader: 'EEE',
       
 35461   formatDayTitle: 'MMMM yyyy',
       
 35462   formatMonthTitle: 'yyyy',
       
 35463   datepickerMode: 'day',
       
 35464   minMode: 'day',
       
 35465   maxMode: 'year',
       
 35466   showWeeks: true,
       
 35467   startingDay: 0,
       
 35468   yearRange: 20,
       
 35469   minDate: null,
       
 35470   maxDate: null
       
 35471 })
       
 35472 
       
 35473 .controller('DatepickerController', ['$scope', '$attrs', '$parse', '$interpolate', '$timeout', '$log', 'dateFilter', 'datepickerConfig', function($scope, $attrs, $parse, $interpolate, $timeout, $log, dateFilter, datepickerConfig) {
       
 35474   var self = this,
       
 35475       ngModelCtrl = { $setViewValue: angular.noop }; // nullModelCtrl;
       
 35476 
       
 35477   // Modes chain
       
 35478   this.modes = ['day', 'month', 'year'];
       
 35479 
       
 35480   // Configuration attributes
       
 35481   angular.forEach(['formatDay', 'formatMonth', 'formatYear', 'formatDayHeader', 'formatDayTitle', 'formatMonthTitle',
       
 35482                    'minMode', 'maxMode', 'showWeeks', 'startingDay', 'yearRange'], function( key, index ) {
       
 35483     self[key] = angular.isDefined($attrs[key]) ? (index < 8 ? $interpolate($attrs[key])($scope.$parent) : $scope.$parent.$eval($attrs[key])) : datepickerConfig[key];
       
 35484   });
       
 35485 
       
 35486   // Watchable date attributes
       
 35487   angular.forEach(['minDate', 'maxDate'], function( key ) {
       
 35488     if ( $attrs[key] ) {
       
 35489       $scope.$parent.$watch($parse($attrs[key]), function(value) {
       
 35490         self[key] = value ? new Date(value) : null;
       
 35491         self.refreshView();
       
 35492       });
       
 35493     } else {
       
 35494       self[key] = datepickerConfig[key] ? new Date(datepickerConfig[key]) : null;
       
 35495     }
       
 35496   });
       
 35497 
       
 35498   $scope.datepickerMode = $scope.datepickerMode || datepickerConfig.datepickerMode;
       
 35499   $scope.uniqueId = 'datepicker-' + $scope.$id + '-' + Math.floor(Math.random() * 10000);
       
 35500   this.activeDate = angular.isDefined($attrs.initDate) ? $scope.$parent.$eval($attrs.initDate) : new Date();
       
 35501 
       
 35502   $scope.isActive = function(dateObject) {
       
 35503     if (self.compare(dateObject.date, self.activeDate) === 0) {
       
 35504       $scope.activeDateId = dateObject.uid;
       
 35505       return true;
       
 35506     }
       
 35507     return false;
       
 35508   };
       
 35509 
       
 35510   this.init = function( ngModelCtrl_ ) {
       
 35511     ngModelCtrl = ngModelCtrl_;
       
 35512 
       
 35513     ngModelCtrl.$render = function() {
       
 35514       self.render();
       
 35515     };
       
 35516   };
       
 35517 
       
 35518   this.render = function() {
       
 35519     if ( ngModelCtrl.$modelValue ) {
       
 35520       var date = new Date( ngModelCtrl.$modelValue ),
       
 35521           isValid = !isNaN(date);
       
 35522 
       
 35523       if ( isValid ) {
       
 35524         this.activeDate = date;
       
 35525       } else {
       
 35526         $log.error('Datepicker directive: "ng-model" value must be a Date object, a number of milliseconds since 01.01.1970 or a string representing an RFC2822 or ISO 8601 date.');
       
 35527       }
       
 35528       ngModelCtrl.$setValidity('date', isValid);
       
 35529     }
       
 35530     this.refreshView();
       
 35531   };
       
 35532 
       
 35533   this.refreshView = function() {
       
 35534     if ( this.element ) {
       
 35535       this._refreshView();
       
 35536 
       
 35537       var date = ngModelCtrl.$modelValue ? new Date(ngModelCtrl.$modelValue) : null;
       
 35538       ngModelCtrl.$setValidity('date-disabled', !date || (this.element && !this.isDisabled(date)));
       
 35539     }
       
 35540   };
       
 35541 
       
 35542   this.createDateObject = function(date, format) {
       
 35543     var model = ngModelCtrl.$modelValue ? new Date(ngModelCtrl.$modelValue) : null;
       
 35544     return {
       
 35545       date: date,
       
 35546       label: dateFilter(date, format),
       
 35547       selected: model && this.compare(date, model) === 0,
       
 35548       disabled: this.isDisabled(date),
       
 35549       current: this.compare(date, new Date()) === 0
       
 35550     };
       
 35551   };
       
 35552 
       
 35553   this.isDisabled = function( date ) {
       
 35554     return ((this.minDate && this.compare(date, this.minDate) < 0) || (this.maxDate && this.compare(date, this.maxDate) > 0) || ($attrs.dateDisabled && $scope.dateDisabled({date: date, mode: $scope.datepickerMode})));
       
 35555   };
       
 35556 
       
 35557   // Split array into smaller arrays
       
 35558   this.split = function(arr, size) {
       
 35559     var arrays = [];
       
 35560     while (arr.length > 0) {
       
 35561       arrays.push(arr.splice(0, size));
       
 35562     }
       
 35563     return arrays;
       
 35564   };
       
 35565 
       
 35566   $scope.select = function( date ) {
       
 35567     if ( $scope.datepickerMode === self.minMode ) {
       
 35568       var dt = ngModelCtrl.$modelValue ? new Date( ngModelCtrl.$modelValue ) : new Date(0, 0, 0, 0, 0, 0, 0);
       
 35569       dt.setFullYear( date.getFullYear(), date.getMonth(), date.getDate() );
       
 35570       ngModelCtrl.$setViewValue( dt );
       
 35571       ngModelCtrl.$render();
       
 35572     } else {
       
 35573       self.activeDate = date;
       
 35574       $scope.datepickerMode = self.modes[ self.modes.indexOf( $scope.datepickerMode ) - 1 ];
       
 35575     }
       
 35576   };
       
 35577 
       
 35578   $scope.move = function( direction ) {
       
 35579     var year = self.activeDate.getFullYear() + direction * (self.step.years || 0),
       
 35580         month = self.activeDate.getMonth() + direction * (self.step.months || 0);
       
 35581     self.activeDate.setFullYear(year, month, 1);
       
 35582     self.refreshView();
       
 35583   };
       
 35584 
       
 35585   $scope.toggleMode = function( direction ) {
       
 35586     direction = direction || 1;
       
 35587 
       
 35588     if (($scope.datepickerMode === self.maxMode && direction === 1) || ($scope.datepickerMode === self.minMode && direction === -1)) {
       
 35589       return;
       
 35590     }
       
 35591 
       
 35592     $scope.datepickerMode = self.modes[ self.modes.indexOf( $scope.datepickerMode ) + direction ];
       
 35593   };
       
 35594 
       
 35595   // Key event mapper
       
 35596   $scope.keys = { 13:'enter', 32:'space', 33:'pageup', 34:'pagedown', 35:'end', 36:'home', 37:'left', 38:'up', 39:'right', 40:'down' };
       
 35597 
       
 35598   var focusElement = function() {
       
 35599     $timeout(function() {
       
 35600       self.element[0].focus();
       
 35601     }, 0 , false);
       
 35602   };
       
 35603 
       
 35604   // Listen for focus requests from popup directive
       
 35605   $scope.$on('datepicker.focus', focusElement);
       
 35606 
       
 35607   $scope.keydown = function( evt ) {
       
 35608     var key = $scope.keys[evt.which];
       
 35609 
       
 35610     if ( !key || evt.shiftKey || evt.altKey ) {
       
 35611       return;
       
 35612     }
       
 35613 
       
 35614     evt.preventDefault();
       
 35615     evt.stopPropagation();
       
 35616 
       
 35617     if (key === 'enter' || key === 'space') {
       
 35618       if ( self.isDisabled(self.activeDate)) {
       
 35619         return; // do nothing
       
 35620       }
       
 35621       $scope.select(self.activeDate);
       
 35622       focusElement();
       
 35623     } else if (evt.ctrlKey && (key === 'up' || key === 'down')) {
       
 35624       $scope.toggleMode(key === 'up' ? 1 : -1);
       
 35625       focusElement();
       
 35626     } else {
       
 35627       self.handleKeyDown(key, evt);
       
 35628       self.refreshView();
       
 35629     }
       
 35630   };
       
 35631 }])
       
 35632 
       
 35633 .directive( 'datepicker', function () {
       
 35634   return {
       
 35635     restrict: 'EA',
       
 35636     replace: true,
       
 35637     templateUrl: 'template/datepicker/datepicker.html',
       
 35638     scope: {
       
 35639       datepickerMode: '=?',
       
 35640       dateDisabled: '&'
       
 35641     },
       
 35642     require: ['datepicker', '?^ngModel'],
       
 35643     controller: 'DatepickerController',
       
 35644     link: function(scope, element, attrs, ctrls) {
       
 35645       var datepickerCtrl = ctrls[0], ngModelCtrl = ctrls[1];
       
 35646 
       
 35647       if ( ngModelCtrl ) {
       
 35648         datepickerCtrl.init( ngModelCtrl );
       
 35649       }
       
 35650     }
       
 35651   };
       
 35652 })
       
 35653 
       
 35654 .directive('daypicker', ['dateFilter', function (dateFilter) {
       
 35655   return {
       
 35656     restrict: 'EA',
       
 35657     replace: true,
       
 35658     templateUrl: 'template/datepicker/day.html',
       
 35659     require: '^datepicker',
       
 35660     link: function(scope, element, attrs, ctrl) {
       
 35661       scope.showWeeks = ctrl.showWeeks;
       
 35662 
       
 35663       ctrl.step = { months: 1 };
       
 35664       ctrl.element = element;
       
 35665 
       
 35666       var DAYS_IN_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
       
 35667       function getDaysInMonth( year, month ) {
       
 35668         return ((month === 1) && (year % 4 === 0) && ((year % 100 !== 0) || (year % 400 === 0))) ? 29 : DAYS_IN_MONTH[month];
       
 35669       }
       
 35670 
       
 35671       function getDates(startDate, n) {
       
 35672         var dates = new Array(n), current = new Date(startDate), i = 0;
       
 35673         current.setHours(12); // Prevent repeated dates because of timezone bug
       
 35674         while ( i < n ) {
       
 35675           dates[i++] = new Date(current);
       
 35676           current.setDate( current.getDate() + 1 );
       
 35677         }
       
 35678         return dates;
       
 35679       }
       
 35680 
       
 35681       ctrl._refreshView = function() {
       
 35682         var year = ctrl.activeDate.getFullYear(),
       
 35683           month = ctrl.activeDate.getMonth(),
       
 35684           firstDayOfMonth = new Date(year, month, 1),
       
 35685           difference = ctrl.startingDay - firstDayOfMonth.getDay(),
       
 35686           numDisplayedFromPreviousMonth = (difference > 0) ? 7 - difference : - difference,
       
 35687           firstDate = new Date(firstDayOfMonth);
       
 35688 
       
 35689         if ( numDisplayedFromPreviousMonth > 0 ) {
       
 35690           firstDate.setDate( - numDisplayedFromPreviousMonth + 1 );
       
 35691         }
       
 35692 
       
 35693         // 42 is the number of days on a six-month calendar
       
 35694         var days = getDates(firstDate, 42);
       
 35695         for (var i = 0; i < 42; i ++) {
       
 35696           days[i] = angular.extend(ctrl.createDateObject(days[i], ctrl.formatDay), {
       
 35697             secondary: days[i].getMonth() !== month,
       
 35698             uid: scope.uniqueId + '-' + i
       
 35699           });
       
 35700         }
       
 35701 
       
 35702         scope.labels = new Array(7);
       
 35703         for (var j = 0; j < 7; j++) {
       
 35704           scope.labels[j] = {
       
 35705             abbr: dateFilter(days[j].date, ctrl.formatDayHeader),
       
 35706             full: dateFilter(days[j].date, 'EEEE')
       
 35707           };
       
 35708         }
       
 35709 
       
 35710         scope.title = dateFilter(ctrl.activeDate, ctrl.formatDayTitle);
       
 35711         scope.rows = ctrl.split(days, 7);
       
 35712 
       
 35713         if ( scope.showWeeks ) {
       
 35714           scope.weekNumbers = [];
       
 35715           var weekNumber = getISO8601WeekNumber( scope.rows[0][0].date ),
       
 35716               numWeeks = scope.rows.length;
       
 35717           while( scope.weekNumbers.push(weekNumber++) < numWeeks ) {}
       
 35718         }
       
 35719       };
       
 35720 
       
 35721       ctrl.compare = function(date1, date2) {
       
 35722         return (new Date( date1.getFullYear(), date1.getMonth(), date1.getDate() ) - new Date( date2.getFullYear(), date2.getMonth(), date2.getDate() ) );
       
 35723       };
       
 35724 
       
 35725       function getISO8601WeekNumber(date) {
       
 35726         var checkDate = new Date(date);
       
 35727         checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7)); // Thursday
       
 35728         var time = checkDate.getTime();
       
 35729         checkDate.setMonth(0); // Compare with Jan 1
       
 35730         checkDate.setDate(1);
       
 35731         return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
       
 35732       }
       
 35733 
       
 35734       ctrl.handleKeyDown = function( key, evt ) {
       
 35735         var date = ctrl.activeDate.getDate();
       
 35736 
       
 35737         if (key === 'left') {
       
 35738           date = date - 1;   // up
       
 35739         } else if (key === 'up') {
       
 35740           date = date - 7;   // down
       
 35741         } else if (key === 'right') {
       
 35742           date = date + 1;   // down
       
 35743         } else if (key === 'down') {
       
 35744           date = date + 7;
       
 35745         } else if (key === 'pageup' || key === 'pagedown') {
       
 35746           var month = ctrl.activeDate.getMonth() + (key === 'pageup' ? - 1 : 1);
       
 35747           ctrl.activeDate.setMonth(month, 1);
       
 35748           date = Math.min(getDaysInMonth(ctrl.activeDate.getFullYear(), ctrl.activeDate.getMonth()), date);
       
 35749         } else if (key === 'home') {
       
 35750           date = 1;
       
 35751         } else if (key === 'end') {
       
 35752           date = getDaysInMonth(ctrl.activeDate.getFullYear(), ctrl.activeDate.getMonth());
       
 35753         }
       
 35754         ctrl.activeDate.setDate(date);
       
 35755       };
       
 35756 
       
 35757       ctrl.refreshView();
       
 35758     }
       
 35759   };
       
 35760 }])
       
 35761 
       
 35762 .directive('monthpicker', ['dateFilter', function (dateFilter) {
       
 35763   return {
       
 35764     restrict: 'EA',
       
 35765     replace: true,
       
 35766     templateUrl: 'template/datepicker/month.html',
       
 35767     require: '^datepicker',
       
 35768     link: function(scope, element, attrs, ctrl) {
       
 35769       ctrl.step = { years: 1 };
       
 35770       ctrl.element = element;
       
 35771 
       
 35772       ctrl._refreshView = function() {
       
 35773         var months = new Array(12),
       
 35774             year = ctrl.activeDate.getFullYear();
       
 35775 
       
 35776         for ( var i = 0; i < 12; i++ ) {
       
 35777           months[i] = angular.extend(ctrl.createDateObject(new Date(year, i, 1), ctrl.formatMonth), {
       
 35778             uid: scope.uniqueId + '-' + i
       
 35779           });
       
 35780         }
       
 35781 
       
 35782         scope.title = dateFilter(ctrl.activeDate, ctrl.formatMonthTitle);
       
 35783         scope.rows = ctrl.split(months, 3);
       
 35784       };
       
 35785 
       
 35786       ctrl.compare = function(date1, date2) {
       
 35787         return new Date( date1.getFullYear(), date1.getMonth() ) - new Date( date2.getFullYear(), date2.getMonth() );
       
 35788       };
       
 35789 
       
 35790       ctrl.handleKeyDown = function( key, evt ) {
       
 35791         var date = ctrl.activeDate.getMonth();
       
 35792 
       
 35793         if (key === 'left') {
       
 35794           date = date - 1;   // up
       
 35795         } else if (key === 'up') {
       
 35796           date = date - 3;   // down
       
 35797         } else if (key === 'right') {
       
 35798           date = date + 1;   // down
       
 35799         } else if (key === 'down') {
       
 35800           date = date + 3;
       
 35801         } else if (key === 'pageup' || key === 'pagedown') {
       
 35802           var year = ctrl.activeDate.getFullYear() + (key === 'pageup' ? - 1 : 1);
       
 35803           ctrl.activeDate.setFullYear(year);
       
 35804         } else if (key === 'home') {
       
 35805           date = 0;
       
 35806         } else if (key === 'end') {
       
 35807           date = 11;
       
 35808         }
       
 35809         ctrl.activeDate.setMonth(date);
       
 35810       };
       
 35811 
       
 35812       ctrl.refreshView();
       
 35813     }
       
 35814   };
       
 35815 }])
       
 35816 
       
 35817 .directive('yearpicker', ['dateFilter', function (dateFilter) {
       
 35818   return {
       
 35819     restrict: 'EA',
       
 35820     replace: true,
       
 35821     templateUrl: 'template/datepicker/year.html',
       
 35822     require: '^datepicker',
       
 35823     link: function(scope, element, attrs, ctrl) {
       
 35824       var range = ctrl.yearRange;
       
 35825 
       
 35826       ctrl.step = { years: range };
       
 35827       ctrl.element = element;
       
 35828 
       
 35829       function getStartingYear( year ) {
       
 35830         return parseInt((year - 1) / range, 10) * range + 1;
       
 35831       }
       
 35832 
       
 35833       ctrl._refreshView = function() {
       
 35834         var years = new Array(range);
       
 35835 
       
 35836         for ( var i = 0, start = getStartingYear(ctrl.activeDate.getFullYear()); i < range; i++ ) {
       
 35837           years[i] = angular.extend(ctrl.createDateObject(new Date(start + i, 0, 1), ctrl.formatYear), {
       
 35838             uid: scope.uniqueId + '-' + i
       
 35839           });
       
 35840         }
       
 35841 
       
 35842         scope.title = [years[0].label, years[range - 1].label].join(' - ');
       
 35843         scope.rows = ctrl.split(years, 5);
       
 35844       };
       
 35845 
       
 35846       ctrl.compare = function(date1, date2) {
       
 35847         return date1.getFullYear() - date2.getFullYear();
       
 35848       };
       
 35849 
       
 35850       ctrl.handleKeyDown = function( key, evt ) {
       
 35851         var date = ctrl.activeDate.getFullYear();
       
 35852 
       
 35853         if (key === 'left') {
       
 35854           date = date - 1;   // up
       
 35855         } else if (key === 'up') {
       
 35856           date = date - 5;   // down
       
 35857         } else if (key === 'right') {
       
 35858           date = date + 1;   // down
       
 35859         } else if (key === 'down') {
       
 35860           date = date + 5;
       
 35861         } else if (key === 'pageup' || key === 'pagedown') {
       
 35862           date += (key === 'pageup' ? - 1 : 1) * ctrl.step.years;
       
 35863         } else if (key === 'home') {
       
 35864           date = getStartingYear( ctrl.activeDate.getFullYear() );
       
 35865         } else if (key === 'end') {
       
 35866           date = getStartingYear( ctrl.activeDate.getFullYear() ) + range - 1;
       
 35867         }
       
 35868         ctrl.activeDate.setFullYear(date);
       
 35869       };
       
 35870 
       
 35871       ctrl.refreshView();
       
 35872     }
       
 35873   };
       
 35874 }])
       
 35875 
       
 35876 .constant('datepickerPopupConfig', {
       
 35877   datepickerPopup: 'yyyy-MM-dd',
       
 35878   currentText: 'Today',
       
 35879   clearText: 'Clear',
       
 35880   closeText: 'Done',
       
 35881   closeOnDateSelection: true,
       
 35882   appendToBody: false,
       
 35883   showButtonBar: true
       
 35884 })
       
 35885 
       
 35886 .directive('datepickerPopup', ['$compile', '$parse', '$document', '$position', 'dateFilter', 'dateParser', 'datepickerPopupConfig',
       
 35887 function ($compile, $parse, $document, $position, dateFilter, dateParser, datepickerPopupConfig) {
       
 35888   return {
       
 35889     restrict: 'EA',
       
 35890     require: 'ngModel',
       
 35891     scope: {
       
 35892       isOpen: '=?',
       
 35893       currentText: '@',
       
 35894       clearText: '@',
       
 35895       closeText: '@',
       
 35896       dateDisabled: '&'
       
 35897     },
       
 35898     link: function(scope, element, attrs, ngModel) {
       
 35899       var dateFormat,
       
 35900           closeOnDateSelection = angular.isDefined(attrs.closeOnDateSelection) ? scope.$parent.$eval(attrs.closeOnDateSelection) : datepickerPopupConfig.closeOnDateSelection,
       
 35901           appendToBody = angular.isDefined(attrs.datepickerAppendToBody) ? scope.$parent.$eval(attrs.datepickerAppendToBody) : datepickerPopupConfig.appendToBody;
       
 35902 
       
 35903       scope.showButtonBar = angular.isDefined(attrs.showButtonBar) ? scope.$parent.$eval(attrs.showButtonBar) : datepickerPopupConfig.showButtonBar;
       
 35904 
       
 35905       scope.getText = function( key ) {
       
 35906         return scope[key + 'Text'] || datepickerPopupConfig[key + 'Text'];
       
 35907       };
       
 35908 
       
 35909       attrs.$observe('datepickerPopup', function(value) {
       
 35910           dateFormat = value || datepickerPopupConfig.datepickerPopup;
       
 35911           ngModel.$render();
       
 35912       });
       
 35913 
       
 35914       // popup element used to display calendar
       
 35915       var popupEl = angular.element('<div datepicker-popup-wrap><div datepicker></div></div>');
       
 35916       popupEl.attr({
       
 35917         'ng-model': 'date',
       
 35918         'ng-change': 'dateSelection()'
       
 35919       });
       
 35920 
       
 35921       function cameltoDash( string ){
       
 35922         return string.replace(/([A-Z])/g, function($1) { return '-' + $1.toLowerCase(); });
       
 35923       }
       
 35924 
       
 35925       // datepicker element
       
 35926       var datepickerEl = angular.element(popupEl.children()[0]);
       
 35927       if ( attrs.datepickerOptions ) {
       
 35928         angular.forEach(scope.$parent.$eval(attrs.datepickerOptions), function( value, option ) {
       
 35929           datepickerEl.attr( cameltoDash(option), value );
       
 35930         });
       
 35931       }
       
 35932 
       
 35933       scope.watchData = {};
       
 35934       angular.forEach(['minDate', 'maxDate', 'datepickerMode'], function( key ) {
       
 35935         if ( attrs[key] ) {
       
 35936           var getAttribute = $parse(attrs[key]);
       
 35937           scope.$parent.$watch(getAttribute, function(value){
       
 35938             scope.watchData[key] = value;
       
 35939           });
       
 35940           datepickerEl.attr(cameltoDash(key), 'watchData.' + key);
       
 35941 
       
 35942           // Propagate changes from datepicker to outside
       
 35943           if ( key === 'datepickerMode' ) {
       
 35944             var setAttribute = getAttribute.assign;
       
 35945             scope.$watch('watchData.' + key, function(value, oldvalue) {
       
 35946               if ( value !== oldvalue ) {
       
 35947                 setAttribute(scope.$parent, value);
       
 35948               }
       
 35949             });
       
 35950           }
       
 35951         }
       
 35952       });
       
 35953       if (attrs.dateDisabled) {
       
 35954         datepickerEl.attr('date-disabled', 'dateDisabled({ date: date, mode: mode })');
       
 35955       }
       
 35956 
       
 35957       function parseDate(viewValue) {
       
 35958         if (!viewValue) {
       
 35959           ngModel.$setValidity('date', true);
       
 35960           return null;
       
 35961         } else if (angular.isDate(viewValue) && !isNaN(viewValue)) {
       
 35962           ngModel.$setValidity('date', true);
       
 35963           return viewValue;
       
 35964         } else if (angular.isString(viewValue)) {
       
 35965           var date = dateParser.parse(viewValue, dateFormat) || new Date(viewValue);
       
 35966           if (isNaN(date)) {
       
 35967             ngModel.$setValidity('date', false);
       
 35968             return undefined;
       
 35969           } else {
       
 35970             ngModel.$setValidity('date', true);
       
 35971             return date;
       
 35972           }
       
 35973         } else {
       
 35974           ngModel.$setValidity('date', false);
       
 35975           return undefined;
       
 35976         }
       
 35977       }
       
 35978       ngModel.$parsers.unshift(parseDate);
       
 35979 
       
 35980       // Inner change
       
 35981       scope.dateSelection = function(dt) {
       
 35982         if (angular.isDefined(dt)) {
       
 35983           scope.date = dt;
       
 35984         }
       
 35985         ngModel.$setViewValue(scope.date);
       
 35986         ngModel.$render();
       
 35987 
       
 35988         if ( closeOnDateSelection ) {
       
 35989           scope.isOpen = false;
       
 35990           element[0].focus();
       
 35991         }
       
 35992       };
       
 35993 
       
 35994       element.bind('input change keyup', function() {
       
 35995         scope.$apply(function() {
       
 35996           scope.date = ngModel.$modelValue;
       
 35997         });
       
 35998       });
       
 35999 
       
 36000       // Outter change
       
 36001       ngModel.$render = function() {
       
 36002         var date = ngModel.$viewValue ? dateFilter(ngModel.$viewValue, dateFormat) : '';
       
 36003         element.val(date);
       
 36004         scope.date = parseDate( ngModel.$modelValue );
       
 36005       };
       
 36006 
       
 36007       var documentClickBind = function(event) {
       
 36008         if (scope.isOpen && event.target !== element[0]) {
       
 36009           scope.$apply(function() {
       
 36010             scope.isOpen = false;
       
 36011           });
       
 36012         }
       
 36013       };
       
 36014 
       
 36015       var keydown = function(evt, noApply) {
       
 36016         scope.keydown(evt);
       
 36017       };
       
 36018       element.bind('keydown', keydown);
       
 36019 
       
 36020       scope.keydown = function(evt) {
       
 36021         if (evt.which === 27) {
       
 36022           evt.preventDefault();
       
 36023           evt.stopPropagation();
       
 36024           scope.close();
       
 36025         } else if (evt.which === 40 && !scope.isOpen) {
       
 36026           scope.isOpen = true;
       
 36027         }
       
 36028       };
       
 36029 
       
 36030       scope.$watch('isOpen', function(value) {
       
 36031         if (value) {
       
 36032           scope.$broadcast('datepicker.focus');
       
 36033           scope.position = appendToBody ? $position.offset(element) : $position.position(element);
       
 36034           scope.position.top = scope.position.top + element.prop('offsetHeight');
       
 36035 
       
 36036           $document.bind('click', documentClickBind);
       
 36037         } else {
       
 36038           $document.unbind('click', documentClickBind);
       
 36039         }
       
 36040       });
       
 36041 
       
 36042       scope.select = function( date ) {
       
 36043         if (date === 'today') {
       
 36044           var today = new Date();
       
 36045           if (angular.isDate(ngModel.$modelValue)) {
       
 36046             date = new Date(ngModel.$modelValue);
       
 36047             date.setFullYear(today.getFullYear(), today.getMonth(), today.getDate());
       
 36048           } else {
       
 36049             date = new Date(today.setHours(0, 0, 0, 0));
       
 36050           }
       
 36051         }
       
 36052         scope.dateSelection( date );
       
 36053       };
       
 36054 
       
 36055       scope.close = function() {
       
 36056         scope.isOpen = false;
       
 36057         element[0].focus();
       
 36058       };
       
 36059 
       
 36060       var $popup = $compile(popupEl)(scope);
       
 36061       // Prevent jQuery cache memory leak (template is now redundant after linking)
       
 36062       popupEl.remove();
       
 36063 
       
 36064       if ( appendToBody ) {
       
 36065         $document.find('body').append($popup);
       
 36066       } else {
       
 36067         element.after($popup);
       
 36068       }
       
 36069 
       
 36070       scope.$on('$destroy', function() {
       
 36071         $popup.remove();
       
 36072         element.unbind('keydown', keydown);
       
 36073         $document.unbind('click', documentClickBind);
       
 36074       });
       
 36075     }
       
 36076   };
       
 36077 }])
       
 36078 
       
 36079 .directive('datepickerPopupWrap', function() {
       
 36080   return {
       
 36081     restrict:'EA',
       
 36082     replace: true,
       
 36083     transclude: true,
       
 36084     templateUrl: 'template/datepicker/popup.html',
       
 36085     link:function (scope, element, attrs) {
       
 36086       element.bind('click', function(event) {
       
 36087         event.preventDefault();
       
 36088         event.stopPropagation();
       
 36089       });
       
 36090     }
       
 36091   };
       
 36092 });
       
 36093 
       
 36094 angular.module('ui.bootstrap.dropdown', [])
       
 36095 
       
 36096 .constant('dropdownConfig', {
       
 36097   openClass: 'open'
       
 36098 })
       
 36099 
       
 36100 .service('dropdownService', ['$document', function($document) {
       
 36101   var openScope = null;
       
 36102 
       
 36103   this.open = function( dropdownScope ) {
       
 36104     if ( !openScope ) {
       
 36105       $document.bind('click', closeDropdown);
       
 36106       $document.bind('keydown', escapeKeyBind);
       
 36107     }
       
 36108 
       
 36109     if ( openScope && openScope !== dropdownScope ) {
       
 36110         openScope.isOpen = false;
       
 36111     }
       
 36112 
       
 36113     openScope = dropdownScope;
       
 36114   };
       
 36115 
       
 36116   this.close = function( dropdownScope ) {
       
 36117     if ( openScope === dropdownScope ) {
       
 36118       openScope = null;
       
 36119       $document.unbind('click', closeDropdown);
       
 36120       $document.unbind('keydown', escapeKeyBind);
       
 36121     }
       
 36122   };
       
 36123 
       
 36124   var closeDropdown = function( evt ) {
       
 36125     var toggleElement = openScope.getToggleElement();
       
 36126     if ( evt && toggleElement && toggleElement[0].contains(evt.target) ) {
       
 36127         return;
       
 36128     }
       
 36129 
       
 36130     openScope.$apply(function() {
       
 36131       openScope.isOpen = false;
       
 36132     });
       
 36133   };
       
 36134 
       
 36135   var escapeKeyBind = function( evt ) {
       
 36136     if ( evt.which === 27 ) {
       
 36137       openScope.focusToggleElement();
       
 36138       closeDropdown();
       
 36139     }
       
 36140   };
       
 36141 }])
       
 36142 
       
 36143 .controller('DropdownController', ['$scope', '$attrs', '$parse', 'dropdownConfig', 'dropdownService', '$animate', function($scope, $attrs, $parse, dropdownConfig, dropdownService, $animate) {
       
 36144   var self = this,
       
 36145       scope = $scope.$new(), // create a child scope so we are not polluting original one
       
 36146       openClass = dropdownConfig.openClass,
       
 36147       getIsOpen,
       
 36148       setIsOpen = angular.noop,
       
 36149       toggleInvoker = $attrs.onToggle ? $parse($attrs.onToggle) : angular.noop;
       
 36150 
       
 36151   this.init = function( element ) {
       
 36152     self.$element = element;
       
 36153 
       
 36154     if ( $attrs.isOpen ) {
       
 36155       getIsOpen = $parse($attrs.isOpen);
       
 36156       setIsOpen = getIsOpen.assign;
       
 36157 
       
 36158       $scope.$watch(getIsOpen, function(value) {
       
 36159         scope.isOpen = !!value;
       
 36160       });
       
 36161     }
       
 36162   };
       
 36163 
       
 36164   this.toggle = function( open ) {
       
 36165     return scope.isOpen = arguments.length ? !!open : !scope.isOpen;
       
 36166   };
       
 36167 
       
 36168   // Allow other directives to watch status
       
 36169   this.isOpen = function() {
       
 36170     return scope.isOpen;
       
 36171   };
       
 36172 
       
 36173   scope.getToggleElement = function() {
       
 36174     return self.toggleElement;
       
 36175   };
       
 36176 
       
 36177   scope.focusToggleElement = function() {
       
 36178     if ( self.toggleElement ) {
       
 36179       self.toggleElement[0].focus();
       
 36180     }
       
 36181   };
       
 36182 
       
 36183   scope.$watch('isOpen', function( isOpen, wasOpen ) {
       
 36184     $animate[isOpen ? 'addClass' : 'removeClass'](self.$element, openClass);
       
 36185 
       
 36186     if ( isOpen ) {
       
 36187       scope.focusToggleElement();
       
 36188       dropdownService.open( scope );
       
 36189     } else {
       
 36190       dropdownService.close( scope );
       
 36191     }
       
 36192 
       
 36193     setIsOpen($scope, isOpen);
       
 36194     if (angular.isDefined(isOpen) && isOpen !== wasOpen) {
       
 36195       toggleInvoker($scope, { open: !!isOpen });
       
 36196     }
       
 36197   });
       
 36198 
       
 36199   $scope.$on('$locationChangeSuccess', function() {
       
 36200     scope.isOpen = false;
       
 36201   });
       
 36202 
       
 36203   $scope.$on('$destroy', function() {
       
 36204     scope.$destroy();
       
 36205   });
       
 36206 }])
       
 36207 
       
 36208 .directive('dropdown', function() {
       
 36209   return {
       
 36210     restrict: 'CA',
       
 36211     controller: 'DropdownController',
       
 36212     link: function(scope, element, attrs, dropdownCtrl) {
       
 36213       dropdownCtrl.init( element );
       
 36214     }
       
 36215   };
       
 36216 })
       
 36217 
       
 36218 .directive('dropdownToggle', function() {
       
 36219   return {
       
 36220     restrict: 'CA',
       
 36221     require: '?^dropdown',
       
 36222     link: function(scope, element, attrs, dropdownCtrl) {
       
 36223       if ( !dropdownCtrl ) {
       
 36224         return;
       
 36225       }
       
 36226 
       
 36227       dropdownCtrl.toggleElement = element;
       
 36228 
       
 36229       var toggleDropdown = function(event) {
       
 36230         event.preventDefault();
       
 36231 
       
 36232         if ( !element.hasClass('disabled') && !attrs.disabled ) {
       
 36233           scope.$apply(function() {
       
 36234             dropdownCtrl.toggle();
       
 36235           });
       
 36236         }
       
 36237       };
       
 36238 
       
 36239       element.bind('click', toggleDropdown);
       
 36240 
       
 36241       // WAI-ARIA
       
 36242       element.attr({ 'aria-haspopup': true, 'aria-expanded': false });
       
 36243       scope.$watch(dropdownCtrl.isOpen, function( isOpen ) {
       
 36244         element.attr('aria-expanded', !!isOpen);
       
 36245       });
       
 36246 
       
 36247       scope.$on('$destroy', function() {
       
 36248         element.unbind('click', toggleDropdown);
       
 36249       });
       
 36250     }
       
 36251   };
       
 36252 });
       
 36253 
       
 36254 angular.module('ui.bootstrap.modal', ['ui.bootstrap.transition'])
       
 36255 
       
 36256 /**
       
 36257  * A helper, internal data structure that acts as a map but also allows getting / removing
       
 36258  * elements in the LIFO order
       
 36259  */
       
 36260   .factory('$$stackedMap', function () {
       
 36261     return {
       
 36262       createNew: function () {
       
 36263         var stack = [];
       
 36264 
       
 36265         return {
       
 36266           add: function (key, value) {
       
 36267             stack.push({
       
 36268               key: key,
       
 36269               value: value
       
 36270             });
       
 36271           },
       
 36272           get: function (key) {
       
 36273             for (var i = 0; i < stack.length; i++) {
       
 36274               if (key == stack[i].key) {
       
 36275                 return stack[i];
       
 36276               }
       
 36277             }
       
 36278           },
       
 36279           keys: function() {
       
 36280             var keys = [];
       
 36281             for (var i = 0; i < stack.length; i++) {
       
 36282               keys.push(stack[i].key);
       
 36283             }
       
 36284             return keys;
       
 36285           },
       
 36286           top: function () {
       
 36287             return stack[stack.length - 1];
       
 36288           },
       
 36289           remove: function (key) {
       
 36290             var idx = -1;
       
 36291             for (var i = 0; i < stack.length; i++) {
       
 36292               if (key == stack[i].key) {
       
 36293                 idx = i;
       
 36294                 break;
       
 36295               }
       
 36296             }
       
 36297             return stack.splice(idx, 1)[0];
       
 36298           },
       
 36299           removeTop: function () {
       
 36300             return stack.splice(stack.length - 1, 1)[0];
       
 36301           },
       
 36302           length: function () {
       
 36303             return stack.length;
       
 36304           }
       
 36305         };
       
 36306       }
       
 36307     };
       
 36308   })
       
 36309 
       
 36310 /**
       
 36311  * A helper directive for the $modal service. It creates a backdrop element.
       
 36312  */
       
 36313   .directive('modalBackdrop', ['$timeout', function ($timeout) {
       
 36314     return {
       
 36315       restrict: 'EA',
       
 36316       replace: true,
       
 36317       templateUrl: 'template/modal/backdrop.html',
       
 36318       link: function (scope, element, attrs) {
       
 36319         scope.backdropClass = attrs.backdropClass || '';
       
 36320 
       
 36321         scope.animate = false;
       
 36322 
       
 36323         //trigger CSS transitions
       
 36324         $timeout(function () {
       
 36325           scope.animate = true;
       
 36326         });
       
 36327       }
       
 36328     };
       
 36329   }])
       
 36330 
       
 36331   .directive('modalWindow', ['$modalStack', '$timeout', function ($modalStack, $timeout) {
       
 36332     return {
       
 36333       restrict: 'EA',
       
 36334       scope: {
       
 36335         index: '@',
       
 36336         animate: '='
       
 36337       },
       
 36338       replace: true,
       
 36339       transclude: true,
       
 36340       templateUrl: function(tElement, tAttrs) {
       
 36341         return tAttrs.templateUrl || 'template/modal/window.html';
       
 36342       },
       
 36343       link: function (scope, element, attrs) {
       
 36344         element.addClass(attrs.windowClass || '');
       
 36345         scope.size = attrs.size;
       
 36346 
       
 36347         $timeout(function () {
       
 36348           // trigger CSS transitions
       
 36349           scope.animate = true;
       
 36350 
       
 36351           /**
       
 36352            * Auto-focusing of a freshly-opened modal element causes any child elements
       
 36353            * with the autofocus attribute to loose focus. This is an issue on touch
       
 36354            * based devices which will show and then hide the onscreen keyboard.
       
 36355            * Attempts to refocus the autofocus element via JavaScript will not reopen
       
 36356            * the onscreen keyboard. Fixed by updated the focusing logic to only autofocus
       
 36357            * the modal element if the modal does not contain an autofocus element.
       
 36358            */
       
 36359           if (!element[0].querySelectorAll('[autofocus]').length) {
       
 36360             element[0].focus();
       
 36361           }
       
 36362         });
       
 36363 
       
 36364         scope.close = function (evt) {
       
 36365           var modal = $modalStack.getTop();
       
 36366           if (modal && modal.value.backdrop && modal.value.backdrop != 'static' && (evt.target === evt.currentTarget)) {
       
 36367             evt.preventDefault();
       
 36368             evt.stopPropagation();
       
 36369             $modalStack.dismiss(modal.key, 'backdrop click');
       
 36370           }
       
 36371         };
       
 36372       }
       
 36373     };
       
 36374   }])
       
 36375 
       
 36376   .directive('modalTransclude', function () {
       
 36377     return {
       
 36378       link: function($scope, $element, $attrs, controller, $transclude) {
       
 36379         $transclude($scope.$parent, function(clone) {
       
 36380           $element.empty();
       
 36381           $element.append(clone);
       
 36382         });
       
 36383       }
       
 36384     };
       
 36385   })
       
 36386 
       
 36387   .factory('$modalStack', ['$transition', '$timeout', '$document', '$compile', '$rootScope', '$$stackedMap',
       
 36388     function ($transition, $timeout, $document, $compile, $rootScope, $$stackedMap) {
       
 36389 
       
 36390       var OPENED_MODAL_CLASS = 'modal-open';
       
 36391 
       
 36392       var backdropDomEl, backdropScope;
       
 36393       var openedWindows = $$stackedMap.createNew();
       
 36394       var $modalStack = {};
       
 36395 
       
 36396       function backdropIndex() {
       
 36397         var topBackdropIndex = -1;
       
 36398         var opened = openedWindows.keys();
       
 36399         for (var i = 0; i < opened.length; i++) {
       
 36400           if (openedWindows.get(opened[i]).value.backdrop) {
       
 36401             topBackdropIndex = i;
       
 36402           }
       
 36403         }
       
 36404         return topBackdropIndex;
       
 36405       }
       
 36406 
       
 36407       $rootScope.$watch(backdropIndex, function(newBackdropIndex){
       
 36408         if (backdropScope) {
       
 36409           backdropScope.index = newBackdropIndex;
       
 36410         }
       
 36411       });
       
 36412 
       
 36413       function removeModalWindow(modalInstance) {
       
 36414 
       
 36415         var body = $document.find('body').eq(0);
       
 36416         var modalWindow = openedWindows.get(modalInstance).value;
       
 36417 
       
 36418         //clean up the stack
       
 36419         openedWindows.remove(modalInstance);
       
 36420 
       
 36421         //remove window DOM element
       
 36422         removeAfterAnimate(modalWindow.modalDomEl, modalWindow.modalScope, 300, function() {
       
 36423           modalWindow.modalScope.$destroy();
       
 36424           body.toggleClass(OPENED_MODAL_CLASS, openedWindows.length() > 0);
       
 36425           checkRemoveBackdrop();
       
 36426         });
       
 36427       }
       
 36428 
       
 36429       function checkRemoveBackdrop() {
       
 36430           //remove backdrop if no longer needed
       
 36431           if (backdropDomEl && backdropIndex() == -1) {
       
 36432             var backdropScopeRef = backdropScope;
       
 36433             removeAfterAnimate(backdropDomEl, backdropScope, 150, function () {
       
 36434               backdropScopeRef.$destroy();
       
 36435               backdropScopeRef = null;
       
 36436             });
       
 36437             backdropDomEl = undefined;
       
 36438             backdropScope = undefined;
       
 36439           }
       
 36440       }
       
 36441 
       
 36442       function removeAfterAnimate(domEl, scope, emulateTime, done) {
       
 36443         // Closing animation
       
 36444         scope.animate = false;
       
 36445 
       
 36446         var transitionEndEventName = $transition.transitionEndEventName;
       
 36447         if (transitionEndEventName) {
       
 36448           // transition out
       
 36449           var timeout = $timeout(afterAnimating, emulateTime);
       
 36450 
       
 36451           domEl.bind(transitionEndEventName, function () {
       
 36452             $timeout.cancel(timeout);
       
 36453             afterAnimating();
       
 36454             scope.$apply();
       
 36455           });
       
 36456         } else {
       
 36457           // Ensure this call is async
       
 36458           $timeout(afterAnimating);
       
 36459         }
       
 36460 
       
 36461         function afterAnimating() {
       
 36462           if (afterAnimating.done) {
       
 36463             return;
       
 36464           }
       
 36465           afterAnimating.done = true;
       
 36466 
       
 36467           domEl.remove();
       
 36468           if (done) {
       
 36469             done();
       
 36470           }
       
 36471         }
       
 36472       }
       
 36473 
       
 36474       $document.bind('keydown', function (evt) {
       
 36475         var modal;
       
 36476 
       
 36477         if (evt.which === 27) {
       
 36478           modal = openedWindows.top();
       
 36479           if (modal && modal.value.keyboard) {
       
 36480             evt.preventDefault();
       
 36481             $rootScope.$apply(function () {
       
 36482               $modalStack.dismiss(modal.key, 'escape key press');
       
 36483             });
       
 36484           }
       
 36485         }
       
 36486       });
       
 36487 
       
 36488       $modalStack.open = function (modalInstance, modal) {
       
 36489 
       
 36490         openedWindows.add(modalInstance, {
       
 36491           deferred: modal.deferred,
       
 36492           modalScope: modal.scope,
       
 36493           backdrop: modal.backdrop,
       
 36494           keyboard: modal.keyboard
       
 36495         });
       
 36496 
       
 36497         var body = $document.find('body').eq(0),
       
 36498             currBackdropIndex = backdropIndex();
       
 36499 
       
 36500         if (currBackdropIndex >= 0 && !backdropDomEl) {
       
 36501           backdropScope = $rootScope.$new(true);
       
 36502           backdropScope.index = currBackdropIndex;
       
 36503           var angularBackgroundDomEl = angular.element('<div modal-backdrop></div>');
       
 36504           angularBackgroundDomEl.attr('backdrop-class', modal.backdropClass);
       
 36505           backdropDomEl = $compile(angularBackgroundDomEl)(backdropScope);
       
 36506           body.append(backdropDomEl);
       
 36507         }
       
 36508 
       
 36509         var angularDomEl = angular.element('<div modal-window></div>');
       
 36510         angularDomEl.attr({
       
 36511           'template-url': modal.windowTemplateUrl,
       
 36512           'window-class': modal.windowClass,
       
 36513           'size': modal.size,
       
 36514           'index': openedWindows.length() - 1,
       
 36515           'animate': 'animate'
       
 36516         }).html(modal.content);
       
 36517 
       
 36518         var modalDomEl = $compile(angularDomEl)(modal.scope);
       
 36519         openedWindows.top().value.modalDomEl = modalDomEl;
       
 36520         body.append(modalDomEl);
       
 36521         body.addClass(OPENED_MODAL_CLASS);
       
 36522       };
       
 36523 
       
 36524       $modalStack.close = function (modalInstance, result) {
       
 36525         var modalWindow = openedWindows.get(modalInstance);
       
 36526         if (modalWindow) {
       
 36527           modalWindow.value.deferred.resolve(result);
       
 36528           removeModalWindow(modalInstance);
       
 36529         }
       
 36530       };
       
 36531 
       
 36532       $modalStack.dismiss = function (modalInstance, reason) {
       
 36533         var modalWindow = openedWindows.get(modalInstance);
       
 36534         if (modalWindow) {
       
 36535           modalWindow.value.deferred.reject(reason);
       
 36536           removeModalWindow(modalInstance);
       
 36537         }
       
 36538       };
       
 36539 
       
 36540       $modalStack.dismissAll = function (reason) {
       
 36541         var topModal = this.getTop();
       
 36542         while (topModal) {
       
 36543           this.dismiss(topModal.key, reason);
       
 36544           topModal = this.getTop();
       
 36545         }
       
 36546       };
       
 36547 
       
 36548       $modalStack.getTop = function () {
       
 36549         return openedWindows.top();
       
 36550       };
       
 36551 
       
 36552       return $modalStack;
       
 36553     }])
       
 36554 
       
 36555   .provider('$modal', function () {
       
 36556 
       
 36557     var $modalProvider = {
       
 36558       options: {
       
 36559         backdrop: true, //can be also false or 'static'
       
 36560         keyboard: true
       
 36561       },
       
 36562       $get: ['$injector', '$rootScope', '$q', '$http', '$templateCache', '$controller', '$modalStack',
       
 36563         function ($injector, $rootScope, $q, $http, $templateCache, $controller, $modalStack) {
       
 36564 
       
 36565           var $modal = {};
       
 36566 
       
 36567           function getTemplatePromise(options) {
       
 36568             return options.template ? $q.when(options.template) :
       
 36569               $http.get(angular.isFunction(options.templateUrl) ? (options.templateUrl)() : options.templateUrl,
       
 36570                 {cache: $templateCache}).then(function (result) {
       
 36571                   return result.data;
       
 36572               });
       
 36573           }
       
 36574 
       
 36575           function getResolvePromises(resolves) {
       
 36576             var promisesArr = [];
       
 36577             angular.forEach(resolves, function (value) {
       
 36578               if (angular.isFunction(value) || angular.isArray(value)) {
       
 36579                 promisesArr.push($q.when($injector.invoke(value)));
       
 36580               }
       
 36581             });
       
 36582             return promisesArr;
       
 36583           }
       
 36584 
       
 36585           $modal.open = function (modalOptions) {
       
 36586 
       
 36587             var modalResultDeferred = $q.defer();
       
 36588             var modalOpenedDeferred = $q.defer();
       
 36589 
       
 36590             //prepare an instance of a modal to be injected into controllers and returned to a caller
       
 36591             var modalInstance = {
       
 36592               result: modalResultDeferred.promise,
       
 36593               opened: modalOpenedDeferred.promise,
       
 36594               close: function (result) {
       
 36595                 $modalStack.close(modalInstance, result);
       
 36596               },
       
 36597               dismiss: function (reason) {
       
 36598                 $modalStack.dismiss(modalInstance, reason);
       
 36599               }
       
 36600             };
       
 36601 
       
 36602             //merge and clean up options
       
 36603             modalOptions = angular.extend({}, $modalProvider.options, modalOptions);
       
 36604             modalOptions.resolve = modalOptions.resolve || {};
       
 36605 
       
 36606             //verify options
       
 36607             if (!modalOptions.template && !modalOptions.templateUrl) {
       
 36608               throw new Error('One of template or templateUrl options is required.');
       
 36609             }
       
 36610 
       
 36611             var templateAndResolvePromise =
       
 36612               $q.all([getTemplatePromise(modalOptions)].concat(getResolvePromises(modalOptions.resolve)));
       
 36613 
       
 36614 
       
 36615             templateAndResolvePromise.then(function resolveSuccess(tplAndVars) {
       
 36616 
       
 36617               var modalScope = (modalOptions.scope || $rootScope).$new();
       
 36618               modalScope.$close = modalInstance.close;
       
 36619               modalScope.$dismiss = modalInstance.dismiss;
       
 36620 
       
 36621               var ctrlInstance, ctrlLocals = {};
       
 36622               var resolveIter = 1;
       
 36623 
       
 36624               //controllers
       
 36625               if (modalOptions.controller) {
       
 36626                 ctrlLocals.$scope = modalScope;
       
 36627                 ctrlLocals.$modalInstance = modalInstance;
       
 36628                 angular.forEach(modalOptions.resolve, function (value, key) {
       
 36629                   ctrlLocals[key] = tplAndVars[resolveIter++];
       
 36630                 });
       
 36631 
       
 36632                 ctrlInstance = $controller(modalOptions.controller, ctrlLocals);
       
 36633                 if (modalOptions.controllerAs) {
       
 36634                   modalScope[modalOptions.controllerAs] = ctrlInstance;
       
 36635                 }
       
 36636               }
       
 36637 
       
 36638               $modalStack.open(modalInstance, {
       
 36639                 scope: modalScope,
       
 36640                 deferred: modalResultDeferred,
       
 36641                 content: tplAndVars[0],
       
 36642                 backdrop: modalOptions.backdrop,
       
 36643                 keyboard: modalOptions.keyboard,
       
 36644                 backdropClass: modalOptions.backdropClass,
       
 36645                 windowClass: modalOptions.windowClass,
       
 36646                 windowTemplateUrl: modalOptions.windowTemplateUrl,
       
 36647                 size: modalOptions.size
       
 36648               });
       
 36649 
       
 36650             }, function resolveError(reason) {
       
 36651               modalResultDeferred.reject(reason);
       
 36652             });
       
 36653 
       
 36654             templateAndResolvePromise.then(function () {
       
 36655               modalOpenedDeferred.resolve(true);
       
 36656             }, function () {
       
 36657               modalOpenedDeferred.reject(false);
       
 36658             });
       
 36659 
       
 36660             return modalInstance;
       
 36661           };
       
 36662 
       
 36663           return $modal;
       
 36664         }]
       
 36665     };
       
 36666 
       
 36667     return $modalProvider;
       
 36668   });
       
 36669 
       
 36670 angular.module('ui.bootstrap.pagination', [])
       
 36671 
       
 36672 .controller('PaginationController', ['$scope', '$attrs', '$parse', function ($scope, $attrs, $parse) {
       
 36673   var self = this,
       
 36674       ngModelCtrl = { $setViewValue: angular.noop }, // nullModelCtrl
       
 36675       setNumPages = $attrs.numPages ? $parse($attrs.numPages).assign : angular.noop;
       
 36676 
       
 36677   this.init = function(ngModelCtrl_, config) {
       
 36678     ngModelCtrl = ngModelCtrl_;
       
 36679     this.config = config;
       
 36680 
       
 36681     ngModelCtrl.$render = function() {
       
 36682       self.render();
       
 36683     };
       
 36684 
       
 36685     if ($attrs.itemsPerPage) {
       
 36686       $scope.$parent.$watch($parse($attrs.itemsPerPage), function(value) {
       
 36687         self.itemsPerPage = parseInt(value, 10);
       
 36688         $scope.totalPages = self.calculateTotalPages();
       
 36689       });
       
 36690     } else {
       
 36691       this.itemsPerPage = config.itemsPerPage;
       
 36692     }
       
 36693   };
       
 36694 
       
 36695   this.calculateTotalPages = function() {
       
 36696     var totalPages = this.itemsPerPage < 1 ? 1 : Math.ceil($scope.totalItems / this.itemsPerPage);
       
 36697     return Math.max(totalPages || 0, 1);
       
 36698   };
       
 36699 
       
 36700   this.render = function() {
       
 36701     $scope.page = parseInt(ngModelCtrl.$viewValue, 10) || 1;
       
 36702   };
       
 36703 
       
 36704   $scope.selectPage = function(page) {
       
 36705     if ( $scope.page !== page && page > 0 && page <= $scope.totalPages) {
       
 36706       ngModelCtrl.$setViewValue(page);
       
 36707       ngModelCtrl.$render();
       
 36708     }
       
 36709   };
       
 36710 
       
 36711   $scope.getText = function( key ) {
       
 36712     return $scope[key + 'Text'] || self.config[key + 'Text'];
       
 36713   };
       
 36714   $scope.noPrevious = function() {
       
 36715     return $scope.page === 1;
       
 36716   };
       
 36717   $scope.noNext = function() {
       
 36718     return $scope.page === $scope.totalPages;
       
 36719   };
       
 36720 
       
 36721   $scope.$watch('totalItems', function() {
       
 36722     $scope.totalPages = self.calculateTotalPages();
       
 36723   });
       
 36724 
       
 36725   $scope.$watch('totalPages', function(value) {
       
 36726     setNumPages($scope.$parent, value); // Readonly variable
       
 36727 
       
 36728     if ( $scope.page > value ) {
       
 36729       $scope.selectPage(value);
       
 36730     } else {
       
 36731       ngModelCtrl.$render();
       
 36732     }
       
 36733   });
       
 36734 }])
       
 36735 
       
 36736 .constant('paginationConfig', {
       
 36737   itemsPerPage: 10,
       
 36738   boundaryLinks: false,
       
 36739   directionLinks: true,
       
 36740   firstText: 'First',
       
 36741   previousText: 'Previous',
       
 36742   nextText: 'Next',
       
 36743   lastText: 'Last',
       
 36744   rotate: true
       
 36745 })
       
 36746 
       
 36747 .directive('pagination', ['$parse', 'paginationConfig', function($parse, paginationConfig) {
       
 36748   return {
       
 36749     restrict: 'EA',
       
 36750     scope: {
       
 36751       totalItems: '=',
       
 36752       firstText: '@',
       
 36753       previousText: '@',
       
 36754       nextText: '@',
       
 36755       lastText: '@'
       
 36756     },
       
 36757     require: ['pagination', '?ngModel'],
       
 36758     controller: 'PaginationController',
       
 36759     templateUrl: 'template/pagination/pagination.html',
       
 36760     replace: true,
       
 36761     link: function(scope, element, attrs, ctrls) {
       
 36762       var paginationCtrl = ctrls[0], ngModelCtrl = ctrls[1];
       
 36763 
       
 36764       if (!ngModelCtrl) {
       
 36765          return; // do nothing if no ng-model
       
 36766       }
       
 36767 
       
 36768       // Setup configuration parameters
       
 36769       var maxSize = angular.isDefined(attrs.maxSize) ? scope.$parent.$eval(attrs.maxSize) : paginationConfig.maxSize,
       
 36770           rotate = angular.isDefined(attrs.rotate) ? scope.$parent.$eval(attrs.rotate) : paginationConfig.rotate;
       
 36771       scope.boundaryLinks = angular.isDefined(attrs.boundaryLinks) ? scope.$parent.$eval(attrs.boundaryLinks) : paginationConfig.boundaryLinks;
       
 36772       scope.directionLinks = angular.isDefined(attrs.directionLinks) ? scope.$parent.$eval(attrs.directionLinks) : paginationConfig.directionLinks;
       
 36773 
       
 36774       paginationCtrl.init(ngModelCtrl, paginationConfig);
       
 36775 
       
 36776       if (attrs.maxSize) {
       
 36777         scope.$parent.$watch($parse(attrs.maxSize), function(value) {
       
 36778           maxSize = parseInt(value, 10);
       
 36779           paginationCtrl.render();
       
 36780         });
       
 36781       }
       
 36782 
       
 36783       // Create page object used in template
       
 36784       function makePage(number, text, isActive) {
       
 36785         return {
       
 36786           number: number,
       
 36787           text: text,
       
 36788           active: isActive
       
 36789         };
       
 36790       }
       
 36791 
       
 36792       function getPages(currentPage, totalPages) {
       
 36793         var pages = [];
       
 36794 
       
 36795         // Default page limits
       
 36796         var startPage = 1, endPage = totalPages;
       
 36797         var isMaxSized = ( angular.isDefined(maxSize) && maxSize < totalPages );
       
 36798 
       
 36799         // recompute if maxSize
       
 36800         if ( isMaxSized ) {
       
 36801           if ( rotate ) {
       
 36802             // Current page is displayed in the middle of the visible ones
       
 36803             startPage = Math.max(currentPage - Math.floor(maxSize/2), 1);
       
 36804             endPage   = startPage + maxSize - 1;
       
 36805 
       
 36806             // Adjust if limit is exceeded
       
 36807             if (endPage > totalPages) {
       
 36808               endPage   = totalPages;
       
 36809               startPage = endPage - maxSize + 1;
       
 36810             }
       
 36811           } else {
       
 36812             // Visible pages are paginated with maxSize
       
 36813             startPage = ((Math.ceil(currentPage / maxSize) - 1) * maxSize) + 1;
       
 36814 
       
 36815             // Adjust last page if limit is exceeded
       
 36816             endPage = Math.min(startPage + maxSize - 1, totalPages);
       
 36817           }
       
 36818         }
       
 36819 
       
 36820         // Add page number links
       
 36821         for (var number = startPage; number <= endPage; number++) {
       
 36822           var page = makePage(number, number, number === currentPage);
       
 36823           pages.push(page);
       
 36824         }
       
 36825 
       
 36826         // Add links to move between page sets
       
 36827         if ( isMaxSized && ! rotate ) {
       
 36828           if ( startPage > 1 ) {
       
 36829             var previousPageSet = makePage(startPage - 1, '...', false);
       
 36830             pages.unshift(previousPageSet);
       
 36831           }
       
 36832 
       
 36833           if ( endPage < totalPages ) {
       
 36834             var nextPageSet = makePage(endPage + 1, '...', false);
       
 36835             pages.push(nextPageSet);
       
 36836           }
       
 36837         }
       
 36838 
       
 36839         return pages;
       
 36840       }
       
 36841 
       
 36842       var originalRender = paginationCtrl.render;
       
 36843       paginationCtrl.render = function() {
       
 36844         originalRender();
       
 36845         if (scope.page > 0 && scope.page <= scope.totalPages) {
       
 36846           scope.pages = getPages(scope.page, scope.totalPages);
       
 36847         }
       
 36848       };
       
 36849     }
       
 36850   };
       
 36851 }])
       
 36852 
       
 36853 .constant('pagerConfig', {
       
 36854   itemsPerPage: 10,
       
 36855   previousText: '« Previous',
       
 36856   nextText: 'Next »',
       
 36857   align: true
       
 36858 })
       
 36859 
       
 36860 .directive('pager', ['pagerConfig', function(pagerConfig) {
       
 36861   return {
       
 36862     restrict: 'EA',
       
 36863     scope: {
       
 36864       totalItems: '=',
       
 36865       previousText: '@',
       
 36866       nextText: '@'
       
 36867     },
       
 36868     require: ['pager', '?ngModel'],
       
 36869     controller: 'PaginationController',
       
 36870     templateUrl: 'template/pagination/pager.html',
       
 36871     replace: true,
       
 36872     link: function(scope, element, attrs, ctrls) {
       
 36873       var paginationCtrl = ctrls[0], ngModelCtrl = ctrls[1];
       
 36874 
       
 36875       if (!ngModelCtrl) {
       
 36876          return; // do nothing if no ng-model
       
 36877       }
       
 36878 
       
 36879       scope.align = angular.isDefined(attrs.align) ? scope.$parent.$eval(attrs.align) : pagerConfig.align;
       
 36880       paginationCtrl.init(ngModelCtrl, pagerConfig);
       
 36881     }
       
 36882   };
       
 36883 }]);
       
 36884 
       
 36885 /**
       
 36886  * The following features are still outstanding: animation as a
       
 36887  * function, placement as a function, inside, support for more triggers than
       
 36888  * just mouse enter/leave, html tooltips, and selector delegation.
       
 36889  */
       
 36890 angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position', 'ui.bootstrap.bindHtml' ] )
       
 36891 
       
 36892 /**
       
 36893  * The $tooltip service creates tooltip- and popover-like directives as well as
       
 36894  * houses global options for them.
       
 36895  */
       
 36896 .provider( '$tooltip', function () {
       
 36897   // The default options tooltip and popover.
       
 36898   var defaultOptions = {
       
 36899     placement: 'top',
       
 36900     animation: true,
       
 36901     popupDelay: 0
       
 36902   };
       
 36903 
       
 36904   // Default hide triggers for each show trigger
       
 36905   var triggerMap = {
       
 36906     'mouseenter': 'mouseleave',
       
 36907     'click': 'click',
       
 36908     'focus': 'blur'
       
 36909   };
       
 36910 
       
 36911   // The options specified to the provider globally.
       
 36912   var globalOptions = {};
       
 36913 
       
 36914   /**
       
 36915    * `options({})` allows global configuration of all tooltips in the
       
 36916    * application.
       
 36917    *
       
 36918    *   var app = angular.module( 'App', ['ui.bootstrap.tooltip'], function( $tooltipProvider ) {
       
 36919    *     // place tooltips left instead of top by default
       
 36920    *     $tooltipProvider.options( { placement: 'left' } );
       
 36921    *   });
       
 36922    */
       
 36923 	this.options = function( value ) {
       
 36924 		angular.extend( globalOptions, value );
       
 36925 	};
       
 36926 
       
 36927   /**
       
 36928    * This allows you to extend the set of trigger mappings available. E.g.:
       
 36929    *
       
 36930    *   $tooltipProvider.setTriggers( 'openTrigger': 'closeTrigger' );
       
 36931    */
       
 36932   this.setTriggers = function setTriggers ( triggers ) {
       
 36933     angular.extend( triggerMap, triggers );
       
 36934   };
       
 36935 
       
 36936   /**
       
 36937    * This is a helper function for translating camel-case to snake-case.
       
 36938    */
       
 36939   function snake_case(name){
       
 36940     var regexp = /[A-Z]/g;
       
 36941     var separator = '-';
       
 36942     return name.replace(regexp, function(letter, pos) {
       
 36943       return (pos ? separator : '') + letter.toLowerCase();
       
 36944     });
       
 36945   }
       
 36946 
       
 36947   /**
       
 36948    * Returns the actual instance of the $tooltip service.
       
 36949    * TODO support multiple triggers
       
 36950    */
       
 36951   this.$get = [ '$window', '$compile', '$timeout', '$parse', '$document', '$position', '$interpolate', function ( $window, $compile, $timeout, $parse, $document, $position, $interpolate ) {
       
 36952     return function $tooltip ( type, prefix, defaultTriggerShow ) {
       
 36953       var options = angular.extend( {}, defaultOptions, globalOptions );
       
 36954 
       
 36955       /**
       
 36956        * Returns an object of show and hide triggers.
       
 36957        *
       
 36958        * If a trigger is supplied,
       
 36959        * it is used to show the tooltip; otherwise, it will use the `trigger`
       
 36960        * option passed to the `$tooltipProvider.options` method; else it will
       
 36961        * default to the trigger supplied to this directive factory.
       
 36962        *
       
 36963        * The hide trigger is based on the show trigger. If the `trigger` option
       
 36964        * was passed to the `$tooltipProvider.options` method, it will use the
       
 36965        * mapped trigger from `triggerMap` or the passed trigger if the map is
       
 36966        * undefined; otherwise, it uses the `triggerMap` value of the show
       
 36967        * trigger; else it will just use the show trigger.
       
 36968        */
       
 36969       function getTriggers ( trigger ) {
       
 36970         var show = trigger || options.trigger || defaultTriggerShow;
       
 36971         var hide = triggerMap[show] || show;
       
 36972         return {
       
 36973           show: show,
       
 36974           hide: hide
       
 36975         };
       
 36976       }
       
 36977 
       
 36978       var directiveName = snake_case( type );
       
 36979 
       
 36980       var startSym = $interpolate.startSymbol();
       
 36981       var endSym = $interpolate.endSymbol();
       
 36982       var template =
       
 36983         '<div '+ directiveName +'-popup '+
       
 36984           'title="'+startSym+'tt_title'+endSym+'" '+
       
 36985           'content="'+startSym+'tt_content'+endSym+'" '+
       
 36986           'placement="'+startSym+'tt_placement'+endSym+'" '+
       
 36987           'animation="tt_animation" '+
       
 36988           'is-open="tt_isOpen"'+
       
 36989           '>'+
       
 36990         '</div>';
       
 36991 
       
 36992       return {
       
 36993         restrict: 'EA',
       
 36994         scope: true,
       
 36995         compile: function (tElem, tAttrs) {
       
 36996           var tooltipLinker = $compile( template );
       
 36997 
       
 36998           return function link ( scope, element, attrs ) {
       
 36999             var tooltip;
       
 37000             var transitionTimeout;
       
 37001             var popupTimeout;
       
 37002             var appendToBody = angular.isDefined( options.appendToBody ) ? options.appendToBody : false;
       
 37003             var triggers = getTriggers( undefined );
       
 37004             var hasEnableExp = angular.isDefined(attrs[prefix+'Enable']);
       
 37005 
       
 37006             var positionTooltip = function () {
       
 37007 
       
 37008               var ttPosition = $position.positionElements(element, tooltip, scope.tt_placement, appendToBody);
       
 37009               ttPosition.top += 'px';
       
 37010               ttPosition.left += 'px';
       
 37011 
       
 37012               // Now set the calculated positioning.
       
 37013               tooltip.css( ttPosition );
       
 37014             };
       
 37015 
       
 37016             // By default, the tooltip is not open.
       
 37017             // TODO add ability to start tooltip opened
       
 37018             scope.tt_isOpen = false;
       
 37019 
       
 37020             function toggleTooltipBind () {
       
 37021               if ( ! scope.tt_isOpen ) {
       
 37022                 showTooltipBind();
       
 37023               } else {
       
 37024                 hideTooltipBind();
       
 37025               }
       
 37026             }
       
 37027 
       
 37028             // Show the tooltip with delay if specified, otherwise show it immediately
       
 37029             function showTooltipBind() {
       
 37030               if(hasEnableExp && !scope.$eval(attrs[prefix+'Enable'])) {
       
 37031                 return;
       
 37032               }
       
 37033               if ( scope.tt_popupDelay ) {
       
 37034                 // Do nothing if the tooltip was already scheduled to pop-up.
       
 37035                 // This happens if show is triggered multiple times before any hide is triggered.
       
 37036                 if (!popupTimeout) {
       
 37037                   popupTimeout = $timeout( show, scope.tt_popupDelay, false );
       
 37038                   popupTimeout.then(function(reposition){reposition();});
       
 37039                 }
       
 37040               } else {
       
 37041                 show()();
       
 37042               }
       
 37043             }
       
 37044 
       
 37045             function hideTooltipBind () {
       
 37046               scope.$apply(function () {
       
 37047                 hide();
       
 37048               });
       
 37049             }
       
 37050 
       
 37051             // Show the tooltip popup element.
       
 37052             function show() {
       
 37053 
       
 37054               popupTimeout = null;
       
 37055 
       
 37056               // If there is a pending remove transition, we must cancel it, lest the
       
 37057               // tooltip be mysteriously removed.
       
 37058               if ( transitionTimeout ) {
       
 37059                 $timeout.cancel( transitionTimeout );
       
 37060                 transitionTimeout = null;
       
 37061               }
       
 37062 
       
 37063               // Don't show empty tooltips.
       
 37064               if ( ! scope.tt_content ) {
       
 37065                 return angular.noop;
       
 37066               }
       
 37067 
       
 37068               createTooltip();
       
 37069 
       
 37070               // Set the initial positioning.
       
 37071               tooltip.css({ top: 0, left: 0, display: 'block' });
       
 37072 
       
 37073               // Now we add it to the DOM because need some info about it. But it's not 
       
 37074               // visible yet anyway.
       
 37075               if ( appendToBody ) {
       
 37076                   $document.find( 'body' ).append( tooltip );
       
 37077               } else {
       
 37078                 element.after( tooltip );
       
 37079               }
       
 37080 
       
 37081               positionTooltip();
       
 37082 
       
 37083               // And show the tooltip.
       
 37084               scope.tt_isOpen = true;
       
 37085               scope.$digest(); // digest required as $apply is not called
       
 37086 
       
 37087               // Return positioning function as promise callback for correct
       
 37088               // positioning after draw.
       
 37089               return positionTooltip;
       
 37090             }
       
 37091 
       
 37092             // Hide the tooltip popup element.
       
 37093             function hide() {
       
 37094               // First things first: we don't show it anymore.
       
 37095               scope.tt_isOpen = false;
       
 37096 
       
 37097               //if tooltip is going to be shown after delay, we must cancel this
       
 37098               $timeout.cancel( popupTimeout );
       
 37099               popupTimeout = null;
       
 37100 
       
 37101               // And now we remove it from the DOM. However, if we have animation, we 
       
 37102               // need to wait for it to expire beforehand.
       
 37103               // FIXME: this is a placeholder for a port of the transitions library.
       
 37104               if ( scope.tt_animation ) {
       
 37105                 if (!transitionTimeout) {
       
 37106                   transitionTimeout = $timeout(removeTooltip, 500);
       
 37107                 }
       
 37108               } else {
       
 37109                 removeTooltip();
       
 37110               }
       
 37111             }
       
 37112 
       
 37113             function createTooltip() {
       
 37114               // There can only be one tooltip element per directive shown at once.
       
 37115               if (tooltip) {
       
 37116                 removeTooltip();
       
 37117               }
       
 37118               tooltip = tooltipLinker(scope, function () {});
       
 37119 
       
 37120               // Get contents rendered into the tooltip
       
 37121               scope.$digest();
       
 37122             }
       
 37123 
       
 37124             function removeTooltip() {
       
 37125               transitionTimeout = null;
       
 37126               if (tooltip) {
       
 37127                 tooltip.remove();
       
 37128                 tooltip = null;
       
 37129               }
       
 37130             }
       
 37131 
       
 37132             /**
       
 37133              * Observe the relevant attributes.
       
 37134              */
       
 37135             attrs.$observe( type, function ( val ) {
       
 37136               scope.tt_content = val;
       
 37137 
       
 37138               if (!val && scope.tt_isOpen ) {
       
 37139                 hide();
       
 37140               }
       
 37141             });
       
 37142 
       
 37143             attrs.$observe( prefix+'Title', function ( val ) {
       
 37144               scope.tt_title = val;
       
 37145             });
       
 37146 
       
 37147             attrs.$observe( prefix+'Placement', function ( val ) {
       
 37148               scope.tt_placement = angular.isDefined( val ) ? val : options.placement;
       
 37149             });
       
 37150 
       
 37151             attrs.$observe( prefix+'PopupDelay', function ( val ) {
       
 37152               var delay = parseInt( val, 10 );
       
 37153               scope.tt_popupDelay = ! isNaN(delay) ? delay : options.popupDelay;
       
 37154             });
       
 37155 
       
 37156             var unregisterTriggers = function () {
       
 37157               element.unbind(triggers.show, showTooltipBind);
       
 37158               element.unbind(triggers.hide, hideTooltipBind);
       
 37159             };
       
 37160 
       
 37161             attrs.$observe( prefix+'Trigger', function ( val ) {
       
 37162               unregisterTriggers();
       
 37163 
       
 37164               triggers = getTriggers( val );
       
 37165 
       
 37166               if ( triggers.show === triggers.hide ) {
       
 37167                 element.bind( triggers.show, toggleTooltipBind );
       
 37168               } else {
       
 37169                 element.bind( triggers.show, showTooltipBind );
       
 37170                 element.bind( triggers.hide, hideTooltipBind );
       
 37171               }
       
 37172             });
       
 37173 
       
 37174             var animation = scope.$eval(attrs[prefix + 'Animation']);
       
 37175             scope.tt_animation = angular.isDefined(animation) ? !!animation : options.animation;
       
 37176 
       
 37177             attrs.$observe( prefix+'AppendToBody', function ( val ) {
       
 37178               appendToBody = angular.isDefined( val ) ? $parse( val )( scope ) : appendToBody;
       
 37179             });
       
 37180 
       
 37181             // if a tooltip is attached to <body> we need to remove it on
       
 37182             // location change as its parent scope will probably not be destroyed
       
 37183             // by the change.
       
 37184             if ( appendToBody ) {
       
 37185               scope.$on('$locationChangeSuccess', function closeTooltipOnLocationChangeSuccess () {
       
 37186               if ( scope.tt_isOpen ) {
       
 37187                 hide();
       
 37188               }
       
 37189             });
       
 37190             }
       
 37191 
       
 37192             // Make sure tooltip is destroyed and removed.
       
 37193             scope.$on('$destroy', function onDestroyTooltip() {
       
 37194               $timeout.cancel( transitionTimeout );
       
 37195               $timeout.cancel( popupTimeout );
       
 37196               unregisterTriggers();
       
 37197               removeTooltip();
       
 37198             });
       
 37199           };
       
 37200         }
       
 37201       };
       
 37202     };
       
 37203   }];
       
 37204 })
       
 37205 
       
 37206 .directive( 'tooltipPopup', function () {
       
 37207   return {
       
 37208     restrict: 'EA',
       
 37209     replace: true,
       
 37210     scope: { content: '@', placement: '@', animation: '&', isOpen: '&' },
       
 37211     templateUrl: 'template/tooltip/tooltip-popup.html'
       
 37212   };
       
 37213 })
       
 37214 
       
 37215 .directive( 'tooltip', [ '$tooltip', function ( $tooltip ) {
       
 37216   return $tooltip( 'tooltip', 'tooltip', 'mouseenter' );
       
 37217 }])
       
 37218 
       
 37219 .directive( 'tooltipHtmlUnsafePopup', function () {
       
 37220   return {
       
 37221     restrict: 'EA',
       
 37222     replace: true,
       
 37223     scope: { content: '@', placement: '@', animation: '&', isOpen: '&' },
       
 37224     templateUrl: 'template/tooltip/tooltip-html-unsafe-popup.html'
       
 37225   };
       
 37226 })
       
 37227 
       
 37228 .directive( 'tooltipHtmlUnsafe', [ '$tooltip', function ( $tooltip ) {
       
 37229   return $tooltip( 'tooltipHtmlUnsafe', 'tooltip', 'mouseenter' );
       
 37230 }]);
       
 37231 
       
 37232 /**
       
 37233  * The following features are still outstanding: popup delay, animation as a
       
 37234  * function, placement as a function, inside, support for more triggers than
       
 37235  * just mouse enter/leave, html popovers, and selector delegatation.
       
 37236  */
       
 37237 angular.module( 'ui.bootstrap.popover', [ 'ui.bootstrap.tooltip' ] )
       
 37238 
       
 37239 .directive( 'popoverPopup', function () {
       
 37240   return {
       
 37241     restrict: 'EA',
       
 37242     replace: true,
       
 37243     scope: { title: '@', content: '@', placement: '@', animation: '&', isOpen: '&' },
       
 37244     templateUrl: 'template/popover/popover.html'
       
 37245   };
       
 37246 })
       
 37247 
       
 37248 .directive( 'popover', [ '$tooltip', function ( $tooltip ) {
       
 37249   return $tooltip( 'popover', 'popover', 'click' );
       
 37250 }]);
       
 37251 
       
 37252 angular.module('ui.bootstrap.progressbar', [])
       
 37253 
       
 37254 .constant('progressConfig', {
       
 37255   animate: true,
       
 37256   max: 100
       
 37257 })
       
 37258 
       
 37259 .controller('ProgressController', ['$scope', '$attrs', 'progressConfig', function($scope, $attrs, progressConfig) {
       
 37260     var self = this,
       
 37261         animate = angular.isDefined($attrs.animate) ? $scope.$parent.$eval($attrs.animate) : progressConfig.animate;
       
 37262 
       
 37263     this.bars = [];
       
 37264     $scope.max = angular.isDefined($attrs.max) ? $scope.$parent.$eval($attrs.max) : progressConfig.max;
       
 37265 
       
 37266     this.addBar = function(bar, element) {
       
 37267         if ( !animate ) {
       
 37268             element.css({'transition': 'none'});
       
 37269         }
       
 37270 
       
 37271         this.bars.push(bar);
       
 37272 
       
 37273         bar.$watch('value', function( value ) {
       
 37274             bar.percent = +(100 * value / $scope.max).toFixed(2);
       
 37275         });
       
 37276 
       
 37277         bar.$on('$destroy', function() {
       
 37278             element = null;
       
 37279             self.removeBar(bar);
       
 37280         });
       
 37281     };
       
 37282 
       
 37283     this.removeBar = function(bar) {
       
 37284         this.bars.splice(this.bars.indexOf(bar), 1);
       
 37285     };
       
 37286 }])
       
 37287 
       
 37288 .directive('progress', function() {
       
 37289     return {
       
 37290         restrict: 'EA',
       
 37291         replace: true,
       
 37292         transclude: true,
       
 37293         controller: 'ProgressController',
       
 37294         require: 'progress',
       
 37295         scope: {},
       
 37296         templateUrl: 'template/progressbar/progress.html'
       
 37297     };
       
 37298 })
       
 37299 
       
 37300 .directive('bar', function() {
       
 37301     return {
       
 37302         restrict: 'EA',
       
 37303         replace: true,
       
 37304         transclude: true,
       
 37305         require: '^progress',
       
 37306         scope: {
       
 37307             value: '=',
       
 37308             type: '@'
       
 37309         },
       
 37310         templateUrl: 'template/progressbar/bar.html',
       
 37311         link: function(scope, element, attrs, progressCtrl) {
       
 37312             progressCtrl.addBar(scope, element);
       
 37313         }
       
 37314     };
       
 37315 })
       
 37316 
       
 37317 .directive('progressbar', function() {
       
 37318     return {
       
 37319         restrict: 'EA',
       
 37320         replace: true,
       
 37321         transclude: true,
       
 37322         controller: 'ProgressController',
       
 37323         scope: {
       
 37324             value: '=',
       
 37325             type: '@'
       
 37326         },
       
 37327         templateUrl: 'template/progressbar/progressbar.html',
       
 37328         link: function(scope, element, attrs, progressCtrl) {
       
 37329             progressCtrl.addBar(scope, angular.element(element.children()[0]));
       
 37330         }
       
 37331     };
       
 37332 });
       
 37333 angular.module('ui.bootstrap.rating', [])
       
 37334 
       
 37335 .constant('ratingConfig', {
       
 37336   max: 5,
       
 37337   stateOn: null,
       
 37338   stateOff: null
       
 37339 })
       
 37340 
       
 37341 .controller('RatingController', ['$scope', '$attrs', 'ratingConfig', function($scope, $attrs, ratingConfig) {
       
 37342   var ngModelCtrl  = { $setViewValue: angular.noop };
       
 37343 
       
 37344   this.init = function(ngModelCtrl_) {
       
 37345     ngModelCtrl = ngModelCtrl_;
       
 37346     ngModelCtrl.$render = this.render;
       
 37347 
       
 37348     this.stateOn = angular.isDefined($attrs.stateOn) ? $scope.$parent.$eval($attrs.stateOn) : ratingConfig.stateOn;
       
 37349     this.stateOff = angular.isDefined($attrs.stateOff) ? $scope.$parent.$eval($attrs.stateOff) : ratingConfig.stateOff;
       
 37350 
       
 37351     var ratingStates = angular.isDefined($attrs.ratingStates) ? $scope.$parent.$eval($attrs.ratingStates) :
       
 37352                         new Array( angular.isDefined($attrs.max) ? $scope.$parent.$eval($attrs.max) : ratingConfig.max );
       
 37353     $scope.range = this.buildTemplateObjects(ratingStates);
       
 37354   };
       
 37355 
       
 37356   this.buildTemplateObjects = function(states) {
       
 37357     for (var i = 0, n = states.length; i < n; i++) {
       
 37358       states[i] = angular.extend({ index: i }, { stateOn: this.stateOn, stateOff: this.stateOff }, states[i]);
       
 37359     }
       
 37360     return states;
       
 37361   };
       
 37362 
       
 37363   $scope.rate = function(value) {
       
 37364     if ( !$scope.readonly && value >= 0 && value <= $scope.range.length ) {
       
 37365       ngModelCtrl.$setViewValue(value);
       
 37366       ngModelCtrl.$render();
       
 37367     }
       
 37368   };
       
 37369 
       
 37370   $scope.enter = function(value) {
       
 37371     if ( !$scope.readonly ) {
       
 37372       $scope.value = value;
       
 37373     }
       
 37374     $scope.onHover({value: value});
       
 37375   };
       
 37376 
       
 37377   $scope.reset = function() {
       
 37378     $scope.value = ngModelCtrl.$viewValue;
       
 37379     $scope.onLeave();
       
 37380   };
       
 37381 
       
 37382   $scope.onKeydown = function(evt) {
       
 37383     if (/(37|38|39|40)/.test(evt.which)) {
       
 37384       evt.preventDefault();
       
 37385       evt.stopPropagation();
       
 37386       $scope.rate( $scope.value + (evt.which === 38 || evt.which === 39 ? 1 : -1) );
       
 37387     }
       
 37388   };
       
 37389 
       
 37390   this.render = function() {
       
 37391     $scope.value = ngModelCtrl.$viewValue;
       
 37392   };
       
 37393 }])
       
 37394 
       
 37395 .directive('rating', function() {
       
 37396   return {
       
 37397     restrict: 'EA',
       
 37398     require: ['rating', 'ngModel'],
       
 37399     scope: {
       
 37400       readonly: '=?',
       
 37401       onHover: '&',
       
 37402       onLeave: '&'
       
 37403     },
       
 37404     controller: 'RatingController',
       
 37405     templateUrl: 'template/rating/rating.html',
       
 37406     replace: true,
       
 37407     link: function(scope, element, attrs, ctrls) {
       
 37408       var ratingCtrl = ctrls[0], ngModelCtrl = ctrls[1];
       
 37409 
       
 37410       if ( ngModelCtrl ) {
       
 37411         ratingCtrl.init( ngModelCtrl );
       
 37412       }
       
 37413     }
       
 37414   };
       
 37415 });
       
 37416 
       
 37417 /**
       
 37418  * @ngdoc overview
       
 37419  * @name ui.bootstrap.tabs
       
 37420  *
       
 37421  * @description
       
 37422  * AngularJS version of the tabs directive.
       
 37423  */
       
 37424 
       
 37425 angular.module('ui.bootstrap.tabs', [])
       
 37426 
       
 37427 .controller('TabsetController', ['$scope', function TabsetCtrl($scope) {
       
 37428   var ctrl = this,
       
 37429       tabs = ctrl.tabs = $scope.tabs = [];
       
 37430 
       
 37431   ctrl.select = function(selectedTab) {
       
 37432     angular.forEach(tabs, function(tab) {
       
 37433       if (tab.active && tab !== selectedTab) {
       
 37434         tab.active = false;
       
 37435         tab.onDeselect();
       
 37436       }
       
 37437     });
       
 37438     selectedTab.active = true;
       
 37439     selectedTab.onSelect();
       
 37440   };
       
 37441 
       
 37442   ctrl.addTab = function addTab(tab) {
       
 37443     tabs.push(tab);
       
 37444     // we can't run the select function on the first tab
       
 37445     // since that would select it twice
       
 37446     if (tabs.length === 1) {
       
 37447       tab.active = true;
       
 37448     } else if (tab.active) {
       
 37449       ctrl.select(tab);
       
 37450     }
       
 37451   };
       
 37452 
       
 37453   ctrl.removeTab = function removeTab(tab) {
       
 37454     var index = tabs.indexOf(tab);
       
 37455     //Select a new tab if the tab to be removed is selected
       
 37456     if (tab.active && tabs.length > 1) {
       
 37457       //If this is the last tab, select the previous tab. else, the next tab.
       
 37458       var newActiveIndex = index == tabs.length - 1 ? index - 1 : index + 1;
       
 37459       ctrl.select(tabs[newActiveIndex]);
       
 37460     }
       
 37461     tabs.splice(index, 1);
       
 37462   };
       
 37463 }])
       
 37464 
       
 37465 /**
       
 37466  * @ngdoc directive
       
 37467  * @name ui.bootstrap.tabs.directive:tabset
       
 37468  * @restrict EA
       
 37469  *
       
 37470  * @description
       
 37471  * Tabset is the outer container for the tabs directive
       
 37472  *
       
 37473  * @param {boolean=} vertical Whether or not to use vertical styling for the tabs.
       
 37474  * @param {boolean=} justified Whether or not to use justified styling for the tabs.
       
 37475  *
       
 37476  * @example
       
 37477 <example module="ui.bootstrap">
       
 37478   <file name="index.html">
       
 37479     <tabset>
       
 37480       <tab heading="Tab 1"><b>First</b> Content!</tab>
       
 37481       <tab heading="Tab 2"><i>Second</i> Content!</tab>
       
 37482     </tabset>
       
 37483     <hr />
       
 37484     <tabset vertical="true">
       
 37485       <tab heading="Vertical Tab 1"><b>First</b> Vertical Content!</tab>
       
 37486       <tab heading="Vertical Tab 2"><i>Second</i> Vertical Content!</tab>
       
 37487     </tabset>
       
 37488     <tabset justified="true">
       
 37489       <tab heading="Justified Tab 1"><b>First</b> Justified Content!</tab>
       
 37490       <tab heading="Justified Tab 2"><i>Second</i> Justified Content!</tab>
       
 37491     </tabset>
       
 37492   </file>
       
 37493 </example>
       
 37494  */
       
 37495 .directive('tabset', function() {
       
 37496   return {
       
 37497     restrict: 'EA',
       
 37498     transclude: true,
       
 37499     replace: true,
       
 37500     scope: {
       
 37501       type: '@'
       
 37502     },
       
 37503     controller: 'TabsetController',
       
 37504     templateUrl: 'template/tabs/tabset.html',
       
 37505     link: function(scope, element, attrs) {
       
 37506       scope.vertical = angular.isDefined(attrs.vertical) ? scope.$parent.$eval(attrs.vertical) : false;
       
 37507       scope.justified = angular.isDefined(attrs.justified) ? scope.$parent.$eval(attrs.justified) : false;
       
 37508     }
       
 37509   };
       
 37510 })
       
 37511 
       
 37512 /**
       
 37513  * @ngdoc directive
       
 37514  * @name ui.bootstrap.tabs.directive:tab
       
 37515  * @restrict EA
       
 37516  *
       
 37517  * @param {string=} heading The visible heading, or title, of the tab. Set HTML headings with {@link ui.bootstrap.tabs.directive:tabHeading tabHeading}.
       
 37518  * @param {string=} select An expression to evaluate when the tab is selected.
       
 37519  * @param {boolean=} active A binding, telling whether or not this tab is selected.
       
 37520  * @param {boolean=} disabled A binding, telling whether or not this tab is disabled.
       
 37521  *
       
 37522  * @description
       
 37523  * Creates a tab with a heading and content. Must be placed within a {@link ui.bootstrap.tabs.directive:tabset tabset}.
       
 37524  *
       
 37525  * @example
       
 37526 <example module="ui.bootstrap">
       
 37527   <file name="index.html">
       
 37528     <div ng-controller="TabsDemoCtrl">
       
 37529       <button class="btn btn-small" ng-click="items[0].active = true">
       
 37530         Select item 1, using active binding
       
 37531       </button>
       
 37532       <button class="btn btn-small" ng-click="items[1].disabled = !items[1].disabled">
       
 37533         Enable/disable item 2, using disabled binding
       
 37534       </button>
       
 37535       <br />
       
 37536       <tabset>
       
 37537         <tab heading="Tab 1">First Tab</tab>
       
 37538         <tab select="alertMe()">
       
 37539           <tab-heading><i class="icon-bell"></i> Alert me!</tab-heading>
       
 37540           Second Tab, with alert callback and html heading!
       
 37541         </tab>
       
 37542         <tab ng-repeat="item in items"
       
 37543           heading="{{item.title}}"
       
 37544           disabled="item.disabled"
       
 37545           active="item.active">
       
 37546           {{item.content}}
       
 37547         </tab>
       
 37548       </tabset>
       
 37549     </div>
       
 37550   </file>
       
 37551   <file name="script.js">
       
 37552     function TabsDemoCtrl($scope) {
       
 37553       $scope.items = [
       
 37554         { title:"Dynamic Title 1", content:"Dynamic Item 0" },
       
 37555         { title:"Dynamic Title 2", content:"Dynamic Item 1", disabled: true }
       
 37556       ];
       
 37557 
       
 37558       $scope.alertMe = function() {
       
 37559         setTimeout(function() {
       
 37560           alert("You've selected the alert tab!");
       
 37561         });
       
 37562       };
       
 37563     };
       
 37564   </file>
       
 37565 </example>
       
 37566  */
       
 37567 
       
 37568 /**
       
 37569  * @ngdoc directive
       
 37570  * @name ui.bootstrap.tabs.directive:tabHeading
       
 37571  * @restrict EA
       
 37572  *
       
 37573  * @description
       
 37574  * Creates an HTML heading for a {@link ui.bootstrap.tabs.directive:tab tab}. Must be placed as a child of a tab element.
       
 37575  *
       
 37576  * @example
       
 37577 <example module="ui.bootstrap">
       
 37578   <file name="index.html">
       
 37579     <tabset>
       
 37580       <tab>
       
 37581         <tab-heading><b>HTML</b> in my titles?!</tab-heading>
       
 37582         And some content, too!
       
 37583       </tab>
       
 37584       <tab>
       
 37585         <tab-heading><i class="icon-heart"></i> Icon heading?!?</tab-heading>
       
 37586         That's right.
       
 37587       </tab>
       
 37588     </tabset>
       
 37589   </file>
       
 37590 </example>
       
 37591  */
       
 37592 .directive('tab', ['$parse', function($parse) {
       
 37593   return {
       
 37594     require: '^tabset',
       
 37595     restrict: 'EA',
       
 37596     replace: true,
       
 37597     templateUrl: 'template/tabs/tab.html',
       
 37598     transclude: true,
       
 37599     scope: {
       
 37600       active: '=?',
       
 37601       heading: '@',
       
 37602       onSelect: '&select', //This callback is called in contentHeadingTransclude
       
 37603                           //once it inserts the tab's content into the dom
       
 37604       onDeselect: '&deselect'
       
 37605     },
       
 37606     controller: function() {
       
 37607       //Empty controller so other directives can require being 'under' a tab
       
 37608     },
       
 37609     compile: function(elm, attrs, transclude) {
       
 37610       return function postLink(scope, elm, attrs, tabsetCtrl) {
       
 37611         scope.$watch('active', function(active) {
       
 37612           if (active) {
       
 37613             tabsetCtrl.select(scope);
       
 37614           }
       
 37615         });
       
 37616 
       
 37617         scope.disabled = false;
       
 37618         if ( attrs.disabled ) {
       
 37619           scope.$parent.$watch($parse(attrs.disabled), function(value) {
       
 37620             scope.disabled = !! value;
       
 37621           });
       
 37622         }
       
 37623 
       
 37624         scope.select = function() {
       
 37625           if ( !scope.disabled ) {
       
 37626             scope.active = true;
       
 37627           }
       
 37628         };
       
 37629 
       
 37630         tabsetCtrl.addTab(scope);
       
 37631         scope.$on('$destroy', function() {
       
 37632           tabsetCtrl.removeTab(scope);
       
 37633         });
       
 37634 
       
 37635         //We need to transclude later, once the content container is ready.
       
 37636         //when this link happens, we're inside a tab heading.
       
 37637         scope.$transcludeFn = transclude;
       
 37638       };
       
 37639     }
       
 37640   };
       
 37641 }])
       
 37642 
       
 37643 .directive('tabHeadingTransclude', [function() {
       
 37644   return {
       
 37645     restrict: 'A',
       
 37646     require: '^tab',
       
 37647     link: function(scope, elm, attrs, tabCtrl) {
       
 37648       scope.$watch('headingElement', function updateHeadingElement(heading) {
       
 37649         if (heading) {
       
 37650           elm.html('');
       
 37651           elm.append(heading);
       
 37652         }
       
 37653       });
       
 37654     }
       
 37655   };
       
 37656 }])
       
 37657 
       
 37658 .directive('tabContentTransclude', function() {
       
 37659   return {
       
 37660     restrict: 'A',
       
 37661     require: '^tabset',
       
 37662     link: function(scope, elm, attrs) {
       
 37663       var tab = scope.$eval(attrs.tabContentTransclude);
       
 37664 
       
 37665       //Now our tab is ready to be transcluded: both the tab heading area
       
 37666       //and the tab content area are loaded.  Transclude 'em both.
       
 37667       tab.$transcludeFn(tab.$parent, function(contents) {
       
 37668         angular.forEach(contents, function(node) {
       
 37669           if (isTabHeading(node)) {
       
 37670             //Let tabHeadingTransclude know.
       
 37671             tab.headingElement = node;
       
 37672           } else {
       
 37673             elm.append(node);
       
 37674           }
       
 37675         });
       
 37676       });
       
 37677     }
       
 37678   };
       
 37679   function isTabHeading(node) {
       
 37680     return node.tagName &&  (
       
 37681       node.hasAttribute('tab-heading') ||
       
 37682       node.hasAttribute('data-tab-heading') ||
       
 37683       node.tagName.toLowerCase() === 'tab-heading' ||
       
 37684       node.tagName.toLowerCase() === 'data-tab-heading'
       
 37685     );
       
 37686   }
       
 37687 })
       
 37688 
       
 37689 ;
       
 37690 
       
 37691 angular.module('ui.bootstrap.timepicker', [])
       
 37692 
       
 37693 .constant('timepickerConfig', {
       
 37694   hourStep: 1,
       
 37695   minuteStep: 1,
       
 37696   showMeridian: true,
       
 37697   meridians: null,
       
 37698   readonlyInput: false,
       
 37699   mousewheel: true
       
 37700 })
       
 37701 
       
 37702 .controller('TimepickerController', ['$scope', '$attrs', '$parse', '$log', '$locale', 'timepickerConfig', function($scope, $attrs, $parse, $log, $locale, timepickerConfig) {
       
 37703   var selected = new Date(),
       
 37704       ngModelCtrl = { $setViewValue: angular.noop }, // nullModelCtrl
       
 37705       meridians = angular.isDefined($attrs.meridians) ? $scope.$parent.$eval($attrs.meridians) : timepickerConfig.meridians || $locale.DATETIME_FORMATS.AMPMS;
       
 37706 
       
 37707   this.init = function( ngModelCtrl_, inputs ) {
       
 37708     ngModelCtrl = ngModelCtrl_;
       
 37709     ngModelCtrl.$render = this.render;
       
 37710 
       
 37711     var hoursInputEl = inputs.eq(0),
       
 37712         minutesInputEl = inputs.eq(1);
       
 37713 
       
 37714     var mousewheel = angular.isDefined($attrs.mousewheel) ? $scope.$parent.$eval($attrs.mousewheel) : timepickerConfig.mousewheel;
       
 37715     if ( mousewheel ) {
       
 37716       this.setupMousewheelEvents( hoursInputEl, minutesInputEl );
       
 37717     }
       
 37718 
       
 37719     $scope.readonlyInput = angular.isDefined($attrs.readonlyInput) ? $scope.$parent.$eval($attrs.readonlyInput) : timepickerConfig.readonlyInput;
       
 37720     this.setupInputEvents( hoursInputEl, minutesInputEl );
       
 37721   };
       
 37722 
       
 37723   var hourStep = timepickerConfig.hourStep;
       
 37724   if ($attrs.hourStep) {
       
 37725     $scope.$parent.$watch($parse($attrs.hourStep), function(value) {
       
 37726       hourStep = parseInt(value, 10);
       
 37727     });
       
 37728   }
       
 37729 
       
 37730   var minuteStep = timepickerConfig.minuteStep;
       
 37731   if ($attrs.minuteStep) {
       
 37732     $scope.$parent.$watch($parse($attrs.minuteStep), function(value) {
       
 37733       minuteStep = parseInt(value, 10);
       
 37734     });
       
 37735   }
       
 37736 
       
 37737   // 12H / 24H mode
       
 37738   $scope.showMeridian = timepickerConfig.showMeridian;
       
 37739   if ($attrs.showMeridian) {
       
 37740     $scope.$parent.$watch($parse($attrs.showMeridian), function(value) {
       
 37741       $scope.showMeridian = !!value;
       
 37742 
       
 37743       if ( ngModelCtrl.$error.time ) {
       
 37744         // Evaluate from template
       
 37745         var hours = getHoursFromTemplate(), minutes = getMinutesFromTemplate();
       
 37746         if (angular.isDefined( hours ) && angular.isDefined( minutes )) {
       
 37747           selected.setHours( hours );
       
 37748           refresh();
       
 37749         }
       
 37750       } else {
       
 37751         updateTemplate();
       
 37752       }
       
 37753     });
       
 37754   }
       
 37755 
       
 37756   // Get $scope.hours in 24H mode if valid
       
 37757   function getHoursFromTemplate ( ) {
       
 37758     var hours = parseInt( $scope.hours, 10 );
       
 37759     var valid = ( $scope.showMeridian ) ? (hours > 0 && hours < 13) : (hours >= 0 && hours < 24);
       
 37760     if ( !valid ) {
       
 37761       return undefined;
       
 37762     }
       
 37763 
       
 37764     if ( $scope.showMeridian ) {
       
 37765       if ( hours === 12 ) {
       
 37766         hours = 0;
       
 37767       }
       
 37768       if ( $scope.meridian === meridians[1] ) {
       
 37769         hours = hours + 12;
       
 37770       }
       
 37771     }
       
 37772     return hours;
       
 37773   }
       
 37774 
       
 37775   function getMinutesFromTemplate() {
       
 37776     var minutes = parseInt($scope.minutes, 10);
       
 37777     return ( minutes >= 0 && minutes < 60 ) ? minutes : undefined;
       
 37778   }
       
 37779 
       
 37780   function pad( value ) {
       
 37781     return ( angular.isDefined(value) && value.toString().length < 2 ) ? '0' + value : value;
       
 37782   }
       
 37783 
       
 37784   // Respond on mousewheel spin
       
 37785   this.setupMousewheelEvents = function( hoursInputEl, minutesInputEl ) {
       
 37786     var isScrollingUp = function(e) {
       
 37787       if (e.originalEvent) {
       
 37788         e = e.originalEvent;
       
 37789       }
       
 37790       //pick correct delta variable depending on event
       
 37791       var delta = (e.wheelDelta) ? e.wheelDelta : -e.deltaY;
       
 37792       return (e.detail || delta > 0);
       
 37793     };
       
 37794 
       
 37795     hoursInputEl.bind('mousewheel wheel', function(e) {
       
 37796       $scope.$apply( (isScrollingUp(e)) ? $scope.incrementHours() : $scope.decrementHours() );
       
 37797       e.preventDefault();
       
 37798     });
       
 37799 
       
 37800     minutesInputEl.bind('mousewheel wheel', function(e) {
       
 37801       $scope.$apply( (isScrollingUp(e)) ? $scope.incrementMinutes() : $scope.decrementMinutes() );
       
 37802       e.preventDefault();
       
 37803     });
       
 37804 
       
 37805   };
       
 37806 
       
 37807   this.setupInputEvents = function( hoursInputEl, minutesInputEl ) {
       
 37808     if ( $scope.readonlyInput ) {
       
 37809       $scope.updateHours = angular.noop;
       
 37810       $scope.updateMinutes = angular.noop;
       
 37811       return;
       
 37812     }
       
 37813 
       
 37814     var invalidate = function(invalidHours, invalidMinutes) {
       
 37815       ngModelCtrl.$setViewValue( null );
       
 37816       ngModelCtrl.$setValidity('time', false);
       
 37817       if (angular.isDefined(invalidHours)) {
       
 37818         $scope.invalidHours = invalidHours;
       
 37819       }
       
 37820       if (angular.isDefined(invalidMinutes)) {
       
 37821         $scope.invalidMinutes = invalidMinutes;
       
 37822       }
       
 37823     };
       
 37824 
       
 37825     $scope.updateHours = function() {
       
 37826       var hours = getHoursFromTemplate();
       
 37827 
       
 37828       if ( angular.isDefined(hours) ) {
       
 37829         selected.setHours( hours );
       
 37830         refresh( 'h' );
       
 37831       } else {
       
 37832         invalidate(true);
       
 37833       }
       
 37834     };
       
 37835 
       
 37836     hoursInputEl.bind('blur', function(e) {
       
 37837       if ( !$scope.invalidHours && $scope.hours < 10) {
       
 37838         $scope.$apply( function() {
       
 37839           $scope.hours = pad( $scope.hours );
       
 37840         });
       
 37841       }
       
 37842     });
       
 37843 
       
 37844     $scope.updateMinutes = function() {
       
 37845       var minutes = getMinutesFromTemplate();
       
 37846 
       
 37847       if ( angular.isDefined(minutes) ) {
       
 37848         selected.setMinutes( minutes );
       
 37849         refresh( 'm' );
       
 37850       } else {
       
 37851         invalidate(undefined, true);
       
 37852       }
       
 37853     };
       
 37854 
       
 37855     minutesInputEl.bind('blur', function(e) {
       
 37856       if ( !$scope.invalidMinutes && $scope.minutes < 10 ) {
       
 37857         $scope.$apply( function() {
       
 37858           $scope.minutes = pad( $scope.minutes );
       
 37859         });
       
 37860       }
       
 37861     });
       
 37862 
       
 37863   };
       
 37864 
       
 37865   this.render = function() {
       
 37866     var date = ngModelCtrl.$modelValue ? new Date( ngModelCtrl.$modelValue ) : null;
       
 37867 
       
 37868     if ( isNaN(date) ) {
       
 37869       ngModelCtrl.$setValidity('time', false);
       
 37870       $log.error('Timepicker directive: "ng-model" value must be a Date object, a number of milliseconds since 01.01.1970 or a string representing an RFC2822 or ISO 8601 date.');
       
 37871     } else {
       
 37872       if ( date ) {
       
 37873         selected = date;
       
 37874       }
       
 37875       makeValid();
       
 37876       updateTemplate();
       
 37877     }
       
 37878   };
       
 37879 
       
 37880   // Call internally when we know that model is valid.
       
 37881   function refresh( keyboardChange ) {
       
 37882     makeValid();
       
 37883     ngModelCtrl.$setViewValue( new Date(selected) );
       
 37884     updateTemplate( keyboardChange );
       
 37885   }
       
 37886 
       
 37887   function makeValid() {
       
 37888     ngModelCtrl.$setValidity('time', true);
       
 37889     $scope.invalidHours = false;
       
 37890     $scope.invalidMinutes = false;
       
 37891   }
       
 37892 
       
 37893   function updateTemplate( keyboardChange ) {
       
 37894     var hours = selected.getHours(), minutes = selected.getMinutes();
       
 37895 
       
 37896     if ( $scope.showMeridian ) {
       
 37897       hours = ( hours === 0 || hours === 12 ) ? 12 : hours % 12; // Convert 24 to 12 hour system
       
 37898     }
       
 37899 
       
 37900     $scope.hours = keyboardChange === 'h' ? hours : pad(hours);
       
 37901     $scope.minutes = keyboardChange === 'm' ? minutes : pad(minutes);
       
 37902     $scope.meridian = selected.getHours() < 12 ? meridians[0] : meridians[1];
       
 37903   }
       
 37904 
       
 37905   function addMinutes( minutes ) {
       
 37906     var dt = new Date( selected.getTime() + minutes * 60000 );
       
 37907     selected.setHours( dt.getHours(), dt.getMinutes() );
       
 37908     refresh();
       
 37909   }
       
 37910 
       
 37911   $scope.incrementHours = function() {
       
 37912     addMinutes( hourStep * 60 );
       
 37913   };
       
 37914   $scope.decrementHours = function() {
       
 37915     addMinutes( - hourStep * 60 );
       
 37916   };
       
 37917   $scope.incrementMinutes = function() {
       
 37918     addMinutes( minuteStep );
       
 37919   };
       
 37920   $scope.decrementMinutes = function() {
       
 37921     addMinutes( - minuteStep );
       
 37922   };
       
 37923   $scope.toggleMeridian = function() {
       
 37924     addMinutes( 12 * 60 * (( selected.getHours() < 12 ) ? 1 : -1) );
       
 37925   };
       
 37926 }])
       
 37927 
       
 37928 .directive('timepicker', function () {
       
 37929   return {
       
 37930     restrict: 'EA',
       
 37931     require: ['timepicker', '?^ngModel'],
       
 37932     controller:'TimepickerController',
       
 37933     replace: true,
       
 37934     scope: {},
       
 37935     templateUrl: 'template/timepicker/timepicker.html',
       
 37936     link: function(scope, element, attrs, ctrls) {
       
 37937       var timepickerCtrl = ctrls[0], ngModelCtrl = ctrls[1];
       
 37938 
       
 37939       if ( ngModelCtrl ) {
       
 37940         timepickerCtrl.init( ngModelCtrl, element.find('input') );
       
 37941       }
       
 37942     }
       
 37943   };
       
 37944 });
       
 37945 
       
 37946 angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position', 'ui.bootstrap.bindHtml'])
       
 37947 
       
 37948 /**
       
 37949  * A helper service that can parse typeahead's syntax (string provided by users)
       
 37950  * Extracted to a separate service for ease of unit testing
       
 37951  */
       
 37952   .factory('typeaheadParser', ['$parse', function ($parse) {
       
 37953 
       
 37954   //                      00000111000000000000022200000000000000003333333333333330000000000044000
       
 37955   var TYPEAHEAD_REGEXP = /^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w\d]*))\s+in\s+([\s\S]+?)$/;
       
 37956 
       
 37957   return {
       
 37958     parse:function (input) {
       
 37959 
       
 37960       var match = input.match(TYPEAHEAD_REGEXP);
       
 37961       if (!match) {
       
 37962         throw new Error(
       
 37963           'Expected typeahead specification in form of "_modelValue_ (as _label_)? for _item_ in _collection_"' +
       
 37964             ' but got "' + input + '".');
       
 37965       }
       
 37966 
       
 37967       return {
       
 37968         itemName:match[3],
       
 37969         source:$parse(match[4]),
       
 37970         viewMapper:$parse(match[2] || match[1]),
       
 37971         modelMapper:$parse(match[1])
       
 37972       };
       
 37973     }
       
 37974   };
       
 37975 }])
       
 37976 
       
 37977   .directive('typeahead', ['$compile', '$parse', '$q', '$timeout', '$document', '$position', 'typeaheadParser',
       
 37978     function ($compile, $parse, $q, $timeout, $document, $position, typeaheadParser) {
       
 37979 
       
 37980   var HOT_KEYS = [9, 13, 27, 38, 40];
       
 37981 
       
 37982   return {
       
 37983     require:'ngModel',
       
 37984     link:function (originalScope, element, attrs, modelCtrl) {
       
 37985 
       
 37986       //SUPPORTED ATTRIBUTES (OPTIONS)
       
 37987 
       
 37988       //minimal no of characters that needs to be entered before typeahead kicks-in
       
 37989       var minSearch = originalScope.$eval(attrs.typeaheadMinLength) || 1;
       
 37990 
       
 37991       //minimal wait time after last character typed before typehead kicks-in
       
 37992       var waitTime = originalScope.$eval(attrs.typeaheadWaitMs) || 0;
       
 37993 
       
 37994       //should it restrict model values to the ones selected from the popup only?
       
 37995       var isEditable = originalScope.$eval(attrs.typeaheadEditable) !== false;
       
 37996 
       
 37997       //binding to a variable that indicates if matches are being retrieved asynchronously
       
 37998       var isLoadingSetter = $parse(attrs.typeaheadLoading).assign || angular.noop;
       
 37999 
       
 38000       //a callback executed when a match is selected
       
 38001       var onSelectCallback = $parse(attrs.typeaheadOnSelect);
       
 38002 
       
 38003       var inputFormatter = attrs.typeaheadInputFormatter ? $parse(attrs.typeaheadInputFormatter) : undefined;
       
 38004 
       
 38005       var appendToBody =  attrs.typeaheadAppendToBody ? originalScope.$eval(attrs.typeaheadAppendToBody) : false;
       
 38006 
       
 38007       //INTERNAL VARIABLES
       
 38008 
       
 38009       //model setter executed upon match selection
       
 38010       var $setModelValue = $parse(attrs.ngModel).assign;
       
 38011 
       
 38012       //expressions used by typeahead
       
 38013       var parserResult = typeaheadParser.parse(attrs.typeahead);
       
 38014 
       
 38015       var hasFocus;
       
 38016 
       
 38017       //create a child scope for the typeahead directive so we are not polluting original scope
       
 38018       //with typeahead-specific data (matches, query etc.)
       
 38019       var scope = originalScope.$new();
       
 38020       originalScope.$on('$destroy', function(){
       
 38021         scope.$destroy();
       
 38022       });
       
 38023 
       
 38024       // WAI-ARIA
       
 38025       var popupId = 'typeahead-' + scope.$id + '-' + Math.floor(Math.random() * 10000);
       
 38026       element.attr({
       
 38027         'aria-autocomplete': 'list',
       
 38028         'aria-expanded': false,
       
 38029         'aria-owns': popupId
       
 38030       });
       
 38031 
       
 38032       //pop-up element used to display matches
       
 38033       var popUpEl = angular.element('<div typeahead-popup></div>');
       
 38034       popUpEl.attr({
       
 38035         id: popupId,
       
 38036         matches: 'matches',
       
 38037         active: 'activeIdx',
       
 38038         select: 'select(activeIdx)',
       
 38039         query: 'query',
       
 38040         position: 'position'
       
 38041       });
       
 38042       //custom item template
       
 38043       if (angular.isDefined(attrs.typeaheadTemplateUrl)) {
       
 38044         popUpEl.attr('template-url', attrs.typeaheadTemplateUrl);
       
 38045       }
       
 38046 
       
 38047       var resetMatches = function() {
       
 38048         scope.matches = [];
       
 38049         scope.activeIdx = -1;
       
 38050         element.attr('aria-expanded', false);
       
 38051       };
       
 38052 
       
 38053       var getMatchId = function(index) {
       
 38054         return popupId + '-option-' + index;
       
 38055       };
       
 38056 
       
 38057       // Indicate that the specified match is the active (pre-selected) item in the list owned by this typeahead.
       
 38058       // This attribute is added or removed automatically when the `activeIdx` changes.
       
 38059       scope.$watch('activeIdx', function(index) {
       
 38060         if (index < 0) {
       
 38061           element.removeAttr('aria-activedescendant');
       
 38062         } else {
       
 38063           element.attr('aria-activedescendant', getMatchId(index));
       
 38064         }
       
 38065       });
       
 38066 
       
 38067       var getMatchesAsync = function(inputValue) {
       
 38068 
       
 38069         var locals = {$viewValue: inputValue};
       
 38070         isLoadingSetter(originalScope, true);
       
 38071         $q.when(parserResult.source(originalScope, locals)).then(function(matches) {
       
 38072 
       
 38073           //it might happen that several async queries were in progress if a user were typing fast
       
 38074           //but we are interested only in responses that correspond to the current view value
       
 38075           var onCurrentRequest = (inputValue === modelCtrl.$viewValue);
       
 38076           if (onCurrentRequest && hasFocus) {
       
 38077             if (matches.length > 0) {
       
 38078 
       
 38079               scope.activeIdx = 0;
       
 38080               scope.matches.length = 0;
       
 38081 
       
 38082               //transform labels
       
 38083               for(var i=0; i<matches.length; i++) {
       
 38084                 locals[parserResult.itemName] = matches[i];
       
 38085                 scope.matches.push({
       
 38086                   id: getMatchId(i),
       
 38087                   label: parserResult.viewMapper(scope, locals),
       
 38088                   model: matches[i]
       
 38089                 });
       
 38090               }
       
 38091 
       
 38092               scope.query = inputValue;
       
 38093               //position pop-up with matches - we need to re-calculate its position each time we are opening a window
       
 38094               //with matches as a pop-up might be absolute-positioned and position of an input might have changed on a page
       
 38095               //due to other elements being rendered
       
 38096               scope.position = appendToBody ? $position.offset(element) : $position.position(element);
       
 38097               scope.position.top = scope.position.top + element.prop('offsetHeight');
       
 38098 
       
 38099               element.attr('aria-expanded', true);
       
 38100             } else {
       
 38101               resetMatches();
       
 38102             }
       
 38103           }
       
 38104           if (onCurrentRequest) {
       
 38105             isLoadingSetter(originalScope, false);
       
 38106           }
       
 38107         }, function(){
       
 38108           resetMatches();
       
 38109           isLoadingSetter(originalScope, false);
       
 38110         });
       
 38111       };
       
 38112 
       
 38113       resetMatches();
       
 38114 
       
 38115       //we need to propagate user's query so we can higlight matches
       
 38116       scope.query = undefined;
       
 38117 
       
 38118       //Declare the timeout promise var outside the function scope so that stacked calls can be cancelled later 
       
 38119       var timeoutPromise;
       
 38120 
       
 38121       var scheduleSearchWithTimeout = function(inputValue) {
       
 38122         timeoutPromise = $timeout(function () {
       
 38123           getMatchesAsync(inputValue);
       
 38124         }, waitTime);
       
 38125       };
       
 38126 
       
 38127       var cancelPreviousTimeout = function() {
       
 38128         if (timeoutPromise) {
       
 38129           $timeout.cancel(timeoutPromise);
       
 38130         }
       
 38131       };
       
 38132 
       
 38133       //plug into $parsers pipeline to open a typeahead on view changes initiated from DOM
       
 38134       //$parsers kick-in on all the changes coming from the view as well as manually triggered by $setViewValue
       
 38135       modelCtrl.$parsers.unshift(function (inputValue) {
       
 38136 
       
 38137         hasFocus = true;
       
 38138 
       
 38139         if (inputValue && inputValue.length >= minSearch) {
       
 38140           if (waitTime > 0) {
       
 38141             cancelPreviousTimeout();
       
 38142             scheduleSearchWithTimeout(inputValue);
       
 38143           } else {
       
 38144             getMatchesAsync(inputValue);
       
 38145           }
       
 38146         } else {
       
 38147           isLoadingSetter(originalScope, false);
       
 38148           cancelPreviousTimeout();
       
 38149           resetMatches();
       
 38150         }
       
 38151 
       
 38152         if (isEditable) {
       
 38153           return inputValue;
       
 38154         } else {
       
 38155           if (!inputValue) {
       
 38156             // Reset in case user had typed something previously.
       
 38157             modelCtrl.$setValidity('editable', true);
       
 38158             return inputValue;
       
 38159           } else {
       
 38160             modelCtrl.$setValidity('editable', false);
       
 38161             return undefined;
       
 38162           }
       
 38163         }
       
 38164       });
       
 38165 
       
 38166       modelCtrl.$formatters.push(function (modelValue) {
       
 38167 
       
 38168         var candidateViewValue, emptyViewValue;
       
 38169         var locals = {};
       
 38170 
       
 38171         if (inputFormatter) {
       
 38172 
       
 38173           locals['$model'] = modelValue;
       
 38174           return inputFormatter(originalScope, locals);
       
 38175 
       
 38176         } else {
       
 38177 
       
 38178           //it might happen that we don't have enough info to properly render input value
       
 38179           //we need to check for this situation and simply return model value if we can't apply custom formatting
       
 38180           locals[parserResult.itemName] = modelValue;
       
 38181           candidateViewValue = parserResult.viewMapper(originalScope, locals);
       
 38182           locals[parserResult.itemName] = undefined;
       
 38183           emptyViewValue = parserResult.viewMapper(originalScope, locals);
       
 38184 
       
 38185           return candidateViewValue!== emptyViewValue ? candidateViewValue : modelValue;
       
 38186         }
       
 38187       });
       
 38188 
       
 38189       scope.select = function (activeIdx) {
       
 38190         //called from within the $digest() cycle
       
 38191         var locals = {};
       
 38192         var model, item;
       
 38193 
       
 38194         locals[parserResult.itemName] = item = scope.matches[activeIdx].model;
       
 38195         model = parserResult.modelMapper(originalScope, locals);
       
 38196         $setModelValue(originalScope, model);
       
 38197         modelCtrl.$setValidity('editable', true);
       
 38198 
       
 38199         onSelectCallback(originalScope, {
       
 38200           $item: item,
       
 38201           $model: model,
       
 38202           $label: parserResult.viewMapper(originalScope, locals)
       
 38203         });
       
 38204 
       
 38205         resetMatches();
       
 38206 
       
 38207         //return focus to the input element if a match was selected via a mouse click event
       
 38208         // use timeout to avoid $rootScope:inprog error
       
 38209         $timeout(function() { element[0].focus(); }, 0, false);
       
 38210       };
       
 38211 
       
 38212       //bind keyboard events: arrows up(38) / down(40), enter(13) and tab(9), esc(27)
       
 38213       element.bind('keydown', function (evt) {
       
 38214 
       
 38215         //typeahead is open and an "interesting" key was pressed
       
 38216         if (scope.matches.length === 0 || HOT_KEYS.indexOf(evt.which) === -1) {
       
 38217           return;
       
 38218         }
       
 38219 
       
 38220         evt.preventDefault();
       
 38221 
       
 38222         if (evt.which === 40) {
       
 38223           scope.activeIdx = (scope.activeIdx + 1) % scope.matches.length;
       
 38224           scope.$digest();
       
 38225 
       
 38226         } else if (evt.which === 38) {
       
 38227           scope.activeIdx = (scope.activeIdx ? scope.activeIdx : scope.matches.length) - 1;
       
 38228           scope.$digest();
       
 38229 
       
 38230         } else if (evt.which === 13 || evt.which === 9) {
       
 38231           scope.$apply(function () {
       
 38232             scope.select(scope.activeIdx);
       
 38233           });
       
 38234 
       
 38235         } else if (evt.which === 27) {
       
 38236           evt.stopPropagation();
       
 38237 
       
 38238           resetMatches();
       
 38239           scope.$digest();
       
 38240         }
       
 38241       });
       
 38242 
       
 38243       element.bind('blur', function (evt) {
       
 38244         hasFocus = false;
       
 38245       });
       
 38246 
       
 38247       // Keep reference to click handler to unbind it.
       
 38248       var dismissClickHandler = function (evt) {
       
 38249         if (element[0] !== evt.target) {
       
 38250           resetMatches();
       
 38251           scope.$digest();
       
 38252         }
       
 38253       };
       
 38254 
       
 38255       $document.bind('click', dismissClickHandler);
       
 38256 
       
 38257       originalScope.$on('$destroy', function(){
       
 38258         $document.unbind('click', dismissClickHandler);
       
 38259       });
       
 38260 
       
 38261       var $popup = $compile(popUpEl)(scope);
       
 38262       if ( appendToBody ) {
       
 38263         $document.find('body').append($popup);
       
 38264       } else {
       
 38265         element.after($popup);
       
 38266       }
       
 38267     }
       
 38268   };
       
 38269 
       
 38270 }])
       
 38271 
       
 38272   .directive('typeaheadPopup', function () {
       
 38273     return {
       
 38274       restrict:'EA',
       
 38275       scope:{
       
 38276         matches:'=',
       
 38277         query:'=',
       
 38278         active:'=',
       
 38279         position:'=',
       
 38280         select:'&'
       
 38281       },
       
 38282       replace:true,
       
 38283       templateUrl:'template/typeahead/typeahead-popup.html',
       
 38284       link:function (scope, element, attrs) {
       
 38285 
       
 38286         scope.templateUrl = attrs.templateUrl;
       
 38287 
       
 38288         scope.isOpen = function () {
       
 38289           return scope.matches.length > 0;
       
 38290         };
       
 38291 
       
 38292         scope.isActive = function (matchIdx) {
       
 38293           return scope.active == matchIdx;
       
 38294         };
       
 38295 
       
 38296         scope.selectActive = function (matchIdx) {
       
 38297           scope.active = matchIdx;
       
 38298         };
       
 38299 
       
 38300         scope.selectMatch = function (activeIdx) {
       
 38301           scope.select({activeIdx:activeIdx});
       
 38302         };
       
 38303       }
       
 38304     };
       
 38305   })
       
 38306 
       
 38307   .directive('typeaheadMatch', ['$http', '$templateCache', '$compile', '$parse', function ($http, $templateCache, $compile, $parse) {
       
 38308     return {
       
 38309       restrict:'EA',
       
 38310       scope:{
       
 38311         index:'=',
       
 38312         match:'=',
       
 38313         query:'='
       
 38314       },
       
 38315       link:function (scope, element, attrs) {
       
 38316         var tplUrl = $parse(attrs.templateUrl)(scope.$parent) || 'template/typeahead/typeahead-match.html';
       
 38317         $http.get(tplUrl, {cache: $templateCache}).success(function(tplContent){
       
 38318            element.replaceWith($compile(tplContent.trim())(scope));
       
 38319         });
       
 38320       }
       
 38321     };
       
 38322   }])
       
 38323 
       
 38324   .filter('typeaheadHighlight', function() {
       
 38325 
       
 38326     function escapeRegexp(queryToEscape) {
       
 38327       return queryToEscape.replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1');
       
 38328     }
       
 38329 
       
 38330     return function(matchItem, query) {
       
 38331       return query ? ('' + matchItem).replace(new RegExp(escapeRegexp(query), 'gi'), '<strong>$&</strong>') : matchItem;
       
 38332     };
       
 38333   });
       
 38334 
       
 38335 angular.module("template/accordion/accordion-group.html", []).run(["$templateCache", function($templateCache) {
       
 38336   $templateCache.put("template/accordion/accordion-group.html",
       
 38337     "<div class=\"panel panel-default\">\n" +
       
 38338     "  <div class=\"panel-heading\">\n" +
       
 38339     "    <h4 class=\"panel-title\">\n" +
       
 38340     "      <a class=\"accordion-toggle\" ng-click=\"toggleOpen()\" accordion-transclude=\"heading\"><span ng-class=\"{'text-muted': isDisabled}\">{{heading}}</span></a>\n" +
       
 38341     "    </h4>\n" +
       
 38342     "  </div>\n" +
       
 38343     "  <div class=\"panel-collapse\" collapse=\"!isOpen\">\n" +
       
 38344     "	  <div class=\"panel-body\" ng-transclude></div>\n" +
       
 38345     "  </div>\n" +
       
 38346     "</div>");
       
 38347 }]);
       
 38348 
       
 38349 angular.module("template/accordion/accordion.html", []).run(["$templateCache", function($templateCache) {
       
 38350   $templateCache.put("template/accordion/accordion.html",
       
 38351     "<div class=\"panel-group\" ng-transclude></div>");
       
 38352 }]);
       
 38353 
       
 38354 angular.module("template/alert/alert.html", []).run(["$templateCache", function($templateCache) {
       
 38355   $templateCache.put("template/alert/alert.html",
       
 38356     "<div class=\"alert\" ng-class=\"['alert-' + (type || 'warning'), closeable ? 'alert-dismissable' : null]\" role=\"alert\">\n" +
       
 38357     "    <button ng-show=\"closeable\" type=\"button\" class=\"close\" ng-click=\"close()\">\n" +
       
 38358     "        <span aria-hidden=\"true\">&times;</span>\n" +
       
 38359     "        <span class=\"sr-only\">Close</span>\n" +
       
 38360     "    </button>\n" +
       
 38361     "    <div ng-transclude></div>\n" +
       
 38362     "</div>\n" +
       
 38363     "");
       
 38364 }]);
       
 38365 
       
 38366 angular.module("template/carousel/carousel.html", []).run(["$templateCache", function($templateCache) {
       
 38367   $templateCache.put("template/carousel/carousel.html",
       
 38368     "<div ng-mouseenter=\"pause()\" ng-mouseleave=\"play()\" class=\"carousel\" ng-swipe-right=\"prev()\" ng-swipe-left=\"next()\">\n" +
       
 38369     "    <ol class=\"carousel-indicators\" ng-show=\"slides.length > 1\">\n" +
       
 38370     "        <li ng-repeat=\"slide in slides track by $index\" ng-class=\"{active: isActive(slide)}\" ng-click=\"select(slide)\"></li>\n" +
       
 38371     "    </ol>\n" +
       
 38372     "    <div class=\"carousel-inner\" ng-transclude></div>\n" +
       
 38373     "    <a class=\"left carousel-control\" ng-click=\"prev()\" ng-show=\"slides.length > 1\"><span class=\"glyphicon glyphicon-chevron-left\"></span></a>\n" +
       
 38374     "    <a class=\"right carousel-control\" ng-click=\"next()\" ng-show=\"slides.length > 1\"><span class=\"glyphicon glyphicon-chevron-right\"></span></a>\n" +
       
 38375     "</div>\n" +
       
 38376     "");
       
 38377 }]);
       
 38378 
       
 38379 angular.module("template/carousel/slide.html", []).run(["$templateCache", function($templateCache) {
       
 38380   $templateCache.put("template/carousel/slide.html",
       
 38381     "<div ng-class=\"{\n" +
       
 38382     "    'active': leaving || (active && !entering),\n" +
       
 38383     "    'prev': (next || active) && direction=='prev',\n" +
       
 38384     "    'next': (next || active) && direction=='next',\n" +
       
 38385     "    'right': direction=='prev',\n" +
       
 38386     "    'left': direction=='next'\n" +
       
 38387     "  }\" class=\"item text-center\" ng-transclude></div>\n" +
       
 38388     "");
       
 38389 }]);
       
 38390 
       
 38391 angular.module("template/datepicker/datepicker.html", []).run(["$templateCache", function($templateCache) {
       
 38392   $templateCache.put("template/datepicker/datepicker.html",
       
 38393     "<div ng-switch=\"datepickerMode\" role=\"application\" ng-keydown=\"keydown($event)\">\n" +
       
 38394     "  <daypicker ng-switch-when=\"day\" tabindex=\"0\"></daypicker>\n" +
       
 38395     "  <monthpicker ng-switch-when=\"month\" tabindex=\"0\"></monthpicker>\n" +
       
 38396     "  <yearpicker ng-switch-when=\"year\" tabindex=\"0\"></yearpicker>\n" +
       
 38397     "</div>");
       
 38398 }]);
       
 38399 
       
 38400 angular.module("template/datepicker/day.html", []).run(["$templateCache", function($templateCache) {
       
 38401   $templateCache.put("template/datepicker/day.html",
       
 38402     "<table role=\"grid\" aria-labelledby=\"{{uniqueId}}-title\" aria-activedescendant=\"{{activeDateId}}\">\n" +
       
 38403     "  <thead>\n" +
       
 38404     "    <tr>\n" +
       
 38405     "      <th><button type=\"button\" class=\"btn btn-default btn-sm pull-left\" ng-click=\"move(-1)\" tabindex=\"-1\"><i class=\"glyphicon glyphicon-chevron-left\"></i></button></th>\n" +
       
 38406     "      <th colspan=\"{{5 + showWeeks}}\"><button id=\"{{uniqueId}}-title\" role=\"heading\" aria-live=\"assertive\" aria-atomic=\"true\" type=\"button\" class=\"btn btn-default btn-sm\" ng-click=\"toggleMode()\" tabindex=\"-1\" style=\"width:100%;\"><strong>{{title}}</strong></button></th>\n" +
       
 38407     "      <th><button type=\"button\" class=\"btn btn-default btn-sm pull-right\" ng-click=\"move(1)\" tabindex=\"-1\"><i class=\"glyphicon glyphicon-chevron-right\"></i></button></th>\n" +
       
 38408     "    </tr>\n" +
       
 38409     "    <tr>\n" +
       
 38410     "      <th ng-show=\"showWeeks\" class=\"text-center\"></th>\n" +
       
 38411     "      <th ng-repeat=\"label in labels track by $index\" class=\"text-center\"><small aria-label=\"{{label.full}}\">{{label.abbr}}</small></th>\n" +
       
 38412     "    </tr>\n" +
       
 38413     "  </thead>\n" +
       
 38414     "  <tbody>\n" +
       
 38415     "    <tr ng-repeat=\"row in rows track by $index\">\n" +
       
 38416     "      <td ng-show=\"showWeeks\" class=\"text-center h6\"><em>{{ weekNumbers[$index] }}</em></td>\n" +
       
 38417     "      <td ng-repeat=\"dt in row track by dt.date\" class=\"text-center\" role=\"gridcell\" id=\"{{dt.uid}}\" aria-disabled=\"{{!!dt.disabled}}\">\n" +
       
 38418     "        <button type=\"button\" style=\"width:100%;\" class=\"btn btn-default btn-sm\" ng-class=\"{'btn-info': dt.selected, active: isActive(dt)}\" ng-click=\"select(dt.date)\" ng-disabled=\"dt.disabled\" tabindex=\"-1\"><span ng-class=\"{'text-muted': dt.secondary, 'text-info': dt.current}\">{{dt.label}}</span></button>\n" +
       
 38419     "      </td>\n" +
       
 38420     "    </tr>\n" +
       
 38421     "  </tbody>\n" +
       
 38422     "</table>\n" +
       
 38423     "");
       
 38424 }]);
       
 38425 
       
 38426 angular.module("template/datepicker/month.html", []).run(["$templateCache", function($templateCache) {
       
 38427   $templateCache.put("template/datepicker/month.html",
       
 38428     "<table role=\"grid\" aria-labelledby=\"{{uniqueId}}-title\" aria-activedescendant=\"{{activeDateId}}\">\n" +
       
 38429     "  <thead>\n" +
       
 38430     "    <tr>\n" +
       
 38431     "      <th><button type=\"button\" class=\"btn btn-default btn-sm pull-left\" ng-click=\"move(-1)\" tabindex=\"-1\"><i class=\"glyphicon glyphicon-chevron-left\"></i></button></th>\n" +
       
 38432     "      <th><button id=\"{{uniqueId}}-title\" role=\"heading\" aria-live=\"assertive\" aria-atomic=\"true\" type=\"button\" class=\"btn btn-default btn-sm\" ng-click=\"toggleMode()\" tabindex=\"-1\" style=\"width:100%;\"><strong>{{title}}</strong></button></th>\n" +
       
 38433     "      <th><button type=\"button\" class=\"btn btn-default btn-sm pull-right\" ng-click=\"move(1)\" tabindex=\"-1\"><i class=\"glyphicon glyphicon-chevron-right\"></i></button></th>\n" +
       
 38434     "    </tr>\n" +
       
 38435     "  </thead>\n" +
       
 38436     "  <tbody>\n" +
       
 38437     "    <tr ng-repeat=\"row in rows track by $index\">\n" +
       
 38438     "      <td ng-repeat=\"dt in row track by dt.date\" class=\"text-center\" role=\"gridcell\" id=\"{{dt.uid}}\" aria-disabled=\"{{!!dt.disabled}}\">\n" +
       
 38439     "        <button type=\"button\" style=\"width:100%;\" class=\"btn btn-default\" ng-class=\"{'btn-info': dt.selected, active: isActive(dt)}\" ng-click=\"select(dt.date)\" ng-disabled=\"dt.disabled\" tabindex=\"-1\"><span ng-class=\"{'text-info': dt.current}\">{{dt.label}}</span></button>\n" +
       
 38440     "      </td>\n" +
       
 38441     "    </tr>\n" +
       
 38442     "  </tbody>\n" +
       
 38443     "</table>\n" +
       
 38444     "");
       
 38445 }]);
       
 38446 
       
 38447 angular.module("template/datepicker/popup.html", []).run(["$templateCache", function($templateCache) {
       
 38448   $templateCache.put("template/datepicker/popup.html",
       
 38449     "<ul class=\"dropdown-menu\" ng-style=\"{display: (isOpen && 'block') || 'none', top: position.top+'px', left: position.left+'px'}\" ng-keydown=\"keydown($event)\">\n" +
       
 38450     "	<li ng-transclude></li>\n" +
       
 38451     "	<li ng-if=\"showButtonBar\" style=\"padding:10px 9px 2px\">\n" +
       
 38452     "		<span class=\"btn-group\">\n" +
       
 38453     "			<button type=\"button\" class=\"btn btn-sm btn-info\" ng-click=\"select('today')\">{{ getText('current') }}</button>\n" +
       
 38454     "			<button type=\"button\" class=\"btn btn-sm btn-danger\" ng-click=\"select(null)\">{{ getText('clear') }}</button>\n" +
       
 38455     "		</span>\n" +
       
 38456     "		<button type=\"button\" class=\"btn btn-sm btn-success pull-right\" ng-click=\"close()\">{{ getText('close') }}</button>\n" +
       
 38457     "	</li>\n" +
       
 38458     "</ul>\n" +
       
 38459     "");
       
 38460 }]);
       
 38461 
       
 38462 angular.module("template/datepicker/year.html", []).run(["$templateCache", function($templateCache) {
       
 38463   $templateCache.put("template/datepicker/year.html",
       
 38464     "<table role=\"grid\" aria-labelledby=\"{{uniqueId}}-title\" aria-activedescendant=\"{{activeDateId}}\">\n" +
       
 38465     "  <thead>\n" +
       
 38466     "    <tr>\n" +
       
 38467     "      <th><button type=\"button\" class=\"btn btn-default btn-sm pull-left\" ng-click=\"move(-1)\" tabindex=\"-1\"><i class=\"glyphicon glyphicon-chevron-left\"></i></button></th>\n" +
       
 38468     "      <th colspan=\"3\"><button id=\"{{uniqueId}}-title\" role=\"heading\" aria-live=\"assertive\" aria-atomic=\"true\" type=\"button\" class=\"btn btn-default btn-sm\" ng-click=\"toggleMode()\" tabindex=\"-1\" style=\"width:100%;\"><strong>{{title}}</strong></button></th>\n" +
       
 38469     "      <th><button type=\"button\" class=\"btn btn-default btn-sm pull-right\" ng-click=\"move(1)\" tabindex=\"-1\"><i class=\"glyphicon glyphicon-chevron-right\"></i></button></th>\n" +
       
 38470     "    </tr>\n" +
       
 38471     "  </thead>\n" +
       
 38472     "  <tbody>\n" +
       
 38473     "    <tr ng-repeat=\"row in rows track by $index\">\n" +
       
 38474     "      <td ng-repeat=\"dt in row track by dt.date\" class=\"text-center\" role=\"gridcell\" id=\"{{dt.uid}}\" aria-disabled=\"{{!!dt.disabled}}\">\n" +
       
 38475     "        <button type=\"button\" style=\"width:100%;\" class=\"btn btn-default\" ng-class=\"{'btn-info': dt.selected, active: isActive(dt)}\" ng-click=\"select(dt.date)\" ng-disabled=\"dt.disabled\" tabindex=\"-1\"><span ng-class=\"{'text-info': dt.current}\">{{dt.label}}</span></button>\n" +
       
 38476     "      </td>\n" +
       
 38477     "    </tr>\n" +
       
 38478     "  </tbody>\n" +
       
 38479     "</table>\n" +
       
 38480     "");
       
 38481 }]);
       
 38482 
       
 38483 angular.module("template/modal/backdrop.html", []).run(["$templateCache", function($templateCache) {
       
 38484   $templateCache.put("template/modal/backdrop.html",
       
 38485     "<div class=\"modal-backdrop fade {{ backdropClass }}\"\n" +
       
 38486     "     ng-class=\"{in: animate}\"\n" +
       
 38487     "     ng-style=\"{'z-index': 1040 + (index && 1 || 0) + index*10}\"\n" +
       
 38488     "></div>\n" +
       
 38489     "");
       
 38490 }]);
       
 38491 
       
 38492 angular.module("template/modal/window.html", []).run(["$templateCache", function($templateCache) {
       
 38493   $templateCache.put("template/modal/window.html",
       
 38494     "<div tabindex=\"-1\" role=\"dialog\" class=\"modal fade\" ng-class=\"{in: animate}\" ng-style=\"{'z-index': 1050 + index*10, display: 'block'}\" ng-click=\"close($event)\">\n" +
       
 38495     "    <div class=\"modal-dialog\" ng-class=\"{'modal-sm': size == 'sm', 'modal-lg': size == 'lg'}\"><div class=\"modal-content\" modal-transclude></div></div>\n" +
       
 38496     "</div>");
       
 38497 }]);
       
 38498 
       
 38499 angular.module("template/pagination/pager.html", []).run(["$templateCache", function($templateCache) {
       
 38500   $templateCache.put("template/pagination/pager.html",
       
 38501     "<ul class=\"pager\">\n" +
       
 38502     "  <li ng-class=\"{disabled: noPrevious(), previous: align}\"><a href ng-click=\"selectPage(page - 1)\">{{getText('previous')}}</a></li>\n" +
       
 38503     "  <li ng-class=\"{disabled: noNext(), next: align}\"><a href ng-click=\"selectPage(page + 1)\">{{getText('next')}}</a></li>\n" +
       
 38504     "</ul>");
       
 38505 }]);
       
 38506 
       
 38507 angular.module("template/pagination/pagination.html", []).run(["$templateCache", function($templateCache) {
       
 38508   $templateCache.put("template/pagination/pagination.html",
       
 38509     "<ul class=\"pagination\">\n" +
       
 38510     "  <li ng-if=\"boundaryLinks\" ng-class=\"{disabled: noPrevious()}\"><a href ng-click=\"selectPage(1)\">{{getText('first')}}</a></li>\n" +
       
 38511     "  <li ng-if=\"directionLinks\" ng-class=\"{disabled: noPrevious()}\"><a href ng-click=\"selectPage(page - 1)\">{{getText('previous')}}</a></li>\n" +
       
 38512     "  <li ng-repeat=\"page in pages track by $index\" ng-class=\"{active: page.active}\"><a href ng-click=\"selectPage(page.number)\">{{page.text}}</a></li>\n" +
       
 38513     "  <li ng-if=\"directionLinks\" ng-class=\"{disabled: noNext()}\"><a href ng-click=\"selectPage(page + 1)\">{{getText('next')}}</a></li>\n" +
       
 38514     "  <li ng-if=\"boundaryLinks\" ng-class=\"{disabled: noNext()}\"><a href ng-click=\"selectPage(totalPages)\">{{getText('last')}}</a></li>\n" +
       
 38515     "</ul>");
       
 38516 }]);
       
 38517 
       
 38518 angular.module("template/tooltip/tooltip-html-unsafe-popup.html", []).run(["$templateCache", function($templateCache) {
       
 38519   $templateCache.put("template/tooltip/tooltip-html-unsafe-popup.html",
       
 38520     "<div class=\"tooltip {{placement}}\" ng-class=\"{ in: isOpen(), fade: animation() }\">\n" +
       
 38521     "  <div class=\"tooltip-arrow\"></div>\n" +
       
 38522     "  <div class=\"tooltip-inner\" bind-html-unsafe=\"content\"></div>\n" +
       
 38523     "</div>\n" +
       
 38524     "");
       
 38525 }]);
       
 38526 
       
 38527 angular.module("template/tooltip/tooltip-popup.html", []).run(["$templateCache", function($templateCache) {
       
 38528   $templateCache.put("template/tooltip/tooltip-popup.html",
       
 38529     "<div class=\"tooltip {{placement}}\" ng-class=\"{ in: isOpen(), fade: animation() }\">\n" +
       
 38530     "  <div class=\"tooltip-arrow\"></div>\n" +
       
 38531     "  <div class=\"tooltip-inner\" ng-bind=\"content\"></div>\n" +
       
 38532     "</div>\n" +
       
 38533     "");
       
 38534 }]);
       
 38535 
       
 38536 angular.module("template/popover/popover.html", []).run(["$templateCache", function($templateCache) {
       
 38537   $templateCache.put("template/popover/popover.html",
       
 38538     "<div class=\"popover {{placement}}\" ng-class=\"{ in: isOpen(), fade: animation() }\">\n" +
       
 38539     "  <div class=\"arrow\"></div>\n" +
       
 38540     "\n" +
       
 38541     "  <div class=\"popover-inner\">\n" +
       
 38542     "      <h3 class=\"popover-title\" ng-bind=\"title\" ng-show=\"title\"></h3>\n" +
       
 38543     "      <div class=\"popover-content\" ng-bind=\"content\"></div>\n" +
       
 38544     "  </div>\n" +
       
 38545     "</div>\n" +
       
 38546     "");
       
 38547 }]);
       
 38548 
       
 38549 angular.module("template/progressbar/bar.html", []).run(["$templateCache", function($templateCache) {
       
 38550   $templateCache.put("template/progressbar/bar.html",
       
 38551     "<div class=\"progress-bar\" ng-class=\"type && 'progress-bar-' + type\" role=\"progressbar\" aria-valuenow=\"{{value}}\" aria-valuemin=\"0\" aria-valuemax=\"{{max}}\" ng-style=\"{width: percent + '%'}\" aria-valuetext=\"{{percent | number:0}}%\" ng-transclude></div>");
       
 38552 }]);
       
 38553 
       
 38554 angular.module("template/progressbar/progress.html", []).run(["$templateCache", function($templateCache) {
       
 38555   $templateCache.put("template/progressbar/progress.html",
       
 38556     "<div class=\"progress\" ng-transclude></div>");
       
 38557 }]);
       
 38558 
       
 38559 angular.module("template/progressbar/progressbar.html", []).run(["$templateCache", function($templateCache) {
       
 38560   $templateCache.put("template/progressbar/progressbar.html",
       
 38561     "<div class=\"progress\">\n" +
       
 38562     "  <div class=\"progress-bar\" ng-class=\"type && 'progress-bar-' + type\" role=\"progressbar\" aria-valuenow=\"{{value}}\" aria-valuemin=\"0\" aria-valuemax=\"{{max}}\" ng-style=\"{width: percent + '%'}\" aria-valuetext=\"{{percent | number:0}}%\" ng-transclude></div>\n" +
       
 38563     "</div>");
       
 38564 }]);
       
 38565 
       
 38566 angular.module("template/rating/rating.html", []).run(["$templateCache", function($templateCache) {
       
 38567   $templateCache.put("template/rating/rating.html",
       
 38568     "<span ng-mouseleave=\"reset()\" ng-keydown=\"onKeydown($event)\" tabindex=\"0\" role=\"slider\" aria-valuemin=\"0\" aria-valuemax=\"{{range.length}}\" aria-valuenow=\"{{value}}\">\n" +
       
 38569     "    <i ng-repeat=\"r in range track by $index\" ng-mouseenter=\"enter($index + 1)\" ng-click=\"rate($index + 1)\" class=\"glyphicon\" ng-class=\"$index < value && (r.stateOn || 'glyphicon-star') || (r.stateOff || 'glyphicon-star-empty')\">\n" +
       
 38570     "        <span class=\"sr-only\">({{ $index < value ? '*' : ' ' }})</span>\n" +
       
 38571     "    </i>\n" +
       
 38572     "</span>");
       
 38573 }]);
       
 38574 
       
 38575 angular.module("template/tabs/tab.html", []).run(["$templateCache", function($templateCache) {
       
 38576   $templateCache.put("template/tabs/tab.html",
       
 38577     "<li ng-class=\"{active: active, disabled: disabled}\">\n" +
       
 38578     "  <a ng-click=\"select()\" tab-heading-transclude>{{heading}}</a>\n" +
       
 38579     "</li>\n" +
       
 38580     "");
       
 38581 }]);
       
 38582 
       
 38583 angular.module("template/tabs/tabset.html", []).run(["$templateCache", function($templateCache) {
       
 38584   $templateCache.put("template/tabs/tabset.html",
       
 38585     "<div>\n" +
       
 38586     "  <ul class=\"nav nav-{{type || 'tabs'}}\" ng-class=\"{'nav-stacked': vertical, 'nav-justified': justified}\" ng-transclude></ul>\n" +
       
 38587     "  <div class=\"tab-content\">\n" +
       
 38588     "    <div class=\"tab-pane\" \n" +
       
 38589     "         ng-repeat=\"tab in tabs\" \n" +
       
 38590     "         ng-class=\"{active: tab.active}\"\n" +
       
 38591     "         tab-content-transclude=\"tab\">\n" +
       
 38592     "    </div>\n" +
       
 38593     "  </div>\n" +
       
 38594     "</div>\n" +
       
 38595     "");
       
 38596 }]);
       
 38597 
       
 38598 angular.module("template/timepicker/timepicker.html", []).run(["$templateCache", function($templateCache) {
       
 38599   $templateCache.put("template/timepicker/timepicker.html",
       
 38600     "<table>\n" +
       
 38601     "	<tbody>\n" +
       
 38602     "		<tr class=\"text-center\">\n" +
       
 38603     "			<td><a ng-click=\"incrementHours()\" class=\"btn btn-link\"><span class=\"glyphicon glyphicon-chevron-up\"></span></a></td>\n" +
       
 38604     "			<td>&nbsp;</td>\n" +
       
 38605     "			<td><a ng-click=\"incrementMinutes()\" class=\"btn btn-link\"><span class=\"glyphicon glyphicon-chevron-up\"></span></a></td>\n" +
       
 38606     "			<td ng-show=\"showMeridian\"></td>\n" +
       
 38607     "		</tr>\n" +
       
 38608     "		<tr>\n" +
       
 38609     "			<td style=\"width:50px;\" class=\"form-group\" ng-class=\"{'has-error': invalidHours}\">\n" +
       
 38610     "				<input type=\"text\" ng-model=\"hours\" ng-change=\"updateHours()\" class=\"form-control text-center\" ng-mousewheel=\"incrementHours()\" ng-readonly=\"readonlyInput\" maxlength=\"2\">\n" +
       
 38611     "			</td>\n" +
       
 38612     "			<td>:</td>\n" +
       
 38613     "			<td style=\"width:50px;\" class=\"form-group\" ng-class=\"{'has-error': invalidMinutes}\">\n" +
       
 38614     "				<input type=\"text\" ng-model=\"minutes\" ng-change=\"updateMinutes()\" class=\"form-control text-center\" ng-readonly=\"readonlyInput\" maxlength=\"2\">\n" +
       
 38615     "			</td>\n" +
       
 38616     "			<td ng-show=\"showMeridian\"><button type=\"button\" class=\"btn btn-default text-center\" ng-click=\"toggleMeridian()\">{{meridian}}</button></td>\n" +
       
 38617     "		</tr>\n" +
       
 38618     "		<tr class=\"text-center\">\n" +
       
 38619     "			<td><a ng-click=\"decrementHours()\" class=\"btn btn-link\"><span class=\"glyphicon glyphicon-chevron-down\"></span></a></td>\n" +
       
 38620     "			<td>&nbsp;</td>\n" +
       
 38621     "			<td><a ng-click=\"decrementMinutes()\" class=\"btn btn-link\"><span class=\"glyphicon glyphicon-chevron-down\"></span></a></td>\n" +
       
 38622     "			<td ng-show=\"showMeridian\"></td>\n" +
       
 38623     "		</tr>\n" +
       
 38624     "	</tbody>\n" +
       
 38625     "</table>\n" +
       
 38626     "");
       
 38627 }]);
       
 38628 
       
 38629 angular.module("template/typeahead/typeahead-match.html", []).run(["$templateCache", function($templateCache) {
       
 38630   $templateCache.put("template/typeahead/typeahead-match.html",
       
 38631     "<a tabindex=\"-1\" bind-html-unsafe=\"match.label | typeaheadHighlight:query\"></a>");
       
 38632 }]);
       
 38633 
       
 38634 angular.module("template/typeahead/typeahead-popup.html", []).run(["$templateCache", function($templateCache) {
       
 38635   $templateCache.put("template/typeahead/typeahead-popup.html",
       
 38636     "<ul class=\"dropdown-menu\" ng-show=\"isOpen()\" ng-style=\"{top: position.top+'px', left: position.left+'px'}\" style=\"display: block;\" role=\"listbox\" aria-hidden=\"{{!isOpen()}}\">\n" +
       
 38637     "    <li ng-repeat=\"match in matches track by $index\" ng-class=\"{active: isActive($index) }\" ng-mouseenter=\"selectActive($index)\" ng-click=\"selectMatch($index)\" role=\"option\" id=\"{{match.id}}\">\n" +
       
 38638     "        <div typeahead-match index=\"$index\" match=\"match\" query=\"query\" template-url=\"templateUrl\"></div>\n" +
       
 38639     "    </li>\n" +
       
 38640     "</ul>\n" +
       
 38641     "");
       
 38642 }]);
       
 38643 
       
 38644 /**
       
 38645  * @license AngularJS v1.3.0-rc.5
       
 38646  * (c) 2010-2014 Google, Inc. http://angularjs.org
       
 38647  * License: MIT
       
 38648  */
       
 38649 (function(window, angular, undefined) {'use strict';
       
 38650 
       
 38651 var $resourceMinErr = angular.$$minErr('$resource');
       
 38652 
       
 38653 // Helper functions and regex to lookup a dotted path on an object
       
 38654 // stopping at undefined/null.  The path must be composed of ASCII
       
 38655 // identifiers (just like $parse)
       
 38656 var MEMBER_NAME_REGEX = /^(\.[a-zA-Z_$][0-9a-zA-Z_$]*)+$/;
       
 38657 
       
 38658 function isValidDottedPath(path) {
       
 38659   return (path != null && path !== '' && path !== 'hasOwnProperty' &&
       
 38660       MEMBER_NAME_REGEX.test('.' + path));
       
 38661 }
       
 38662 
       
 38663 function lookupDottedPath(obj, path) {
       
 38664   if (!isValidDottedPath(path)) {
       
 38665     throw $resourceMinErr('badmember', 'Dotted member path "@{0}" is invalid.', path);
       
 38666   }
       
 38667   var keys = path.split('.');
       
 38668   for (var i = 0, ii = keys.length; i < ii && obj !== undefined; i++) {
       
 38669     var key = keys[i];
       
 38670     obj = (obj !== null) ? obj[key] : undefined;
       
 38671   }
       
 38672   return obj;
       
 38673 }
       
 38674 
       
 38675 /**
       
 38676  * Create a shallow copy of an object and clear other fields from the destination
       
 38677  */
       
 38678 function shallowClearAndCopy(src, dst) {
       
 38679   dst = dst || {};
       
 38680 
       
 38681   angular.forEach(dst, function(value, key){
       
 38682     delete dst[key];
       
 38683   });
       
 38684 
       
 38685   for (var key in src) {
       
 38686     if (src.hasOwnProperty(key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) {
       
 38687       dst[key] = src[key];
       
 38688     }
       
 38689   }
       
 38690 
       
 38691   return dst;
       
 38692 }
       
 38693 
       
 38694 /**
       
 38695  * @ngdoc module
       
 38696  * @name ngResource
       
 38697  * @description
       
 38698  *
       
 38699  * # ngResource
       
 38700  *
       
 38701  * The `ngResource` module provides interaction support with RESTful services
       
 38702  * via the $resource service.
       
 38703  *
       
 38704  *
       
 38705  * <div doc-module-components="ngResource"></div>
       
 38706  *
       
 38707  * See {@link ngResource.$resource `$resource`} for usage.
       
 38708  */
       
 38709 
       
 38710 /**
       
 38711  * @ngdoc service
       
 38712  * @name $resource
       
 38713  * @requires $http
       
 38714  *
       
 38715  * @description
       
 38716  * A factory which creates a resource object that lets you interact with
       
 38717  * [RESTful](http://en.wikipedia.org/wiki/Representational_State_Transfer) server-side data sources.
       
 38718  *
       
 38719  * The returned resource object has action methods which provide high-level behaviors without
       
 38720  * the need to interact with the low level {@link ng.$http $http} service.
       
 38721  *
       
 38722  * Requires the {@link ngResource `ngResource`} module to be installed.
       
 38723  *
       
 38724  * By default, trailing slashes will be stripped from the calculated URLs,
       
 38725  * which can pose problems with server backends that do not expect that
       
 38726  * behavior.  This can be disabled by configuring the `$resourceProvider` like
       
 38727  * this:
       
 38728  *
       
 38729  * ```js
       
 38730      app.config(['$resourceProvider', function ($resourceProvider) {
       
 38731        // Don't strip trailing slashes from calculated URLs
       
 38732        $resourceProvider.defaults.stripTrailingSlashes = false;
       
 38733      }]);
       
 38734  * ```
       
 38735  *
       
 38736  * @param {string} url A parametrized URL template with parameters prefixed by `:` as in
       
 38737  *   `/user/:username`. If you are using a URL with a port number (e.g.
       
 38738  *   `http://example.com:8080/api`), it will be respected.
       
 38739  *
       
 38740  *   If you are using a url with a suffix, just add the suffix, like this:
       
 38741  *   `$resource('http://example.com/resource.json')` or `$resource('http://example.com/:id.json')`
       
 38742  *   or even `$resource('http://example.com/resource/:resource_id.:format')`
       
 38743  *   If the parameter before the suffix is empty, :resource_id in this case, then the `/.` will be
       
 38744  *   collapsed down to a single `.`.  If you need this sequence to appear and not collapse then you
       
 38745  *   can escape it with `/\.`.
       
 38746  *
       
 38747  * @param {Object=} paramDefaults Default values for `url` parameters. These can be overridden in
       
 38748  *   `actions` methods. If any of the parameter value is a function, it will be executed every time
       
 38749  *   when a param value needs to be obtained for a request (unless the param was overridden).
       
 38750  *
       
 38751  *   Each key value in the parameter object is first bound to url template if present and then any
       
 38752  *   excess keys are appended to the url search query after the `?`.
       
 38753  *
       
 38754  *   Given a template `/path/:verb` and parameter `{verb:'greet', salutation:'Hello'}` results in
       
 38755  *   URL `/path/greet?salutation=Hello`.
       
 38756  *
       
 38757  *   If the parameter value is prefixed with `@` then the value for that parameter will be extracted
       
 38758  *   from the corresponding property on the `data` object (provided when calling an action method).  For
       
 38759  *   example, if the `defaultParam` object is `{someParam: '@someProp'}` then the value of `someParam`
       
 38760  *   will be `data.someProp`.
       
 38761  *
       
 38762  * @param {Object.<Object>=} actions Hash with declaration of custom action that should extend
       
 38763  *   the default set of resource actions. The declaration should be created in the format of {@link
       
 38764  *   ng.$http#usage_parameters $http.config}:
       
 38765  *
       
 38766  *       {action1: {method:?, params:?, isArray:?, headers:?, ...},
       
 38767  *        action2: {method:?, params:?, isArray:?, headers:?, ...},
       
 38768  *        ...}
       
 38769  *
       
 38770  *   Where:
       
 38771  *
       
 38772  *   - **`action`** – {string} – The name of action. This name becomes the name of the method on
       
 38773  *     your resource object.
       
 38774  *   - **`method`** – {string} – Case insensitive HTTP method (e.g. `GET`, `POST`, `PUT`,
       
 38775  *     `DELETE`, `JSONP`, etc).
       
 38776  *   - **`params`** – {Object=} – Optional set of pre-bound parameters for this action. If any of
       
 38777  *     the parameter value is a function, it will be executed every time when a param value needs to
       
 38778  *     be obtained for a request (unless the param was overridden).
       
 38779  *   - **`url`** – {string} – action specific `url` override. The url templating is supported just
       
 38780  *     like for the resource-level urls.
       
 38781  *   - **`isArray`** – {boolean=} – If true then the returned object for this action is an array,
       
 38782  *     see `returns` section.
       
 38783  *   - **`transformRequest`** –
       
 38784  *     `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
       
 38785  *     transform function or an array of such functions. The transform function takes the http
       
 38786  *     request body and headers and returns its transformed (typically serialized) version.
       
 38787  *     By default, transformRequest will contain one function that checks if the request data is
       
 38788  *     an object and serializes to using `angular.toJson`. To prevent this behavior, set
       
 38789  *     `transformRequest` to an empty array: `transformRequest: []`
       
 38790  *   - **`transformResponse`** –
       
 38791  *     `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
       
 38792  *     transform function or an array of such functions. The transform function takes the http
       
 38793  *     response body and headers and returns its transformed (typically deserialized) version.
       
 38794  *     By default, transformResponse will contain one function that checks if the response looks like
       
 38795  *     a JSON string and deserializes it using `angular.fromJson`. To prevent this behavior, set
       
 38796  *     `transformResponse` to an empty array: `transformResponse: []`
       
 38797  *   - **`cache`** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
       
 38798  *     GET request, otherwise if a cache instance built with
       
 38799  *     {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
       
 38800  *     caching.
       
 38801  *   - **`timeout`** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise} that
       
 38802  *     should abort the request when resolved.
       
 38803  *   - **`withCredentials`** - `{boolean}` - whether to set the `withCredentials` flag on the
       
 38804  *     XHR object. See
       
 38805  *     [requests with credentials](https://developer.mozilla.org/en/http_access_control#section_5)
       
 38806  *     for more information.
       
 38807  *   - **`responseType`** - `{string}` - see
       
 38808  *     [requestType](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType).
       
 38809  *   - **`interceptor`** - `{Object=}` - The interceptor object has two optional methods -
       
 38810  *     `response` and `responseError`. Both `response` and `responseError` interceptors get called
       
 38811  *     with `http response` object. See {@link ng.$http $http interceptors}.
       
 38812  *
       
 38813  * @param {Object} options Hash with custom settings that should extend the
       
 38814  *   default `$resourceProvider` behavior.  The only supported option is
       
 38815  *
       
 38816  *   Where:
       
 38817  *
       
 38818  *   - **`stripTrailingSlashes`** – {boolean} – If true then the trailing
       
 38819  *   slashes from any calculated URL will be stripped. (Defaults to true.)
       
 38820  *
       
 38821  * @returns {Object} A resource "class" object with methods for the default set of resource actions
       
 38822  *   optionally extended with custom `actions`. The default set contains these actions:
       
 38823  *   ```js
       
 38824  *   { 'get':    {method:'GET'},
       
 38825  *     'save':   {method:'POST'},
       
 38826  *     'query':  {method:'GET', isArray:true},
       
 38827  *     'remove': {method:'DELETE'},
       
 38828  *     'delete': {method:'DELETE'} };
       
 38829  *   ```
       
 38830  *
       
 38831  *   Calling these methods invoke an {@link ng.$http} with the specified http method,
       
 38832  *   destination and parameters. When the data is returned from the server then the object is an
       
 38833  *   instance of the resource class. The actions `save`, `remove` and `delete` are available on it
       
 38834  *   as  methods with the `$` prefix. This allows you to easily perform CRUD operations (create,
       
 38835  *   read, update, delete) on server-side data like this:
       
 38836  *   ```js
       
 38837  *   var User = $resource('/user/:userId', {userId:'@id'});
       
 38838  *   var user = User.get({userId:123}, function() {
       
 38839  *     user.abc = true;
       
 38840  *     user.$save();
       
 38841  *   });
       
 38842  *   ```
       
 38843  *
       
 38844  *   It is important to realize that invoking a $resource object method immediately returns an
       
 38845  *   empty reference (object or array depending on `isArray`). Once the data is returned from the
       
 38846  *   server the existing reference is populated with the actual data. This is a useful trick since
       
 38847  *   usually the resource is assigned to a model which is then rendered by the view. Having an empty
       
 38848  *   object results in no rendering, once the data arrives from the server then the object is
       
 38849  *   populated with the data and the view automatically re-renders itself showing the new data. This
       
 38850  *   means that in most cases one never has to write a callback function for the action methods.
       
 38851  *
       
 38852  *   The action methods on the class object or instance object can be invoked with the following
       
 38853  *   parameters:
       
 38854  *
       
 38855  *   - HTTP GET "class" actions: `Resource.action([parameters], [success], [error])`
       
 38856  *   - non-GET "class" actions: `Resource.action([parameters], postData, [success], [error])`
       
 38857  *   - non-GET instance actions:  `instance.$action([parameters], [success], [error])`
       
 38858  *
       
 38859  *   Success callback is called with (value, responseHeaders) arguments. Error callback is called
       
 38860  *   with (httpResponse) argument.
       
 38861  *
       
 38862  *   Class actions return empty instance (with additional properties below).
       
 38863  *   Instance actions return promise of the action.
       
 38864  *
       
 38865  *   The Resource instances and collection have these additional properties:
       
 38866  *
       
 38867  *   - `$promise`: the {@link ng.$q promise} of the original server interaction that created this
       
 38868  *     instance or collection.
       
 38869  *
       
 38870  *     On success, the promise is resolved with the same resource instance or collection object,
       
 38871  *     updated with data from server. This makes it easy to use in
       
 38872  *     {@link ngRoute.$routeProvider resolve section of $routeProvider.when()} to defer view
       
 38873  *     rendering until the resource(s) are loaded.
       
 38874  *
       
 38875  *     On failure, the promise is resolved with the {@link ng.$http http response} object, without
       
 38876  *     the `resource` property.
       
 38877  *
       
 38878  *     If an interceptor object was provided, the promise will instead be resolved with the value
       
 38879  *     returned by the interceptor.
       
 38880  *
       
 38881  *   - `$resolved`: `true` after first server interaction is completed (either with success or
       
 38882  *      rejection), `false` before that. Knowing if the Resource has been resolved is useful in
       
 38883  *      data-binding.
       
 38884  *
       
 38885  * @example
       
 38886  *
       
 38887  * # Credit card resource
       
 38888  *
       
 38889  * ```js
       
 38890      // Define CreditCard class
       
 38891      var CreditCard = $resource('/user/:userId/card/:cardId',
       
 38892       {userId:123, cardId:'@id'}, {
       
 38893        charge: {method:'POST', params:{charge:true}}
       
 38894       });
       
 38895 
       
 38896      // We can retrieve a collection from the server
       
 38897      var cards = CreditCard.query(function() {
       
 38898        // GET: /user/123/card
       
 38899        // server returns: [ {id:456, number:'1234', name:'Smith'} ];
       
 38900 
       
 38901        var card = cards[0];
       
 38902        // each item is an instance of CreditCard
       
 38903        expect(card instanceof CreditCard).toEqual(true);
       
 38904        card.name = "J. Smith";
       
 38905        // non GET methods are mapped onto the instances
       
 38906        card.$save();
       
 38907        // POST: /user/123/card/456 {id:456, number:'1234', name:'J. Smith'}
       
 38908        // server returns: {id:456, number:'1234', name: 'J. Smith'};
       
 38909 
       
 38910        // our custom method is mapped as well.
       
 38911        card.$charge({amount:9.99});
       
 38912        // POST: /user/123/card/456?amount=9.99&charge=true {id:456, number:'1234', name:'J. Smith'}
       
 38913      });
       
 38914 
       
 38915      // we can create an instance as well
       
 38916      var newCard = new CreditCard({number:'0123'});
       
 38917      newCard.name = "Mike Smith";
       
 38918      newCard.$save();
       
 38919      // POST: /user/123/card {number:'0123', name:'Mike Smith'}
       
 38920      // server returns: {id:789, number:'0123', name: 'Mike Smith'};
       
 38921      expect(newCard.id).toEqual(789);
       
 38922  * ```
       
 38923  *
       
 38924  * The object returned from this function execution is a resource "class" which has "static" method
       
 38925  * for each action in the definition.
       
 38926  *
       
 38927  * Calling these methods invoke `$http` on the `url` template with the given `method`, `params` and
       
 38928  * `headers`.
       
 38929  * When the data is returned from the server then the object is an instance of the resource type and
       
 38930  * all of the non-GET methods are available with `$` prefix. This allows you to easily support CRUD
       
 38931  * operations (create, read, update, delete) on server-side data.
       
 38932 
       
 38933    ```js
       
 38934      var User = $resource('/user/:userId', {userId:'@id'});
       
 38935      User.get({userId:123}, function(user) {
       
 38936        user.abc = true;
       
 38937        user.$save();
       
 38938      });
       
 38939    ```
       
 38940  *
       
 38941  * It's worth noting that the success callback for `get`, `query` and other methods gets passed
       
 38942  * in the response that came from the server as well as $http header getter function, so one
       
 38943  * could rewrite the above example and get access to http headers as:
       
 38944  *
       
 38945    ```js
       
 38946      var User = $resource('/user/:userId', {userId:'@id'});
       
 38947      User.get({userId:123}, function(u, getResponseHeaders){
       
 38948        u.abc = true;
       
 38949        u.$save(function(u, putResponseHeaders) {
       
 38950          //u => saved user object
       
 38951          //putResponseHeaders => $http header getter
       
 38952        });
       
 38953      });
       
 38954    ```
       
 38955  *
       
 38956  * You can also access the raw `$http` promise via the `$promise` property on the object returned
       
 38957  *
       
 38958    ```
       
 38959      var User = $resource('/user/:userId', {userId:'@id'});
       
 38960      User.get({userId:123})
       
 38961          .$promise.then(function(user) {
       
 38962            $scope.user = user;
       
 38963          });
       
 38964    ```
       
 38965 
       
 38966  * # Creating a custom 'PUT' request
       
 38967  * In this example we create a custom method on our resource to make a PUT request
       
 38968  * ```js
       
 38969  *    var app = angular.module('app', ['ngResource', 'ngRoute']);
       
 38970  *
       
 38971  *    // Some APIs expect a PUT request in the format URL/object/ID
       
 38972  *    // Here we are creating an 'update' method
       
 38973  *    app.factory('Notes', ['$resource', function($resource) {
       
 38974  *    return $resource('/notes/:id', null,
       
 38975  *        {
       
 38976  *            'update': { method:'PUT' }
       
 38977  *        });
       
 38978  *    }]);
       
 38979  *
       
 38980  *    // In our controller we get the ID from the URL using ngRoute and $routeParams
       
 38981  *    // We pass in $routeParams and our Notes factory along with $scope
       
 38982  *    app.controller('NotesCtrl', ['$scope', '$routeParams', 'Notes',
       
 38983                                       function($scope, $routeParams, Notes) {
       
 38984  *    // First get a note object from the factory
       
 38985  *    var note = Notes.get({ id:$routeParams.id });
       
 38986  *    $id = note.id;
       
 38987  *
       
 38988  *    // Now call update passing in the ID first then the object you are updating
       
 38989  *    Notes.update({ id:$id }, note);
       
 38990  *
       
 38991  *    // This will PUT /notes/ID with the note object in the request payload
       
 38992  *    }]);
       
 38993  * ```
       
 38994  */
       
 38995 angular.module('ngResource', ['ng']).
       
 38996   provider('$resource', function () {
       
 38997     var provider = this;
       
 38998 
       
 38999     this.defaults = {
       
 39000       // Strip slashes by default
       
 39001       stripTrailingSlashes: true,
       
 39002 
       
 39003       // Default actions configuration
       
 39004       actions: {
       
 39005         'get': {method: 'GET'},
       
 39006         'save': {method: 'POST'},
       
 39007         'query': {method: 'GET', isArray: true},
       
 39008         'remove': {method: 'DELETE'},
       
 39009         'delete': {method: 'DELETE'}
       
 39010       }
       
 39011     };
       
 39012 
       
 39013     this.$get = ['$http', '$q', function ($http, $q) {
       
 39014 
       
 39015       var noop = angular.noop,
       
 39016         forEach = angular.forEach,
       
 39017         extend = angular.extend,
       
 39018         copy = angular.copy,
       
 39019         isFunction = angular.isFunction;
       
 39020 
       
 39021       /**
       
 39022        * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
       
 39023        * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set
       
 39024        * (pchar) allowed in path segments:
       
 39025        *    segment       = *pchar
       
 39026        *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
       
 39027        *    pct-encoded   = "%" HEXDIG HEXDIG
       
 39028        *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
       
 39029        *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
       
 39030        *                     / "*" / "+" / "," / ";" / "="
       
 39031        */
       
 39032       function encodeUriSegment(val) {
       
 39033         return encodeUriQuery(val, true).
       
 39034           replace(/%26/gi, '&').
       
 39035           replace(/%3D/gi, '=').
       
 39036           replace(/%2B/gi, '+');
       
 39037       }
       
 39038 
       
 39039 
       
 39040       /**
       
 39041        * This method is intended for encoding *key* or *value* parts of query component. We need a
       
 39042        * custom method because encodeURIComponent is too aggressive and encodes stuff that doesn't
       
 39043        * have to be encoded per http://tools.ietf.org/html/rfc3986:
       
 39044        *    query       = *( pchar / "/" / "?" )
       
 39045        *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
       
 39046        *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
       
 39047        *    pct-encoded   = "%" HEXDIG HEXDIG
       
 39048        *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
       
 39049        *                     / "*" / "+" / "," / ";" / "="
       
 39050        */
       
 39051       function encodeUriQuery(val, pctEncodeSpaces) {
       
 39052         return encodeURIComponent(val).
       
 39053           replace(/%40/gi, '@').
       
 39054           replace(/%3A/gi, ':').
       
 39055           replace(/%24/g, '$').
       
 39056           replace(/%2C/gi, ',').
       
 39057           replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
       
 39058       }
       
 39059 
       
 39060       function Route(template, defaults) {
       
 39061         this.template = template;
       
 39062         this.defaults = extend({}, provider.defaults, defaults);
       
 39063         this.urlParams = {};
       
 39064       }
       
 39065 
       
 39066       Route.prototype = {
       
 39067         setUrlParams: function (config, params, actionUrl) {
       
 39068           var self = this,
       
 39069             url = actionUrl || self.template,
       
 39070             val,
       
 39071             encodedVal;
       
 39072 
       
 39073           var urlParams = self.urlParams = {};
       
 39074           forEach(url.split(/\W/), function (param) {
       
 39075             if (param === 'hasOwnProperty') {
       
 39076               throw $resourceMinErr('badname', "hasOwnProperty is not a valid parameter name.");
       
 39077             }
       
 39078             if (!(new RegExp("^\\d+$").test(param)) && param &&
       
 39079               (new RegExp("(^|[^\\\\]):" + param + "(\\W|$)").test(url))) {
       
 39080               urlParams[param] = true;
       
 39081             }
       
 39082           });
       
 39083           url = url.replace(/\\:/g, ':');
       
 39084 
       
 39085           params = params || {};
       
 39086           forEach(self.urlParams, function (_, urlParam) {
       
 39087             val = params.hasOwnProperty(urlParam) ? params[urlParam] : self.defaults[urlParam];
       
 39088             if (angular.isDefined(val) && val !== null) {
       
 39089               encodedVal = encodeUriSegment(val);
       
 39090               url = url.replace(new RegExp(":" + urlParam + "(\\W|$)", "g"), function (match, p1) {
       
 39091                 return encodedVal + p1;
       
 39092               });
       
 39093             } else {
       
 39094               url = url.replace(new RegExp("(\/?):" + urlParam + "(\\W|$)", "g"), function (match,
       
 39095                   leadingSlashes, tail) {
       
 39096                 if (tail.charAt(0) == '/') {
       
 39097                   return tail;
       
 39098                 } else {
       
 39099                   return leadingSlashes + tail;
       
 39100                 }
       
 39101               });
       
 39102             }
       
 39103           });
       
 39104 
       
 39105           // strip trailing slashes and set the url (unless this behavior is specifically disabled)
       
 39106           if (self.defaults.stripTrailingSlashes) {
       
 39107             url = url.replace(/\/+$/, '') || '/';
       
 39108           }
       
 39109 
       
 39110           // then replace collapse `/.` if found in the last URL path segment before the query
       
 39111           // E.g. `http://url.com/id./format?q=x` becomes `http://url.com/id.format?q=x`
       
 39112           url = url.replace(/\/\.(?=\w+($|\?))/, '.');
       
 39113           // replace escaped `/\.` with `/.`
       
 39114           config.url = url.replace(/\/\\\./, '/.');
       
 39115 
       
 39116 
       
 39117           // set params - delegate param encoding to $http
       
 39118           forEach(params, function (value, key) {
       
 39119             if (!self.urlParams[key]) {
       
 39120               config.params = config.params || {};
       
 39121               config.params[key] = value;
       
 39122             }
       
 39123           });
       
 39124         }
       
 39125       };
       
 39126 
       
 39127 
       
 39128       function resourceFactory(url, paramDefaults, actions, options) {
       
 39129         var route = new Route(url, options);
       
 39130 
       
 39131         actions = extend({}, provider.defaults.actions, actions);
       
 39132 
       
 39133         function extractParams(data, actionParams) {
       
 39134           var ids = {};
       
 39135           actionParams = extend({}, paramDefaults, actionParams);
       
 39136           forEach(actionParams, function (value, key) {
       
 39137             if (isFunction(value)) { value = value(); }
       
 39138             ids[key] = value && value.charAt && value.charAt(0) == '@' ?
       
 39139               lookupDottedPath(data, value.substr(1)) : value;
       
 39140           });
       
 39141           return ids;
       
 39142         }
       
 39143 
       
 39144         function defaultResponseInterceptor(response) {
       
 39145           return response.resource;
       
 39146         }
       
 39147 
       
 39148         function Resource(value) {
       
 39149           shallowClearAndCopy(value || {}, this);
       
 39150         }
       
 39151 
       
 39152         Resource.prototype.toJSON = function () {
       
 39153           var data = extend({}, this);
       
 39154           delete data.$promise;
       
 39155           delete data.$resolved;
       
 39156           return data;
       
 39157         };
       
 39158 
       
 39159         forEach(actions, function (action, name) {
       
 39160           var hasBody = /^(POST|PUT|PATCH)$/i.test(action.method);
       
 39161 
       
 39162           Resource[name] = function (a1, a2, a3, a4) {
       
 39163             var params = {}, data, success, error;
       
 39164 
       
 39165             /* jshint -W086 */ /* (purposefully fall through case statements) */
       
 39166             switch (arguments.length) {
       
 39167               case 4:
       
 39168                 error = a4;
       
 39169                 success = a3;
       
 39170               //fallthrough
       
 39171               case 3:
       
 39172               case 2:
       
 39173                 if (isFunction(a2)) {
       
 39174                   if (isFunction(a1)) {
       
 39175                     success = a1;
       
 39176                     error = a2;
       
 39177                     break;
       
 39178                   }
       
 39179 
       
 39180                   success = a2;
       
 39181                   error = a3;
       
 39182                   //fallthrough
       
 39183                 } else {
       
 39184                   params = a1;
       
 39185                   data = a2;
       
 39186                   success = a3;
       
 39187                   break;
       
 39188                 }
       
 39189               case 1:
       
 39190                 if (isFunction(a1)) success = a1;
       
 39191                 else if (hasBody) data = a1;
       
 39192                 else params = a1;
       
 39193                 break;
       
 39194               case 0: break;
       
 39195               default:
       
 39196                 throw $resourceMinErr('badargs',
       
 39197                   "Expected up to 4 arguments [params, data, success, error], got {0} arguments",
       
 39198                   arguments.length);
       
 39199             }
       
 39200             /* jshint +W086 */ /* (purposefully fall through case statements) */
       
 39201 
       
 39202             var isInstanceCall = this instanceof Resource;
       
 39203             var value = isInstanceCall ? data : (action.isArray ? [] : new Resource(data));
       
 39204             var httpConfig = {};
       
 39205             var responseInterceptor = action.interceptor && action.interceptor.response ||
       
 39206               defaultResponseInterceptor;
       
 39207             var responseErrorInterceptor = action.interceptor && action.interceptor.responseError ||
       
 39208               undefined;
       
 39209 
       
 39210             forEach(action, function (value, key) {
       
 39211               if (key != 'params' && key != 'isArray' && key != 'interceptor') {
       
 39212                 httpConfig[key] = copy(value);
       
 39213               }
       
 39214             });
       
 39215 
       
 39216             if (hasBody) httpConfig.data = data;
       
 39217             route.setUrlParams(httpConfig,
       
 39218               extend({}, extractParams(data, action.params || {}), params),
       
 39219               action.url);
       
 39220 
       
 39221             var promise = $http(httpConfig).then(function (response) {
       
 39222               var data = response.data,
       
 39223                 promise = value.$promise;
       
 39224 
       
 39225               if (data) {
       
 39226                 // Need to convert action.isArray to boolean in case it is undefined
       
 39227                 // jshint -W018
       
 39228                 if (angular.isArray(data) !== (!!action.isArray)) {
       
 39229                   throw $resourceMinErr('badcfg',
       
 39230                       'Error in resource configuration for action `{0}`. Expected response to ' +
       
 39231                       'contain an {1} but got an {2}', name, action.isArray ? 'array' : 'object',
       
 39232                     angular.isArray(data) ? 'array' : 'object');
       
 39233                 }
       
 39234                 // jshint +W018
       
 39235                 if (action.isArray) {
       
 39236                   value.length = 0;
       
 39237                   forEach(data, function (item) {
       
 39238                     if (typeof item === "object") {
       
 39239                       value.push(new Resource(item));
       
 39240                     } else {
       
 39241                       // Valid JSON values may be string literals, and these should not be converted
       
 39242                       // into objects. These items will not have access to the Resource prototype
       
 39243                       // methods, but unfortunately there
       
 39244                       value.push(item);
       
 39245                     }
       
 39246                   });
       
 39247                 } else {
       
 39248                   shallowClearAndCopy(data, value);
       
 39249                   value.$promise = promise;
       
 39250                 }
       
 39251               }
       
 39252 
       
 39253               value.$resolved = true;
       
 39254 
       
 39255               response.resource = value;
       
 39256 
       
 39257               return response;
       
 39258             }, function (response) {
       
 39259               value.$resolved = true;
       
 39260 
       
 39261               (error || noop)(response);
       
 39262 
       
 39263               return $q.reject(response);
       
 39264             });
       
 39265 
       
 39266             promise = promise.then(
       
 39267               function (response) {
       
 39268                 var value = responseInterceptor(response);
       
 39269                 (success || noop)(value, response.headers);
       
 39270                 return value;
       
 39271               },
       
 39272               responseErrorInterceptor);
       
 39273 
       
 39274             if (!isInstanceCall) {
       
 39275               // we are creating instance / collection
       
 39276               // - set the initial promise
       
 39277               // - return the instance / collection
       
 39278               value.$promise = promise;
       
 39279               value.$resolved = false;
       
 39280 
       
 39281               return value;
       
 39282             }
       
 39283 
       
 39284             // instance call
       
 39285             return promise;
       
 39286           };
       
 39287 
       
 39288 
       
 39289           Resource.prototype['$' + name] = function (params, success, error) {
       
 39290             if (isFunction(params)) {
       
 39291               error = success; success = params; params = {};
       
 39292             }
       
 39293             var result = Resource[name].call(this, params, this, success, error);
       
 39294             return result.$promise || result;
       
 39295           };
       
 39296         });
       
 39297 
       
 39298         Resource.bind = function (additionalParamDefaults) {
       
 39299           return resourceFactory(url, extend({}, paramDefaults, additionalParamDefaults), actions);
       
 39300         };
       
 39301 
       
 39302         return Resource;
       
 39303       }
       
 39304 
       
 39305       return resourceFactory;
       
 39306     }];
       
 39307   });
       
 39308 
       
 39309 
       
 39310 })(window, window.angular);
       
 39311 
       
 39312 /**
       
 39313  * @license AngularJS v1.3.0-rc.5
       
 39314  * (c) 2010-2014 Google, Inc. http://angularjs.org
       
 39315  * License: MIT
       
 39316  */
       
 39317 (function(window, angular, undefined) {'use strict';
       
 39318 
       
 39319 /**
       
 39320  * @ngdoc module
       
 39321  * @name ngRoute
       
 39322  * @description
       
 39323  *
       
 39324  * # ngRoute
       
 39325  *
       
 39326  * The `ngRoute` module provides routing and deeplinking services and directives for angular apps.
       
 39327  *
       
 39328  * ## Example
       
 39329  * See {@link ngRoute.$route#example $route} for an example of configuring and using `ngRoute`.
       
 39330  *
       
 39331  *
       
 39332  * <div doc-module-components="ngRoute"></div>
       
 39333  */
       
 39334  /* global -ngRouteModule */
       
 39335 var ngRouteModule = angular.module('ngRoute', ['ng']).
       
 39336                         provider('$route', $RouteProvider),
       
 39337     $routeMinErr = angular.$$minErr('ngRoute');
       
 39338 
       
 39339 /**
       
 39340  * @ngdoc provider
       
 39341  * @name $routeProvider
       
 39342  *
       
 39343  * @description
       
 39344  *
       
 39345  * Used for configuring routes.
       
 39346  *
       
 39347  * ## Example
       
 39348  * See {@link ngRoute.$route#example $route} for an example of configuring and using `ngRoute`.
       
 39349  *
       
 39350  * ## Dependencies
       
 39351  * Requires the {@link ngRoute `ngRoute`} module to be installed.
       
 39352  */
       
 39353 function $RouteProvider(){
       
 39354   function inherit(parent, extra) {
       
 39355     return angular.extend(new (angular.extend(function() {}, {prototype:parent}))(), extra);
       
 39356   }
       
 39357 
       
 39358   var routes = {};
       
 39359 
       
 39360   /**
       
 39361    * @ngdoc method
       
 39362    * @name $routeProvider#when
       
 39363    *
       
 39364    * @param {string} path Route path (matched against `$location.path`). If `$location.path`
       
 39365    *    contains redundant trailing slash or is missing one, the route will still match and the
       
 39366    *    `$location.path` will be updated to add or drop the trailing slash to exactly match the
       
 39367    *    route definition.
       
 39368    *
       
 39369    *    * `path` can contain named groups starting with a colon: e.g. `:name`. All characters up
       
 39370    *        to the next slash are matched and stored in `$routeParams` under the given `name`
       
 39371    *        when the route matches.
       
 39372    *    * `path` can contain named groups starting with a colon and ending with a star:
       
 39373    *        e.g.`:name*`. All characters are eagerly stored in `$routeParams` under the given `name`
       
 39374    *        when the route matches.
       
 39375    *    * `path` can contain optional named groups with a question mark: e.g.`:name?`.
       
 39376    *
       
 39377    *    For example, routes like `/color/:color/largecode/:largecode*\/edit` will match
       
 39378    *    `/color/brown/largecode/code/with/slashes/edit` and extract:
       
 39379    *
       
 39380    *    * `color: brown`
       
 39381    *    * `largecode: code/with/slashes`.
       
 39382    *
       
 39383    *
       
 39384    * @param {Object} route Mapping information to be assigned to `$route.current` on route
       
 39385    *    match.
       
 39386    *
       
 39387    *    Object properties:
       
 39388    *
       
 39389    *    - `controller` – `{(string|function()=}` – Controller fn that should be associated with
       
 39390    *      newly created scope or the name of a {@link angular.Module#controller registered
       
 39391    *      controller} if passed as a string.
       
 39392    *    - `controllerAs` – `{string=}` – A controller alias name. If present the controller will be
       
 39393    *      published to scope under the `controllerAs` name.
       
 39394    *    - `template` – `{string=|function()=}` – html template as a string or a function that
       
 39395    *      returns an html template as a string which should be used by {@link
       
 39396    *      ngRoute.directive:ngView ngView} or {@link ng.directive:ngInclude ngInclude} directives.
       
 39397    *      This property takes precedence over `templateUrl`.
       
 39398    *
       
 39399    *      If `template` is a function, it will be called with the following parameters:
       
 39400    *
       
 39401    *      - `{Array.<Object>}` - route parameters extracted from the current
       
 39402    *        `$location.path()` by applying the current route
       
 39403    *
       
 39404    *    - `templateUrl` – `{string=|function()=}` – path or function that returns a path to an html
       
 39405    *      template that should be used by {@link ngRoute.directive:ngView ngView}.
       
 39406    *
       
 39407    *      If `templateUrl` is a function, it will be called with the following parameters:
       
 39408    *
       
 39409    *      - `{Array.<Object>}` - route parameters extracted from the current
       
 39410    *        `$location.path()` by applying the current route
       
 39411    *
       
 39412    *    - `resolve` - `{Object.<string, function>=}` - An optional map of dependencies which should
       
 39413    *      be injected into the controller. If any of these dependencies are promises, the router
       
 39414    *      will wait for them all to be resolved or one to be rejected before the controller is
       
 39415    *      instantiated.
       
 39416    *      If all the promises are resolved successfully, the values of the resolved promises are
       
 39417    *      injected and {@link ngRoute.$route#$routeChangeSuccess $routeChangeSuccess} event is
       
 39418    *      fired. If any of the promises are rejected the
       
 39419    *      {@link ngRoute.$route#$routeChangeError $routeChangeError} event is fired. The map object
       
 39420    *      is:
       
 39421    *
       
 39422    *      - `key` – `{string}`: a name of a dependency to be injected into the controller.
       
 39423    *      - `factory` - `{string|function}`: If `string` then it is an alias for a service.
       
 39424    *        Otherwise if function, then it is {@link auto.$injector#invoke injected}
       
 39425    *        and the return value is treated as the dependency. If the result is a promise, it is
       
 39426    *        resolved before its value is injected into the controller. Be aware that
       
 39427    *        `ngRoute.$routeParams` will still refer to the previous route within these resolve
       
 39428    *        functions.  Use `$route.current.params` to access the new route parameters, instead.
       
 39429    *
       
 39430    *    - `redirectTo` – {(string|function())=} – value to update
       
 39431    *      {@link ng.$location $location} path with and trigger route redirection.
       
 39432    *
       
 39433    *      If `redirectTo` is a function, it will be called with the following parameters:
       
 39434    *
       
 39435    *      - `{Object.<string>}` - route parameters extracted from the current
       
 39436    *        `$location.path()` by applying the current route templateUrl.
       
 39437    *      - `{string}` - current `$location.path()`
       
 39438    *      - `{Object}` - current `$location.search()`
       
 39439    *
       
 39440    *      The custom `redirectTo` function is expected to return a string which will be used
       
 39441    *      to update `$location.path()` and `$location.search()`.
       
 39442    *
       
 39443    *    - `[reloadOnSearch=true]` - {boolean=} - reload route when only `$location.search()`
       
 39444    *      or `$location.hash()` changes.
       
 39445    *
       
 39446    *      If the option is set to `false` and url in the browser changes, then
       
 39447    *      `$routeUpdate` event is broadcasted on the root scope.
       
 39448    *
       
 39449    *    - `[caseInsensitiveMatch=false]` - {boolean=} - match routes without being case sensitive
       
 39450    *
       
 39451    *      If the option is set to `true`, then the particular route can be matched without being
       
 39452    *      case sensitive
       
 39453    *
       
 39454    * @returns {Object} self
       
 39455    *
       
 39456    * @description
       
 39457    * Adds a new route definition to the `$route` service.
       
 39458    */
       
 39459   this.when = function(path, route) {
       
 39460     routes[path] = angular.extend(
       
 39461       {reloadOnSearch: true},
       
 39462       route,
       
 39463       path && pathRegExp(path, route)
       
 39464     );
       
 39465 
       
 39466     // create redirection for trailing slashes
       
 39467     if (path) {
       
 39468       var redirectPath = (path[path.length-1] == '/')
       
 39469             ? path.substr(0, path.length-1)
       
 39470             : path +'/';
       
 39471 
       
 39472       routes[redirectPath] = angular.extend(
       
 39473         {redirectTo: path},
       
 39474         pathRegExp(redirectPath, route)
       
 39475       );
       
 39476     }
       
 39477 
       
 39478     return this;
       
 39479   };
       
 39480 
       
 39481    /**
       
 39482     * @param path {string} path
       
 39483     * @param opts {Object} options
       
 39484     * @return {?Object}
       
 39485     *
       
 39486     * @description
       
 39487     * Normalizes the given path, returning a regular expression
       
 39488     * and the original path.
       
 39489     *
       
 39490     * Inspired by pathRexp in visionmedia/express/lib/utils.js.
       
 39491     */
       
 39492   function pathRegExp(path, opts) {
       
 39493     var insensitive = opts.caseInsensitiveMatch,
       
 39494         ret = {
       
 39495           originalPath: path,
       
 39496           regexp: path
       
 39497         },
       
 39498         keys = ret.keys = [];
       
 39499 
       
 39500     path = path
       
 39501       .replace(/([().])/g, '\\$1')
       
 39502       .replace(/(\/)?:(\w+)([\?\*])?/g, function(_, slash, key, option){
       
 39503         var optional = option === '?' ? option : null;
       
 39504         var star = option === '*' ? option : null;
       
 39505         keys.push({ name: key, optional: !!optional });
       
 39506         slash = slash || '';
       
 39507         return ''
       
 39508           + (optional ? '' : slash)
       
 39509           + '(?:'
       
 39510           + (optional ? slash : '')
       
 39511           + (star && '(.+?)' || '([^/]+)')
       
 39512           + (optional || '')
       
 39513           + ')'
       
 39514           + (optional || '');
       
 39515       })
       
 39516       .replace(/([\/$\*])/g, '\\$1');
       
 39517 
       
 39518     ret.regexp = new RegExp('^' + path + '$', insensitive ? 'i' : '');
       
 39519     return ret;
       
 39520   }
       
 39521 
       
 39522   /**
       
 39523    * @ngdoc method
       
 39524    * @name $routeProvider#otherwise
       
 39525    *
       
 39526    * @description
       
 39527    * Sets route definition that will be used on route change when no other route definition
       
 39528    * is matched.
       
 39529    *
       
 39530    * @param {Object|string} params Mapping information to be assigned to `$route.current`.
       
 39531    * If called with a string, the value maps to `redirectTo`.
       
 39532    * @returns {Object} self
       
 39533    */
       
 39534   this.otherwise = function(params) {
       
 39535     if (typeof params === 'string') {
       
 39536       params = {redirectTo: params};
       
 39537     }
       
 39538     this.when(null, params);
       
 39539     return this;
       
 39540   };
       
 39541 
       
 39542 
       
 39543   this.$get = ['$rootScope',
       
 39544                '$location',
       
 39545                '$routeParams',
       
 39546                '$q',
       
 39547                '$injector',
       
 39548                '$templateRequest',
       
 39549                '$sce',
       
 39550       function($rootScope, $location, $routeParams, $q, $injector, $templateRequest, $sce) {
       
 39551 
       
 39552     /**
       
 39553      * @ngdoc service
       
 39554      * @name $route
       
 39555      * @requires $location
       
 39556      * @requires $routeParams
       
 39557      *
       
 39558      * @property {Object} current Reference to the current route definition.
       
 39559      * The route definition contains:
       
 39560      *
       
 39561      *   - `controller`: The controller constructor as define in route definition.
       
 39562      *   - `locals`: A map of locals which is used by {@link ng.$controller $controller} service for
       
 39563      *     controller instantiation. The `locals` contain
       
 39564      *     the resolved values of the `resolve` map. Additionally the `locals` also contain:
       
 39565      *
       
 39566      *     - `$scope` - The current route scope.
       
 39567      *     - `$template` - The current route template HTML.
       
 39568      *
       
 39569      * @property {Object} routes Object with all route configuration Objects as its properties.
       
 39570      *
       
 39571      * @description
       
 39572      * `$route` is used for deep-linking URLs to controllers and views (HTML partials).
       
 39573      * It watches `$location.url()` and tries to map the path to an existing route definition.
       
 39574      *
       
 39575      * Requires the {@link ngRoute `ngRoute`} module to be installed.
       
 39576      *
       
 39577      * You can define routes through {@link ngRoute.$routeProvider $routeProvider}'s API.
       
 39578      *
       
 39579      * The `$route` service is typically used in conjunction with the
       
 39580      * {@link ngRoute.directive:ngView `ngView`} directive and the
       
 39581      * {@link ngRoute.$routeParams `$routeParams`} service.
       
 39582      *
       
 39583      * @example
       
 39584      * This example shows how changing the URL hash causes the `$route` to match a route against the
       
 39585      * URL, and the `ngView` pulls in the partial.
       
 39586      *
       
 39587      * <example name="$route-service" module="ngRouteExample"
       
 39588      *          deps="angular-route.js" fixBase="true">
       
 39589      *   <file name="index.html">
       
 39590      *     <div ng-controller="MainController">
       
 39591      *       Choose:
       
 39592      *       <a href="Book/Moby">Moby</a> |
       
 39593      *       <a href="Book/Moby/ch/1">Moby: Ch1</a> |
       
 39594      *       <a href="Book/Gatsby">Gatsby</a> |
       
 39595      *       <a href="Book/Gatsby/ch/4?key=value">Gatsby: Ch4</a> |
       
 39596      *       <a href="Book/Scarlet">Scarlet Letter</a><br/>
       
 39597      *
       
 39598      *       <div ng-view></div>
       
 39599      *
       
 39600      *       <hr />
       
 39601      *
       
 39602      *       <pre>$location.path() = {{$location.path()}}</pre>
       
 39603      *       <pre>$route.current.templateUrl = {{$route.current.templateUrl}}</pre>
       
 39604      *       <pre>$route.current.params = {{$route.current.params}}</pre>
       
 39605      *       <pre>$route.current.scope.name = {{$route.current.scope.name}}</pre>
       
 39606      *       <pre>$routeParams = {{$routeParams}}</pre>
       
 39607      *     </div>
       
 39608      *   </file>
       
 39609      *
       
 39610      *   <file name="book.html">
       
 39611      *     controller: {{name}}<br />
       
 39612      *     Book Id: {{params.bookId}}<br />
       
 39613      *   </file>
       
 39614      *
       
 39615      *   <file name="chapter.html">
       
 39616      *     controller: {{name}}<br />
       
 39617      *     Book Id: {{params.bookId}}<br />
       
 39618      *     Chapter Id: {{params.chapterId}}
       
 39619      *   </file>
       
 39620      *
       
 39621      *   <file name="script.js">
       
 39622      *     angular.module('ngRouteExample', ['ngRoute'])
       
 39623      *
       
 39624      *      .controller('MainController', function($scope, $route, $routeParams, $location) {
       
 39625      *          $scope.$route = $route;
       
 39626      *          $scope.$location = $location;
       
 39627      *          $scope.$routeParams = $routeParams;
       
 39628      *      })
       
 39629      *
       
 39630      *      .controller('BookController', function($scope, $routeParams) {
       
 39631      *          $scope.name = "BookController";
       
 39632      *          $scope.params = $routeParams;
       
 39633      *      })
       
 39634      *
       
 39635      *      .controller('ChapterController', function($scope, $routeParams) {
       
 39636      *          $scope.name = "ChapterController";
       
 39637      *          $scope.params = $routeParams;
       
 39638      *      })
       
 39639      *
       
 39640      *     .config(function($routeProvider, $locationProvider) {
       
 39641      *       $routeProvider
       
 39642      *        .when('/Book/:bookId', {
       
 39643      *         templateUrl: 'book.html',
       
 39644      *         controller: 'BookController',
       
 39645      *         resolve: {
       
 39646      *           // I will cause a 1 second delay
       
 39647      *           delay: function($q, $timeout) {
       
 39648      *             var delay = $q.defer();
       
 39649      *             $timeout(delay.resolve, 1000);
       
 39650      *             return delay.promise;
       
 39651      *           }
       
 39652      *         }
       
 39653      *       })
       
 39654      *       .when('/Book/:bookId/ch/:chapterId', {
       
 39655      *         templateUrl: 'chapter.html',
       
 39656      *         controller: 'ChapterController'
       
 39657      *       });
       
 39658      *
       
 39659      *       // configure html5 to get links working on jsfiddle
       
 39660      *       $locationProvider.html5Mode(true);
       
 39661      *     });
       
 39662      *
       
 39663      *   </file>
       
 39664      *
       
 39665      *   <file name="protractor.js" type="protractor">
       
 39666      *     it('should load and compile correct template', function() {
       
 39667      *       element(by.linkText('Moby: Ch1')).click();
       
 39668      *       var content = element(by.css('[ng-view]')).getText();
       
 39669      *       expect(content).toMatch(/controller\: ChapterController/);
       
 39670      *       expect(content).toMatch(/Book Id\: Moby/);
       
 39671      *       expect(content).toMatch(/Chapter Id\: 1/);
       
 39672      *
       
 39673      *       element(by.partialLinkText('Scarlet')).click();
       
 39674      *
       
 39675      *       content = element(by.css('[ng-view]')).getText();
       
 39676      *       expect(content).toMatch(/controller\: BookController/);
       
 39677      *       expect(content).toMatch(/Book Id\: Scarlet/);
       
 39678      *     });
       
 39679      *   </file>
       
 39680      * </example>
       
 39681      */
       
 39682 
       
 39683     /**
       
 39684      * @ngdoc event
       
 39685      * @name $route#$routeChangeStart
       
 39686      * @eventType broadcast on root scope
       
 39687      * @description
       
 39688      * Broadcasted before a route change. At this  point the route services starts
       
 39689      * resolving all of the dependencies needed for the route change to occur.
       
 39690      * Typically this involves fetching the view template as well as any dependencies
       
 39691      * defined in `resolve` route property. Once  all of the dependencies are resolved
       
 39692      * `$routeChangeSuccess` is fired.
       
 39693      *
       
 39694      * The route change (and the `$location` change that triggered it) can be prevented
       
 39695      * by calling `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on}
       
 39696      * for more details about event object.
       
 39697      *
       
 39698      * @param {Object} angularEvent Synthetic event object.
       
 39699      * @param {Route} next Future route information.
       
 39700      * @param {Route} current Current route information.
       
 39701      */
       
 39702 
       
 39703     /**
       
 39704      * @ngdoc event
       
 39705      * @name $route#$routeChangeSuccess
       
 39706      * @eventType broadcast on root scope
       
 39707      * @description
       
 39708      * Broadcasted after a route dependencies are resolved.
       
 39709      * {@link ngRoute.directive:ngView ngView} listens for the directive
       
 39710      * to instantiate the controller and render the view.
       
 39711      *
       
 39712      * @param {Object} angularEvent Synthetic event object.
       
 39713      * @param {Route} current Current route information.
       
 39714      * @param {Route|Undefined} previous Previous route information, or undefined if current is
       
 39715      * first route entered.
       
 39716      */
       
 39717 
       
 39718     /**
       
 39719      * @ngdoc event
       
 39720      * @name $route#$routeChangeError
       
 39721      * @eventType broadcast on root scope
       
 39722      * @description
       
 39723      * Broadcasted if any of the resolve promises are rejected.
       
 39724      *
       
 39725      * @param {Object} angularEvent Synthetic event object
       
 39726      * @param {Route} current Current route information.
       
 39727      * @param {Route} previous Previous route information.
       
 39728      * @param {Route} rejection Rejection of the promise. Usually the error of the failed promise.
       
 39729      */
       
 39730 
       
 39731     /**
       
 39732      * @ngdoc event
       
 39733      * @name $route#$routeUpdate
       
 39734      * @eventType broadcast on root scope
       
 39735      * @description
       
 39736      *
       
 39737      * The `reloadOnSearch` property has been set to false, and we are reusing the same
       
 39738      * instance of the Controller.
       
 39739      */
       
 39740 
       
 39741     var forceReload = false,
       
 39742         preparedRoute,
       
 39743         preparedRouteIsUpdateOnly,
       
 39744         $route = {
       
 39745           routes: routes,
       
 39746 
       
 39747           /**
       
 39748            * @ngdoc method
       
 39749            * @name $route#reload
       
 39750            *
       
 39751            * @description
       
 39752            * Causes `$route` service to reload the current route even if
       
 39753            * {@link ng.$location $location} hasn't changed.
       
 39754            *
       
 39755            * As a result of that, {@link ngRoute.directive:ngView ngView}
       
 39756            * creates new scope, reinstantiates the controller.
       
 39757            */
       
 39758           reload: function() {
       
 39759             forceReload = true;
       
 39760             $rootScope.$evalAsync(function() {
       
 39761               // Don't support cancellation of a reload for now...
       
 39762               prepareRoute();
       
 39763               commitRoute();
       
 39764             });
       
 39765           },
       
 39766 
       
 39767           /**
       
 39768            * @ngdoc method
       
 39769            * @name $route#updateParams
       
 39770            *
       
 39771            * @description
       
 39772            * Causes `$route` service to update the current URL, replacing
       
 39773            * current route parameters with those specified in `newParams`.
       
 39774            * Provided property names that match the route's path segment
       
 39775            * definitions will be interpolated into the location's path, while
       
 39776            * remaining properties will be treated as query params.
       
 39777            *
       
 39778            * @param {Object} newParams mapping of URL parameter names to values
       
 39779            */
       
 39780           updateParams: function(newParams) {
       
 39781             if (this.current && this.current.$$route) {
       
 39782               var searchParams = {}, self=this;
       
 39783 
       
 39784               angular.forEach(Object.keys(newParams), function(key) {
       
 39785                 if (!self.current.pathParams[key]) searchParams[key] = newParams[key];
       
 39786               });
       
 39787 
       
 39788               newParams = angular.extend({}, this.current.params, newParams);
       
 39789               $location.path(interpolate(this.current.$$route.originalPath, newParams));
       
 39790               $location.search(angular.extend({}, $location.search(), searchParams));
       
 39791             }
       
 39792             else {
       
 39793               throw $routeMinErr('norout', 'Tried updating route when with no current route');
       
 39794             }
       
 39795           }
       
 39796         };
       
 39797 
       
 39798     $rootScope.$on('$locationChangeStart', prepareRoute);
       
 39799     $rootScope.$on('$locationChangeSuccess', commitRoute);
       
 39800 
       
 39801     return $route;
       
 39802 
       
 39803     /////////////////////////////////////////////////////
       
 39804 
       
 39805     /**
       
 39806      * @param on {string} current url
       
 39807      * @param route {Object} route regexp to match the url against
       
 39808      * @return {?Object}
       
 39809      *
       
 39810      * @description
       
 39811      * Check if the route matches the current url.
       
 39812      *
       
 39813      * Inspired by match in
       
 39814      * visionmedia/express/lib/router/router.js.
       
 39815      */
       
 39816     function switchRouteMatcher(on, route) {
       
 39817       var keys = route.keys,
       
 39818           params = {};
       
 39819 
       
 39820       if (!route.regexp) return null;
       
 39821 
       
 39822       var m = route.regexp.exec(on);
       
 39823       if (!m) return null;
       
 39824 
       
 39825       for (var i = 1, len = m.length; i < len; ++i) {
       
 39826         var key = keys[i - 1];
       
 39827 
       
 39828         var val = m[i];
       
 39829 
       
 39830         if (key && val) {
       
 39831           params[key.name] = val;
       
 39832         }
       
 39833       }
       
 39834       return params;
       
 39835     }
       
 39836 
       
 39837     function prepareRoute($locationEvent) {
       
 39838       var lastRoute = $route.current;
       
 39839 
       
 39840       preparedRoute = parseRoute();
       
 39841       preparedRouteIsUpdateOnly = preparedRoute && lastRoute && preparedRoute.$$route === lastRoute.$$route
       
 39842           && angular.equals(preparedRoute.pathParams, lastRoute.pathParams)
       
 39843           && !preparedRoute.reloadOnSearch && !forceReload;
       
 39844 
       
 39845       if (!preparedRouteIsUpdateOnly && (lastRoute || preparedRoute)) {
       
 39846         if ($rootScope.$broadcast('$routeChangeStart', preparedRoute, lastRoute).defaultPrevented) {
       
 39847           if ($locationEvent) {
       
 39848             $locationEvent.preventDefault();
       
 39849           }
       
 39850         }
       
 39851       }
       
 39852     }
       
 39853 
       
 39854     function commitRoute() {
       
 39855       var lastRoute = $route.current;
       
 39856       var nextRoute = preparedRoute;
       
 39857 
       
 39858       if (preparedRouteIsUpdateOnly) {
       
 39859         lastRoute.params = nextRoute.params;
       
 39860         angular.copy(lastRoute.params, $routeParams);
       
 39861         $rootScope.$broadcast('$routeUpdate', lastRoute);
       
 39862       } else if (nextRoute || lastRoute) {
       
 39863         forceReload = false;
       
 39864         $route.current = nextRoute;
       
 39865         if (nextRoute) {
       
 39866           if (nextRoute.redirectTo) {
       
 39867             if (angular.isString(nextRoute.redirectTo)) {
       
 39868               $location.path(interpolate(nextRoute.redirectTo, nextRoute.params)).search(nextRoute.params)
       
 39869                        .replace();
       
 39870             } else {
       
 39871               $location.url(nextRoute.redirectTo(nextRoute.pathParams, $location.path(), $location.search()))
       
 39872                        .replace();
       
 39873             }
       
 39874           }
       
 39875         }
       
 39876 
       
 39877         $q.when(nextRoute).
       
 39878           then(function() {
       
 39879             if (nextRoute) {
       
 39880               var locals = angular.extend({}, nextRoute.resolve),
       
 39881                   template, templateUrl;
       
 39882 
       
 39883               angular.forEach(locals, function(value, key) {
       
 39884                 locals[key] = angular.isString(value) ?
       
 39885                     $injector.get(value) : $injector.invoke(value, null, null, key);
       
 39886               });
       
 39887 
       
 39888               if (angular.isDefined(template = nextRoute.template)) {
       
 39889                 if (angular.isFunction(template)) {
       
 39890                   template = template(nextRoute.params);
       
 39891                 }
       
 39892               } else if (angular.isDefined(templateUrl = nextRoute.templateUrl)) {
       
 39893                 if (angular.isFunction(templateUrl)) {
       
 39894                   templateUrl = templateUrl(nextRoute.params);
       
 39895                 }
       
 39896                 templateUrl = $sce.getTrustedResourceUrl(templateUrl);
       
 39897                 if (angular.isDefined(templateUrl)) {
       
 39898                   nextRoute.loadedTemplateUrl = templateUrl;
       
 39899                   template = $templateRequest(templateUrl);
       
 39900                 }
       
 39901               }
       
 39902               if (angular.isDefined(template)) {
       
 39903                 locals['$template'] = template;
       
 39904               }
       
 39905               return $q.all(locals);
       
 39906             }
       
 39907           }).
       
 39908           // after route change
       
 39909           then(function(locals) {
       
 39910             if (nextRoute == $route.current) {
       
 39911               if (nextRoute) {
       
 39912                 nextRoute.locals = locals;
       
 39913                 angular.copy(nextRoute.params, $routeParams);
       
 39914               }
       
 39915               $rootScope.$broadcast('$routeChangeSuccess', nextRoute, lastRoute);
       
 39916             }
       
 39917           }, function(error) {
       
 39918             if (nextRoute == $route.current) {
       
 39919               $rootScope.$broadcast('$routeChangeError', nextRoute, lastRoute, error);
       
 39920             }
       
 39921           });
       
 39922       }
       
 39923     }
       
 39924 
       
 39925 
       
 39926     /**
       
 39927      * @returns {Object} the current active route, by matching it against the URL
       
 39928      */
       
 39929     function parseRoute() {
       
 39930       // Match a route
       
 39931       var params, match;
       
 39932       angular.forEach(routes, function(route, path) {
       
 39933         if (!match && (params = switchRouteMatcher($location.path(), route))) {
       
 39934           match = inherit(route, {
       
 39935             params: angular.extend({}, $location.search(), params),
       
 39936             pathParams: params});
       
 39937           match.$$route = route;
       
 39938         }
       
 39939       });
       
 39940       // No route matched; fallback to "otherwise" route
       
 39941       return match || routes[null] && inherit(routes[null], {params: {}, pathParams:{}});
       
 39942     }
       
 39943 
       
 39944     /**
       
 39945      * @returns {string} interpolation of the redirect path with the parameters
       
 39946      */
       
 39947     function interpolate(string, params) {
       
 39948       var result = [];
       
 39949       angular.forEach((string||'').split(':'), function(segment, i) {
       
 39950         if (i === 0) {
       
 39951           result.push(segment);
       
 39952         } else {
       
 39953           var segmentMatch = segment.match(/(\w+)(.*)/);
       
 39954           var key = segmentMatch[1];
       
 39955           result.push(params[key]);
       
 39956           result.push(segmentMatch[2] || '');
       
 39957           delete params[key];
       
 39958         }
       
 39959       });
       
 39960       return result.join('');
       
 39961     }
       
 39962   }];
       
 39963 }
       
 39964 
       
 39965 ngRouteModule.provider('$routeParams', $RouteParamsProvider);
       
 39966 
       
 39967 
       
 39968 /**
       
 39969  * @ngdoc service
       
 39970  * @name $routeParams
       
 39971  * @requires $route
       
 39972  *
       
 39973  * @description
       
 39974  * The `$routeParams` service allows you to retrieve the current set of route parameters.
       
 39975  *
       
 39976  * Requires the {@link ngRoute `ngRoute`} module to be installed.
       
 39977  *
       
 39978  * The route parameters are a combination of {@link ng.$location `$location`}'s
       
 39979  * {@link ng.$location#search `search()`} and {@link ng.$location#path `path()`}.
       
 39980  * The `path` parameters are extracted when the {@link ngRoute.$route `$route`} path is matched.
       
 39981  *
       
 39982  * In case of parameter name collision, `path` params take precedence over `search` params.
       
 39983  *
       
 39984  * The service guarantees that the identity of the `$routeParams` object will remain unchanged
       
 39985  * (but its properties will likely change) even when a route change occurs.
       
 39986  *
       
 39987  * Note that the `$routeParams` are only updated *after* a route change completes successfully.
       
 39988  * This means that you cannot rely on `$routeParams` being correct in route resolve functions.
       
 39989  * Instead you can use `$route.current.params` to access the new route's parameters.
       
 39990  *
       
 39991  * @example
       
 39992  * ```js
       
 39993  *  // Given:
       
 39994  *  // URL: http://server.com/index.html#/Chapter/1/Section/2?search=moby
       
 39995  *  // Route: /Chapter/:chapterId/Section/:sectionId
       
 39996  *  //
       
 39997  *  // Then
       
 39998  *  $routeParams ==> {chapterId:'1', sectionId:'2', search:'moby'}
       
 39999  * ```
       
 40000  */
       
 40001 function $RouteParamsProvider() {
       
 40002   this.$get = function() { return {}; };
       
 40003 }
       
 40004 
       
 40005 ngRouteModule.directive('ngView', ngViewFactory);
       
 40006 ngRouteModule.directive('ngView', ngViewFillContentFactory);
       
 40007 
       
 40008 
       
 40009 /**
       
 40010  * @ngdoc directive
       
 40011  * @name ngView
       
 40012  * @restrict ECA
       
 40013  *
       
 40014  * @description
       
 40015  * # Overview
       
 40016  * `ngView` is a directive that complements the {@link ngRoute.$route $route} service by
       
 40017  * including the rendered template of the current route into the main layout (`index.html`) file.
       
 40018  * Every time the current route changes, the included view changes with it according to the
       
 40019  * configuration of the `$route` service.
       
 40020  *
       
 40021  * Requires the {@link ngRoute `ngRoute`} module to be installed.
       
 40022  *
       
 40023  * @animations
       
 40024  * enter - animation is used to bring new content into the browser.
       
 40025  * leave - animation is used to animate existing content away.
       
 40026  *
       
 40027  * The enter and leave animation occur concurrently.
       
 40028  *
       
 40029  * @scope
       
 40030  * @priority 400
       
 40031  * @param {string=} onload Expression to evaluate whenever the view updates.
       
 40032  *
       
 40033  * @param {string=} autoscroll Whether `ngView` should call {@link ng.$anchorScroll
       
 40034  *                  $anchorScroll} to scroll the viewport after the view is updated.
       
 40035  *
       
 40036  *                  - If the attribute is not set, disable scrolling.
       
 40037  *                  - If the attribute is set without value, enable scrolling.
       
 40038  *                  - Otherwise enable scrolling only if the `autoscroll` attribute value evaluated
       
 40039  *                    as an expression yields a truthy value.
       
 40040  * @example
       
 40041     <example name="ngView-directive" module="ngViewExample"
       
 40042              deps="angular-route.js;angular-animate.js"
       
 40043              animations="true" fixBase="true">
       
 40044       <file name="index.html">
       
 40045         <div ng-controller="MainCtrl as main">
       
 40046           Choose:
       
 40047           <a href="Book/Moby">Moby</a> |
       
 40048           <a href="Book/Moby/ch/1">Moby: Ch1</a> |
       
 40049           <a href="Book/Gatsby">Gatsby</a> |
       
 40050           <a href="Book/Gatsby/ch/4?key=value">Gatsby: Ch4</a> |
       
 40051           <a href="Book/Scarlet">Scarlet Letter</a><br/>
       
 40052 
       
 40053           <div class="view-animate-container">
       
 40054             <div ng-view class="view-animate"></div>
       
 40055           </div>
       
 40056           <hr />
       
 40057 
       
 40058           <pre>$location.path() = {{main.$location.path()}}</pre>
       
 40059           <pre>$route.current.templateUrl = {{main.$route.current.templateUrl}}</pre>
       
 40060           <pre>$route.current.params = {{main.$route.current.params}}</pre>
       
 40061           <pre>$routeParams = {{main.$routeParams}}</pre>
       
 40062         </div>
       
 40063       </file>
       
 40064 
       
 40065       <file name="book.html">
       
 40066         <div>
       
 40067           controller: {{book.name}}<br />
       
 40068           Book Id: {{book.params.bookId}}<br />
       
 40069         </div>
       
 40070       </file>
       
 40071 
       
 40072       <file name="chapter.html">
       
 40073         <div>
       
 40074           controller: {{chapter.name}}<br />
       
 40075           Book Id: {{chapter.params.bookId}}<br />
       
 40076           Chapter Id: {{chapter.params.chapterId}}
       
 40077         </div>
       
 40078       </file>
       
 40079 
       
 40080       <file name="animations.css">
       
 40081         .view-animate-container {
       
 40082           position:relative;
       
 40083           height:100px!important;
       
 40084           position:relative;
       
 40085           background:white;
       
 40086           border:1px solid black;
       
 40087           height:40px;
       
 40088           overflow:hidden;
       
 40089         }
       
 40090 
       
 40091         .view-animate {
       
 40092           padding:10px;
       
 40093         }
       
 40094 
       
 40095         .view-animate.ng-enter, .view-animate.ng-leave {
       
 40096           -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s;
       
 40097           transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 1.5s;
       
 40098 
       
 40099           display:block;
       
 40100           width:100%;
       
 40101           border-left:1px solid black;
       
 40102 
       
 40103           position:absolute;
       
 40104           top:0;
       
 40105           left:0;
       
 40106           right:0;
       
 40107           bottom:0;
       
 40108           padding:10px;
       
 40109         }
       
 40110 
       
 40111         .view-animate.ng-enter {
       
 40112           left:100%;
       
 40113         }
       
 40114         .view-animate.ng-enter.ng-enter-active {
       
 40115           left:0;
       
 40116         }
       
 40117         .view-animate.ng-leave.ng-leave-active {
       
 40118           left:-100%;
       
 40119         }
       
 40120       </file>
       
 40121 
       
 40122       <file name="script.js">
       
 40123         angular.module('ngViewExample', ['ngRoute', 'ngAnimate'])
       
 40124           .config(['$routeProvider', '$locationProvider',
       
 40125             function($routeProvider, $locationProvider) {
       
 40126               $routeProvider
       
 40127                 .when('/Book/:bookId', {
       
 40128                   templateUrl: 'book.html',
       
 40129                   controller: 'BookCtrl',
       
 40130                   controllerAs: 'book'
       
 40131                 })
       
 40132                 .when('/Book/:bookId/ch/:chapterId', {
       
 40133                   templateUrl: 'chapter.html',
       
 40134                   controller: 'ChapterCtrl',
       
 40135                   controllerAs: 'chapter'
       
 40136                 });
       
 40137 
       
 40138               $locationProvider.html5Mode(true);
       
 40139           }])
       
 40140           .controller('MainCtrl', ['$route', '$routeParams', '$location',
       
 40141             function($route, $routeParams, $location) {
       
 40142               this.$route = $route;
       
 40143               this.$location = $location;
       
 40144               this.$routeParams = $routeParams;
       
 40145           }])
       
 40146           .controller('BookCtrl', ['$routeParams', function($routeParams) {
       
 40147             this.name = "BookCtrl";
       
 40148             this.params = $routeParams;
       
 40149           }])
       
 40150           .controller('ChapterCtrl', ['$routeParams', function($routeParams) {
       
 40151             this.name = "ChapterCtrl";
       
 40152             this.params = $routeParams;
       
 40153           }]);
       
 40154 
       
 40155       </file>
       
 40156 
       
 40157       <file name="protractor.js" type="protractor">
       
 40158         it('should load and compile correct template', function() {
       
 40159           element(by.linkText('Moby: Ch1')).click();
       
 40160           var content = element(by.css('[ng-view]')).getText();
       
 40161           expect(content).toMatch(/controller\: ChapterCtrl/);
       
 40162           expect(content).toMatch(/Book Id\: Moby/);
       
 40163           expect(content).toMatch(/Chapter Id\: 1/);
       
 40164 
       
 40165           element(by.partialLinkText('Scarlet')).click();
       
 40166 
       
 40167           content = element(by.css('[ng-view]')).getText();
       
 40168           expect(content).toMatch(/controller\: BookCtrl/);
       
 40169           expect(content).toMatch(/Book Id\: Scarlet/);
       
 40170         });
       
 40171       </file>
       
 40172     </example>
       
 40173  */
       
 40174 
       
 40175 
       
 40176 /**
       
 40177  * @ngdoc event
       
 40178  * @name ngView#$viewContentLoaded
       
 40179  * @eventType emit on the current ngView scope
       
 40180  * @description
       
 40181  * Emitted every time the ngView content is reloaded.
       
 40182  */
       
 40183 ngViewFactory.$inject = ['$route', '$anchorScroll', '$animate'];
       
 40184 function ngViewFactory(   $route,   $anchorScroll,   $animate) {
       
 40185   return {
       
 40186     restrict: 'ECA',
       
 40187     terminal: true,
       
 40188     priority: 400,
       
 40189     transclude: 'element',
       
 40190     link: function(scope, $element, attr, ctrl, $transclude) {
       
 40191         var currentScope,
       
 40192             currentElement,
       
 40193             previousLeaveAnimation,
       
 40194             autoScrollExp = attr.autoscroll,
       
 40195             onloadExp = attr.onload || '';
       
 40196 
       
 40197         scope.$on('$routeChangeSuccess', update);
       
 40198         update();
       
 40199 
       
 40200         function cleanupLastView() {
       
 40201           if(previousLeaveAnimation) {
       
 40202             $animate.cancel(previousLeaveAnimation);
       
 40203             previousLeaveAnimation = null;
       
 40204           }
       
 40205 
       
 40206           if(currentScope) {
       
 40207             currentScope.$destroy();
       
 40208             currentScope = null;
       
 40209           }
       
 40210           if(currentElement) {
       
 40211             previousLeaveAnimation = $animate.leave(currentElement);
       
 40212             previousLeaveAnimation.then(function() {
       
 40213               previousLeaveAnimation = null;
       
 40214             });
       
 40215             currentElement = null;
       
 40216           }
       
 40217         }
       
 40218 
       
 40219         function update() {
       
 40220           var locals = $route.current && $route.current.locals,
       
 40221               template = locals && locals.$template;
       
 40222 
       
 40223           if (angular.isDefined(template)) {
       
 40224             var newScope = scope.$new();
       
 40225             var current = $route.current;
       
 40226 
       
 40227             // Note: This will also link all children of ng-view that were contained in the original
       
 40228             // html. If that content contains controllers, ... they could pollute/change the scope.
       
 40229             // However, using ng-view on an element with additional content does not make sense...
       
 40230             // Note: We can't remove them in the cloneAttchFn of $transclude as that
       
 40231             // function is called before linking the content, which would apply child
       
 40232             // directives to non existing elements.
       
 40233             var clone = $transclude(newScope, function(clone) {
       
 40234               $animate.enter(clone, null, currentElement || $element).then(function onNgViewEnter () {
       
 40235                 if (angular.isDefined(autoScrollExp)
       
 40236                   && (!autoScrollExp || scope.$eval(autoScrollExp))) {
       
 40237                   $anchorScroll();
       
 40238                 }
       
 40239               });
       
 40240               cleanupLastView();
       
 40241             });
       
 40242 
       
 40243             currentElement = clone;
       
 40244             currentScope = current.scope = newScope;
       
 40245             currentScope.$emit('$viewContentLoaded');
       
 40246             currentScope.$eval(onloadExp);
       
 40247           } else {
       
 40248             cleanupLastView();
       
 40249           }
       
 40250         }
       
 40251     }
       
 40252   };
       
 40253 }
       
 40254 
       
 40255 // This directive is called during the $transclude call of the first `ngView` directive.
       
 40256 // It will replace and compile the content of the element with the loaded template.
       
 40257 // We need this directive so that the element content is already filled when
       
 40258 // the link function of another directive on the same element as ngView
       
 40259 // is called.
       
 40260 ngViewFillContentFactory.$inject = ['$compile', '$controller', '$route'];
       
 40261 function ngViewFillContentFactory($compile, $controller, $route) {
       
 40262   return {
       
 40263     restrict: 'ECA',
       
 40264     priority: -400,
       
 40265     link: function(scope, $element) {
       
 40266       var current = $route.current,
       
 40267           locals = current.locals;
       
 40268 
       
 40269       $element.html(locals.$template);
       
 40270 
       
 40271       var link = $compile($element.contents());
       
 40272 
       
 40273       if (current.controller) {
       
 40274         locals.$scope = scope;
       
 40275         var controller = $controller(current.controller, locals);
       
 40276         if (current.controllerAs) {
       
 40277           scope[current.controllerAs] = controller;
       
 40278         }
       
 40279         $element.data('$ngControllerController', controller);
       
 40280         $element.children().data('$ngControllerController', controller);
       
 40281       }
       
 40282 
       
 40283       link(scope);
       
 40284     }
       
 40285   };
       
 40286 }
       
 40287 
       
 40288 
       
 40289 })(window, window.angular);
       
 40290 
       
 40291 var app = angular.module('app', ['autocomplete']);
       
 40292 
       
 40293 // the service that retrieves some movie title from an url
       
 40294 app.factory('MovieRetriever', function($http, $q, $timeout){
       
 40295   var MovieRetriever = new Object();
       
 40296 
       
 40297   MovieRetriever.getmovies = function(i) {
       
 40298     var moviedata = $q.defer();
       
 40299     var movies;
       
 40300 
       
 40301     var someMovies = ["The Wolverine", "The Smurfs 2", "The Mortal Instruments: City of Bones", "Drinking Buddies", "All the Boys Love Mandy Lane", "The Act Of Killing", "Red 2", "Jobs", "Getaway", "Red Obsession", "2 Guns", "The World's End", "Planes", "Paranoia", "The To Do List", "Man of Steel"];
       
 40302 
       
 40303     var moreMovies = ["The Wolverine", "The Smurfs 2", "The Mortal Instruments: City of Bones", "Drinking Buddies", "All the Boys Love Mandy Lane", "The Act Of Killing", "Red 2", "Jobs", "Getaway", "Red Obsession", "2 Guns", "The World's End", "Planes", "Paranoia", "The To Do List", "Man of Steel", "The Way Way Back", "Before Midnight", "Only God Forgives", "I Give It a Year", "The Heat", "Pacific Rim", "Pacific Rim", "Kevin Hart: Let Me Explain", "A Hijacking", "Maniac", "After Earth", "The Purge", "Much Ado About Nothing", "Europa Report", "Stuck in Love", "We Steal Secrets: The Story Of Wikileaks", "The Croods", "This Is the End", "The Frozen Ground", "Turbo", "Blackfish", "Frances Ha", "Prince Avalanche", "The Attack", "Grown Ups 2", "White House Down", "Lovelace", "Girl Most Likely", "Parkland", "Passion", "Monsters University", "R.I.P.D.", "Byzantium", "The Conjuring", "The Internship"]
       
 40304 
       
 40305     if(i && i.indexOf('T')!=-1)
       
 40306       movies=moreMovies;
       
 40307     else
       
 40308       movies=moreMovies;
       
 40309 
       
 40310     $timeout(function(){
       
 40311       moviedata.resolve(movies);
       
 40312     },1000);
       
 40313 
       
 40314     return moviedata.promise
       
 40315   }
       
 40316 
       
 40317   return MovieRetriever;
       
 40318 });
       
 40319 
       
 40320 app.controller('MyCtrl', function($scope, MovieRetriever){
       
 40321 
       
 40322   $scope.movies = MovieRetriever.getmovies("...");
       
 40323   $scope.movies.then(function(data){
       
 40324     $scope.movies = data;
       
 40325   });
       
 40326 
       
 40327   $scope.getmovies = function(){
       
 40328     return $scope.movies;
       
 40329   }
       
 40330 
       
 40331   $scope.doSomething = function(typedthings){
       
 40332     console.log("Do something like reload data with this: " + typedthings );
       
 40333     $scope.newmovies = MovieRetriever.getmovies(typedthings);
       
 40334     $scope.newmovies.then(function(data){
       
 40335       $scope.movies = data;
       
 40336     });
       
 40337   }
       
 40338 
       
 40339   $scope.doSomethingElse = function(suggestion){
       
 40340     console.log("Suggestion selected: " + suggestion );
       
 40341   }
       
 40342 
       
 40343 });
       
 40344 
       
 40345 /* --- Made by justgoscha and licensed under MIT license --- */
       
 40346 
       
 40347 var app = angular.module('autocomplete', []);
       
 40348 
       
 40349 app.directive('autocomplete', function() {
       
 40350   var index = -1;
       
 40351 
       
 40352   return {
       
 40353     restrict: 'E',
       
 40354     scope: {
       
 40355       searchParam: '=ngModel',
       
 40356       suggestions: '=data',
       
 40357       onType: '=onType',
       
 40358       onSelect: '=onSelect'
       
 40359     },
       
 40360     controller: ['$scope', function($scope){
       
 40361       // the index of the suggestions that's currently selected
       
 40362       $scope.selectedIndex = -1;
       
 40363 
       
 40364       // set new index
       
 40365       $scope.setIndex = function(i){
       
 40366         $scope.selectedIndex = parseInt(i);
       
 40367       };
       
 40368 
       
 40369       this.setIndex = function(i){
       
 40370         $scope.setIndex(i);
       
 40371         $scope.$apply();
       
 40372       };
       
 40373 
       
 40374       $scope.getIndex = function(i){
       
 40375         return $scope.selectedIndex;
       
 40376       };
       
 40377 
       
 40378       // watches if the parameter filter should be changed
       
 40379       var watching = true;
       
 40380 
       
 40381       // autocompleting drop down on/off
       
 40382       $scope.completing = false;
       
 40383 
       
 40384       // starts autocompleting on typing in something
       
 40385       $scope.$watch('searchParam', function(newValue, oldValue){
       
 40386 
       
 40387         if (oldValue === newValue || !oldValue) {
       
 40388           return;
       
 40389         }
       
 40390 
       
 40391         if(watching && typeof $scope.searchParam !== 'undefined' && $scope.searchParam !== null) {
       
 40392           $scope.completing = true;
       
 40393           $scope.searchFilter = $scope.searchParam;
       
 40394           $scope.selectedIndex = -1;
       
 40395         }
       
 40396 
       
 40397         // function thats passed to on-type attribute gets executed
       
 40398         if($scope.onType)
       
 40399           $scope.onType($scope.searchParam);
       
 40400       });
       
 40401 
       
 40402       // for hovering over suggestions
       
 40403       this.preSelect = function(suggestion){
       
 40404 
       
 40405         watching = false;
       
 40406 
       
 40407         // this line determines if it is shown
       
 40408         // in the input field before it's selected:
       
 40409         //$scope.searchParam = suggestion;
       
 40410 
       
 40411         $scope.$apply();
       
 40412         watching = true;
       
 40413 
       
 40414       };
       
 40415 
       
 40416       $scope.preSelect = this.preSelect;
       
 40417 
       
 40418       this.preSelectOff = function(){
       
 40419         watching = true;
       
 40420       };
       
 40421 
       
 40422       $scope.preSelectOff = this.preSelectOff;
       
 40423 
       
 40424       // selecting a suggestion with RIGHT ARROW or ENTER
       
 40425       $scope.select = function(suggestion){
       
 40426         if(suggestion){
       
 40427           $scope.searchParam = suggestion;
       
 40428           $scope.searchFilter = suggestion;
       
 40429           if($scope.onSelect)
       
 40430             $scope.onSelect(suggestion);
       
 40431         }
       
 40432         watching = false;
       
 40433         $scope.completing = false;
       
 40434         setTimeout(function(){watching = true;},1000);
       
 40435         $scope.setIndex(-1);
       
 40436       };
       
 40437 
       
 40438 
       
 40439     }],
       
 40440     link: function(scope, element, attrs){
       
 40441 
       
 40442       var attr = '';
       
 40443 
       
 40444       // Default atts
       
 40445       scope.attrs = {
       
 40446         "placeholder": "start typing...",
       
 40447         "class": "",
       
 40448         "id": "",
       
 40449         "inputclass": "",
       
 40450         "inputid": ""
       
 40451       };
       
 40452 
       
 40453       for (var a in attrs) {
       
 40454         attr = a.replace('attr', '').toLowerCase();
       
 40455         // add attribute overriding defaults
       
 40456         // and preventing duplication
       
 40457         if (a.indexOf('attr') === 0) {
       
 40458           scope.attrs[attr] = attrs[a];
       
 40459         }
       
 40460       }
       
 40461 
       
 40462       if (attrs.clickActivation) {
       
 40463         element[0].onclick = function(e){
       
 40464           if(!scope.searchParam){
       
 40465             scope.completing = true;
       
 40466             scope.$apply();
       
 40467           }
       
 40468         };
       
 40469       }
       
 40470 
       
 40471       var key = {left: 37, up: 38, right: 39, down: 40 , enter: 13, esc: 27, tab: 9};
       
 40472 
       
 40473       document.addEventListener("keydown", function(e){
       
 40474         var keycode = e.keyCode || e.which;
       
 40475 
       
 40476         switch (keycode){
       
 40477           case key.esc:
       
 40478             // disable suggestions on escape
       
 40479             scope.select();
       
 40480             scope.setIndex(-1);
       
 40481             scope.$apply();
       
 40482             e.preventDefault();
       
 40483         }
       
 40484       }, true);
       
 40485 
       
 40486       document.addEventListener("blur", function(e){
       
 40487         // disable suggestions on blur
       
 40488         // we do a timeout to prevent hiding it before a click event is registered
       
 40489         setTimeout(function() {
       
 40490           scope.select();
       
 40491           scope.setIndex(-1);
       
 40492           scope.$apply();
       
 40493         }, 200);
       
 40494       }, true);
       
 40495 
       
 40496       element[0].addEventListener("keydown",function (e){
       
 40497         var keycode = e.keyCode || e.which;
       
 40498 
       
 40499         var l = angular.element(this).find('li').length;
       
 40500 
       
 40501         // implementation of the up and down movement in the list of suggestions
       
 40502         switch (keycode){
       
 40503           case key.up:
       
 40504 
       
 40505             index = scope.getIndex()-1;
       
 40506             if(index<-1){
       
 40507               index = l-1;
       
 40508             } else if (index >= l ){
       
 40509               index = -1;
       
 40510               scope.setIndex(index);
       
 40511               scope.preSelectOff();
       
 40512               break;
       
 40513             }
       
 40514             scope.setIndex(index);
       
 40515 
       
 40516             if(index!==-1)
       
 40517               scope.preSelect(angular.element(angular.element(this).find('li')[index]).text());
       
 40518 
       
 40519             scope.$apply();
       
 40520 
       
 40521             break;
       
 40522           case key.down:
       
 40523             index = scope.getIndex()+1;
       
 40524             if(index<-1){
       
 40525               index = l-1;
       
 40526             } else if (index >= l ){
       
 40527               index = -1;
       
 40528               scope.setIndex(index);
       
 40529               scope.preSelectOff();
       
 40530               scope.$apply();
       
 40531               break;
       
 40532             }
       
 40533             scope.setIndex(index);
       
 40534 
       
 40535             if(index!==-1)
       
 40536               scope.preSelect(angular.element(angular.element(this).find('li')[index]).text());
       
 40537 
       
 40538             break;
       
 40539           case key.left:
       
 40540             break;
       
 40541           case key.right:
       
 40542           case key.enter:
       
 40543           case key.tab:
       
 40544 
       
 40545             index = scope.getIndex();
       
 40546             // scope.preSelectOff();
       
 40547             if(index !== -1) {
       
 40548               scope.select(angular.element(angular.element(this).find('li')[index]).text());
       
 40549               if(keycode == key.enter) {
       
 40550                 e.preventDefault();
       
 40551               }
       
 40552             } else {
       
 40553               if(keycode == key.enter) {
       
 40554                 scope.select();
       
 40555               }
       
 40556             }
       
 40557             scope.setIndex(-1);
       
 40558             scope.$apply();
       
 40559 
       
 40560             break;
       
 40561           case key.esc:
       
 40562             // disable suggestions on escape
       
 40563             scope.select();
       
 40564             scope.setIndex(-1);
       
 40565             scope.$apply();
       
 40566             e.preventDefault();
       
 40567             break;
       
 40568           default:
       
 40569             return;
       
 40570         }
       
 40571 
       
 40572       });
       
 40573     },
       
 40574     template: '\
       
 40575         <div class="autocomplete {{ attrs.class }}" id="{{ attrs.id }}">\
       
 40576           <input\
       
 40577             type="text"\
       
 40578             ng-model="searchParam"\
       
 40579             placeholder="{{ attrs.placeholder }}"\
       
 40580             class="{{ attrs.inputclass }}"\
       
 40581             id="{{ attrs.inputid }}"/>\
       
 40582           <ul ng-show="completing && suggestions.length>0">\
       
 40583             <li\
       
 40584               suggestion\
       
 40585               ng-repeat="suggestion in suggestions | filter:searchFilter | orderBy:\'toString()\' track by $index"\
       
 40586               index="{{ $index }}"\
       
 40587               val="{{ suggestion }}"\
       
 40588               ng-class="{ active: ($index === selectedIndex) }"\
       
 40589               ng-click="select(suggestion)"\
       
 40590               ng-bind-html="suggestion | highlight:searchParam"></li>\
       
 40591           </ul>\
       
 40592         </div>'
       
 40593   };
       
 40594 });
       
 40595 
       
 40596 app.filter('highlight', ['$sce', function ($sce) {
       
 40597   return function (input, searchParam) {
       
 40598     if (typeof input === 'function') return '';
       
 40599     if (searchParam) {
       
 40600       var words = '(' +
       
 40601             searchParam.split(/\ /).join(' |') + '|' +
       
 40602             searchParam.split(/\ /).join('|') +
       
 40603           ')',
       
 40604           exp = new RegExp(words, 'gi');
       
 40605       if (words.length) {
       
 40606         input = input.replace(exp, "<span class=\"highlight\">$1</span>");
       
 40607       }
       
 40608     }
       
 40609     return $sce.trustAsHtml(input);
       
 40610   };
       
 40611 }]);
       
 40612 
       
 40613 app.directive('suggestion', function(){
       
 40614   return {
       
 40615     restrict: 'A',
       
 40616     require: '^autocomplete', // ^look for controller on parents element
       
 40617     link: function(scope, element, attrs, autoCtrl){
       
 40618       element.bind('mouseenter', function() {
       
 40619         autoCtrl.preSelect(attrs.val);
       
 40620         autoCtrl.setIndex(attrs.index);
       
 40621       });
       
 40622 
       
 40623       element.bind('mouseleave', function() {
       
 40624         autoCtrl.preSelectOff();
       
 40625       });
       
 40626     }
       
 40627   };
       
 40628 });
       
 40629 
       
 40630 /*
       
 40631 string.js - Copyright (C) 2012-2014, JP Richardson <jprichardson@gmail.com>
       
 40632 */
       
 40633 
       
 40634 !(function() {
       
 40635   "use strict";
       
 40636 
       
 40637   var VERSION = '2.1.0';
       
 40638 
       
 40639   var ENTITIES = {};
       
 40640 
       
 40641   // from http://semplicewebsites.com/removing-accents-javascript
       
 40642   var latin_map={"Á":"A","Ă":"A","Ắ":"A","Ặ":"A","Ằ":"A","Ẳ":"A","Ẵ":"A","Ǎ":"A","Â":"A","Ấ":"A","Ậ":"A","Ầ":"A","Ẩ":"A","Ẫ":"A","Ä":"A","Ǟ":"A","Ȧ":"A","Ǡ":"A","Ạ":"A","Ȁ":"A","À":"A","Ả":"A","Ȃ":"A","Ā":"A","Ą":"A","Å":"A","Ǻ":"A","Ḁ":"A","Ⱥ":"A","Ã":"A","Ꜳ":"AA","Æ":"AE","Ǽ":"AE","Ǣ":"AE","Ꜵ":"AO","Ꜷ":"AU","Ꜹ":"AV","Ꜻ":"AV","Ꜽ":"AY","Ḃ":"B","Ḅ":"B","Ɓ":"B","Ḇ":"B","Ƀ":"B","Ƃ":"B","Ć":"C","Č":"C","Ç":"C","Ḉ":"C","Ĉ":"C","Ċ":"C","Ƈ":"C","Ȼ":"C","Ď":"D","Ḑ":"D","Ḓ":"D","Ḋ":"D","Ḍ":"D","Ɗ":"D","Ḏ":"D","Dz":"D","Dž":"D","Đ":"D","Ƌ":"D","DZ":"DZ","DŽ":"DZ","É":"E","Ĕ":"E","Ě":"E","Ȩ":"E","Ḝ":"E","Ê":"E","Ế":"E","Ệ":"E","Ề":"E","Ể":"E","Ễ":"E","Ḙ":"E","Ë":"E","Ė":"E","Ẹ":"E","Ȅ":"E","È":"E","Ẻ":"E","Ȇ":"E","Ē":"E","Ḗ":"E","Ḕ":"E","Ę":"E","Ɇ":"E","Ẽ":"E","Ḛ":"E","Ꝫ":"ET","Ḟ":"F","Ƒ":"F","Ǵ":"G","Ğ":"G","Ǧ":"G","Ģ":"G","Ĝ":"G","Ġ":"G","Ɠ":"G","Ḡ":"G","Ǥ":"G","Ḫ":"H","Ȟ":"H","Ḩ":"H","Ĥ":"H","Ⱨ":"H","Ḧ":"H","Ḣ":"H","Ḥ":"H","Ħ":"H","Í":"I","Ĭ":"I","Ǐ":"I","Î":"I","Ï":"I","Ḯ":"I","İ":"I","Ị":"I","Ȉ":"I","Ì":"I","Ỉ":"I","Ȋ":"I","Ī":"I","Į":"I","Ɨ":"I","Ĩ":"I","Ḭ":"I","Ꝺ":"D","Ꝼ":"F","Ᵹ":"G","Ꞃ":"R","Ꞅ":"S","Ꞇ":"T","Ꝭ":"IS","Ĵ":"J","Ɉ":"J","Ḱ":"K","Ǩ":"K","Ķ":"K","Ⱪ":"K","Ꝃ":"K","Ḳ":"K","Ƙ":"K","Ḵ":"K","Ꝁ":"K","Ꝅ":"K","Ĺ":"L","Ƚ":"L","Ľ":"L","Ļ":"L","Ḽ":"L","Ḷ":"L","Ḹ":"L","Ⱡ":"L","Ꝉ":"L","Ḻ":"L","Ŀ":"L","Ɫ":"L","Lj":"L","Ł":"L","LJ":"LJ","Ḿ":"M","Ṁ":"M","Ṃ":"M","Ɱ":"M","Ń":"N","Ň":"N","Ņ":"N","Ṋ":"N","Ṅ":"N","Ṇ":"N","Ǹ":"N","Ɲ":"N","Ṉ":"N","Ƞ":"N","Nj":"N","Ñ":"N","NJ":"NJ","Ó":"O","Ŏ":"O","Ǒ":"O","Ô":"O","Ố":"O","Ộ":"O","Ồ":"O","Ổ":"O","Ỗ":"O","Ö":"O","Ȫ":"O","Ȯ":"O","Ȱ":"O","Ọ":"O","Ő":"O","Ȍ":"O","Ò":"O","Ỏ":"O","Ơ":"O","Ớ":"O","Ợ":"O","Ờ":"O","Ở":"O","Ỡ":"O","Ȏ":"O","Ꝋ":"O","Ꝍ":"O","Ō":"O","Ṓ":"O","Ṑ":"O","Ɵ":"O","Ǫ":"O","Ǭ":"O","Ø":"O","Ǿ":"O","Õ":"O","Ṍ":"O","Ṏ":"O","Ȭ":"O","Ƣ":"OI","Ꝏ":"OO","Ɛ":"E","Ɔ":"O","Ȣ":"OU","Ṕ":"P","Ṗ":"P","Ꝓ":"P","Ƥ":"P","Ꝕ":"P","Ᵽ":"P","Ꝑ":"P","Ꝙ":"Q","Ꝗ":"Q","Ŕ":"R","Ř":"R","Ŗ":"R","Ṙ":"R","Ṛ":"R","Ṝ":"R","Ȑ":"R","Ȓ":"R","Ṟ":"R","Ɍ":"R","Ɽ":"R","Ꜿ":"C","Ǝ":"E","Ś":"S","Ṥ":"S","Š":"S","Ṧ":"S","Ş":"S","Ŝ":"S","Ș":"S","Ṡ":"S","Ṣ":"S","Ṩ":"S","ẞ":"SS","Ť":"T","Ţ":"T","Ṱ":"T","Ț":"T","Ⱦ":"T","Ṫ":"T","Ṭ":"T","Ƭ":"T","Ṯ":"T","Ʈ":"T","Ŧ":"T","Ɐ":"A","Ꞁ":"L","Ɯ":"M","Ʌ":"V","Ꜩ":"TZ","Ú":"U","Ŭ":"U","Ǔ":"U","Û":"U","Ṷ":"U","Ü":"U","Ǘ":"U","Ǚ":"U","Ǜ":"U","Ǖ":"U","Ṳ":"U","Ụ":"U","Ű":"U","Ȕ":"U","Ù":"U","Ủ":"U","Ư":"U","Ứ":"U","Ự":"U","Ừ":"U","Ử":"U","Ữ":"U","Ȗ":"U","Ū":"U","Ṻ":"U","Ų":"U","Ů":"U","Ũ":"U","Ṹ":"U","Ṵ":"U","Ꝟ":"V","Ṿ":"V","Ʋ":"V","Ṽ":"V","Ꝡ":"VY","Ẃ":"W","Ŵ":"W","Ẅ":"W","Ẇ":"W","Ẉ":"W","Ẁ":"W","Ⱳ":"W","Ẍ":"X","Ẋ":"X","Ý":"Y","Ŷ":"Y","Ÿ":"Y","Ẏ":"Y","Ỵ":"Y","Ỳ":"Y","Ƴ":"Y","Ỷ":"Y","Ỿ":"Y","Ȳ":"Y","Ɏ":"Y","Ỹ":"Y","Ź":"Z","Ž":"Z","Ẑ":"Z","Ⱬ":"Z","Ż":"Z","Ẓ":"Z","Ȥ":"Z","Ẕ":"Z","Ƶ":"Z","IJ":"IJ","Œ":"OE","ᴀ":"A","ᴁ":"AE","ʙ":"B","ᴃ":"B","ᴄ":"C","ᴅ":"D","ᴇ":"E","ꜰ":"F","ɢ":"G","ʛ":"G","ʜ":"H","ɪ":"I","ʁ":"R","ᴊ":"J","ᴋ":"K","ʟ":"L","ᴌ":"L","ᴍ":"M","ɴ":"N","ᴏ":"O","ɶ":"OE","ᴐ":"O","ᴕ":"OU","ᴘ":"P","ʀ":"R","ᴎ":"N","ᴙ":"R","ꜱ":"S","ᴛ":"T","ⱻ":"E","ᴚ":"R","ᴜ":"U","ᴠ":"V","ᴡ":"W","ʏ":"Y","ᴢ":"Z","á":"a","ă":"a","ắ":"a","ặ":"a","ằ":"a","ẳ":"a","ẵ":"a","ǎ":"a","â":"a","ấ":"a","ậ":"a","ầ":"a","ẩ":"a","ẫ":"a","ä":"a","ǟ":"a","ȧ":"a","ǡ":"a","ạ":"a","ȁ":"a","à":"a","ả":"a","ȃ":"a","ā":"a","ą":"a","ᶏ":"a","ẚ":"a","å":"a","ǻ":"a","ḁ":"a","ⱥ":"a","ã":"a","ꜳ":"aa","æ":"ae","ǽ":"ae","ǣ":"ae","ꜵ":"ao","ꜷ":"au","ꜹ":"av","ꜻ":"av","ꜽ":"ay","ḃ":"b","ḅ":"b","ɓ":"b","ḇ":"b","ᵬ":"b","ᶀ":"b","ƀ":"b","ƃ":"b","ɵ":"o","ć":"c","č":"c","ç":"c","ḉ":"c","ĉ":"c","ɕ":"c","ċ":"c","ƈ":"c","ȼ":"c","ď":"d","ḑ":"d","ḓ":"d","ȡ":"d","ḋ":"d","ḍ":"d","ɗ":"d","ᶑ":"d","ḏ":"d","ᵭ":"d","ᶁ":"d","đ":"d","ɖ":"d","ƌ":"d","ı":"i","ȷ":"j","ɟ":"j","ʄ":"j","dz":"dz","dž":"dz","é":"e","ĕ":"e","ě":"e","ȩ":"e","ḝ":"e","ê":"e","ế":"e","ệ":"e","ề":"e","ể":"e","ễ":"e","ḙ":"e","ë":"e","ė":"e","ẹ":"e","ȅ":"e","è":"e","ẻ":"e","ȇ":"e","ē":"e","ḗ":"e","ḕ":"e","ⱸ":"e","ę":"e","ᶒ":"e","ɇ":"e","ẽ":"e","ḛ":"e","ꝫ":"et","ḟ":"f","ƒ":"f","ᵮ":"f","ᶂ":"f","ǵ":"g","ğ":"g","ǧ":"g","ģ":"g","ĝ":"g","ġ":"g","ɠ":"g","ḡ":"g","ᶃ":"g","ǥ":"g","ḫ":"h","ȟ":"h","ḩ":"h","ĥ":"h","ⱨ":"h","ḧ":"h","ḣ":"h","ḥ":"h","ɦ":"h","ẖ":"h","ħ":"h","ƕ":"hv","í":"i","ĭ":"i","ǐ":"i","î":"i","ï":"i","ḯ":"i","ị":"i","ȉ":"i","ì":"i","ỉ":"i","ȋ":"i","ī":"i","į":"i","ᶖ":"i","ɨ":"i","ĩ":"i","ḭ":"i","ꝺ":"d","ꝼ":"f","ᵹ":"g","ꞃ":"r","ꞅ":"s","ꞇ":"t","ꝭ":"is","ǰ":"j","ĵ":"j","ʝ":"j","ɉ":"j","ḱ":"k","ǩ":"k","ķ":"k","ⱪ":"k","ꝃ":"k","ḳ":"k","ƙ":"k","ḵ":"k","ᶄ":"k","ꝁ":"k","ꝅ":"k","ĺ":"l","ƚ":"l","ɬ":"l","ľ":"l","ļ":"l","ḽ":"l","ȴ":"l","ḷ":"l","ḹ":"l","ⱡ":"l","ꝉ":"l","ḻ":"l","ŀ":"l","ɫ":"l","ᶅ":"l","ɭ":"l","ł":"l","lj":"lj","ſ":"s","ẜ":"s","ẛ":"s","ẝ":"s","ḿ":"m","ṁ":"m","ṃ":"m","ɱ":"m","ᵯ":"m","ᶆ":"m","ń":"n","ň":"n","ņ":"n","ṋ":"n","ȵ":"n","ṅ":"n","ṇ":"n","ǹ":"n","ɲ":"n","ṉ":"n","ƞ":"n","ᵰ":"n","ᶇ":"n","ɳ":"n","ñ":"n","nj":"nj","ó":"o","ŏ":"o","ǒ":"o","ô":"o","ố":"o","ộ":"o","ồ":"o","ổ":"o","ỗ":"o","ö":"o","ȫ":"o","ȯ":"o","ȱ":"o","ọ":"o","ő":"o","ȍ":"o","ò":"o","ỏ":"o","ơ":"o","ớ":"o","ợ":"o","ờ":"o","ở":"o","ỡ":"o","ȏ":"o","ꝋ":"o","ꝍ":"o","ⱺ":"o","ō":"o","ṓ":"o","ṑ":"o","ǫ":"o","ǭ":"o","ø":"o","ǿ":"o","õ":"o","ṍ":"o","ṏ":"o","ȭ":"o","ƣ":"oi","ꝏ":"oo","ɛ":"e","ᶓ":"e","ɔ":"o","ᶗ":"o","ȣ":"ou","ṕ":"p","ṗ":"p","ꝓ":"p","ƥ":"p","ᵱ":"p","ᶈ":"p","ꝕ":"p","ᵽ":"p","ꝑ":"p","ꝙ":"q","ʠ":"q","ɋ":"q","ꝗ":"q","ŕ":"r","ř":"r","ŗ":"r","ṙ":"r","ṛ":"r","ṝ":"r","ȑ":"r","ɾ":"r","ᵳ":"r","ȓ":"r","ṟ":"r","ɼ":"r","ᵲ":"r","ᶉ":"r","ɍ":"r","ɽ":"r","ↄ":"c","ꜿ":"c","ɘ":"e","ɿ":"r","ś":"s","ṥ":"s","š":"s","ṧ":"s","ş":"s","ŝ":"s","ș":"s","ṡ":"s","ṣ":"s","ṩ":"s","ʂ":"s","ᵴ":"s","ᶊ":"s","ȿ":"s","ɡ":"g","ß":"ss","ᴑ":"o","ᴓ":"o","ᴝ":"u","ť":"t","ţ":"t","ṱ":"t","ț":"t","ȶ":"t","ẗ":"t","ⱦ":"t","ṫ":"t","ṭ":"t","ƭ":"t","ṯ":"t","ᵵ":"t","ƫ":"t","ʈ":"t","ŧ":"t","ᵺ":"th","ɐ":"a","ᴂ":"ae","ǝ":"e","ᵷ":"g","ɥ":"h","ʮ":"h","ʯ":"h","ᴉ":"i","ʞ":"k","ꞁ":"l","ɯ":"m","ɰ":"m","ᴔ":"oe","ɹ":"r","ɻ":"r","ɺ":"r","ⱹ":"r","ʇ":"t","ʌ":"v","ʍ":"w","ʎ":"y","ꜩ":"tz","ú":"u","ŭ":"u","ǔ":"u","û":"u","ṷ":"u","ü":"u","ǘ":"u","ǚ":"u","ǜ":"u","ǖ":"u","ṳ":"u","ụ":"u","ű":"u","ȕ":"u","ù":"u","ủ":"u","ư":"u","ứ":"u","ự":"u","ừ":"u","ử":"u","ữ":"u","ȗ":"u","ū":"u","ṻ":"u","ų":"u","ᶙ":"u","ů":"u","ũ":"u","ṹ":"u","ṵ":"u","ᵫ":"ue","ꝸ":"um","ⱴ":"v","ꝟ":"v","ṿ":"v","ʋ":"v","ᶌ":"v","ⱱ":"v","ṽ":"v","ꝡ":"vy","ẃ":"w","ŵ":"w","ẅ":"w","ẇ":"w","ẉ":"w","ẁ":"w","ⱳ":"w","ẘ":"w","ẍ":"x","ẋ":"x","ᶍ":"x","ý":"y","ŷ":"y","ÿ":"y","ẏ":"y","ỵ":"y","ỳ":"y","ƴ":"y","ỷ":"y","ỿ":"y","ȳ":"y","ẙ":"y","ɏ":"y","ỹ":"y","ź":"z","ž":"z","ẑ":"z","ʑ":"z","ⱬ":"z","ż":"z","ẓ":"z","ȥ":"z","ẕ":"z","ᵶ":"z","ᶎ":"z","ʐ":"z","ƶ":"z","ɀ":"z","ff":"ff","ffi":"ffi","ffl":"ffl","fi":"fi","fl":"fl","ij":"ij","œ":"oe","st":"st","ₐ":"a","ₑ":"e","ᵢ":"i","ⱼ":"j","ₒ":"o","ᵣ":"r","ᵤ":"u","ᵥ":"v","ₓ":"x"};
       
 40643 
       
 40644 //******************************************************************************
       
 40645 // Added an initialize function which is essentially the code from the S
       
 40646 // constructor.  Now, the S constructor calls this and a new method named
       
 40647 // setValue calls it as well.  The setValue function allows constructors for
       
 40648 // modules that extend string.js to set the initial value of an object without
       
 40649 // knowing the internal workings of string.js.
       
 40650 //
       
 40651 // Also, all methods which return a new S object now call:
       
 40652 //
       
 40653 //      return new this.constructor(s);
       
 40654 //
       
 40655 // instead of:
       
 40656 //
       
 40657 //      return new S(s);
       
 40658 //
       
 40659 // This allows extended objects to keep their proper instanceOf and constructor.
       
 40660 //******************************************************************************
       
 40661 
       
 40662   function initialize (object, s) {
       
 40663     if (s !== null && s !== undefined) {
       
 40664       if (typeof s === 'string')
       
 40665         object.s = s;
       
 40666       else
       
 40667         object.s = s.toString();
       
 40668     } else {
       
 40669       object.s = s; //null or undefined
       
 40670     }
       
 40671 
       
 40672     object.orig = s; //original object, currently only used by toCSV() and toBoolean()
       
 40673 
       
 40674     if (s !== null && s !== undefined) {
       
 40675       if (object.__defineGetter__) {
       
 40676         object.__defineGetter__('length', function() {
       
 40677           return object.s.length;
       
 40678         })
       
 40679       } else {
       
 40680         object.length = s.length;
       
 40681       }
       
 40682     } else {
       
 40683       object.length = -1;
       
 40684     }
       
 40685   }
       
 40686 
       
 40687   function S(s) {
       
 40688   	initialize(this, s);
       
 40689   }
       
 40690 
       
 40691   var __nsp = String.prototype;
       
 40692   var __sp = S.prototype = {
       
 40693 
       
 40694     between: function(left, right) {
       
 40695       var s = this.s;
       
 40696       var startPos = s.indexOf(left);
       
 40697       var endPos = s.indexOf(right, startPos + left.length);
       
 40698       if (endPos == -1 && right != null) 
       
 40699         return new this.constructor('')
       
 40700       else if (endPos == -1 && right == null)
       
 40701         return new this.constructor(s.substring(startPos + left.length))
       
 40702       else 
       
 40703         return new this.constructor(s.slice(startPos + left.length, endPos));
       
 40704     },
       
 40705 
       
 40706     //# modified slightly from https://github.com/epeli/underscore.string
       
 40707     camelize: function() {
       
 40708       var s = this.trim().s.replace(/(\-|_|\s)+(.)?/g, function(mathc, sep, c) {
       
 40709         return (c ? c.toUpperCase() : '');
       
 40710       });
       
 40711       return new this.constructor(s);
       
 40712     },
       
 40713 
       
 40714     capitalize: function() {
       
 40715       return new this.constructor(this.s.substr(0, 1).toUpperCase() + this.s.substring(1).toLowerCase());
       
 40716     },
       
 40717 
       
 40718     charAt: function(index) {
       
 40719       return this.s.charAt(index);
       
 40720     },
       
 40721 
       
 40722     chompLeft: function(prefix) {
       
 40723       var s = this.s;
       
 40724       if (s.indexOf(prefix) === 0) {
       
 40725          s = s.slice(prefix.length);
       
 40726          return new this.constructor(s);
       
 40727       } else {
       
 40728         return this;
       
 40729       }
       
 40730     },
       
 40731 
       
 40732     chompRight: function(suffix) {
       
 40733       if (this.endsWith(suffix)) {
       
 40734         var s = this.s;
       
 40735         s = s.slice(0, s.length - suffix.length);
       
 40736         return new this.constructor(s);
       
 40737       } else {
       
 40738         return this;
       
 40739       }
       
 40740     },
       
 40741 
       
 40742     //#thanks Google
       
 40743     collapseWhitespace: function() {
       
 40744       var s = this.s.replace(/[\s\xa0]+/g, ' ').replace(/^\s+|\s+$/g, '');
       
 40745       return new this.constructor(s);
       
 40746     },
       
 40747 
       
 40748     contains: function(ss) {
       
 40749       return this.s.indexOf(ss) >= 0;
       
 40750     },
       
 40751 
       
 40752     count: function(ss) {
       
 40753       var count = 0
       
 40754         , pos = this.s.indexOf(ss)
       
 40755 
       
 40756       while (pos >= 0) {
       
 40757         count += 1
       
 40758         pos = this.s.indexOf(ss, pos + 1)
       
 40759       }
       
 40760 
       
 40761       return count
       
 40762     },
       
 40763 
       
 40764     //#modified from https://github.com/epeli/underscore.string
       
 40765     dasherize: function() {
       
 40766       var s = this.trim().s.replace(/[_\s]+/g, '-').replace(/([A-Z])/g, '-$1').replace(/-+/g, '-').toLowerCase();
       
 40767       return new this.constructor(s);
       
 40768     },
       
 40769 
       
 40770     latinise: function() {
       
 40771       var s = this.replace(/[^A-Za-z0-9\[\] ]/g, function(x) { return latin_map[x] || x; });
       
 40772       return new this.constructor(s);
       
 40773     },
       
 40774 
       
 40775     decodeHtmlEntities: function() { //https://github.com/substack/node-ent/blob/master/index.js
       
 40776       var s = this.s;
       
 40777       s = s.replace(/&#(\d+);?/g, function (_, code) {
       
 40778         return String.fromCharCode(code);
       
 40779       })
       
 40780       .replace(/&#[xX]([A-Fa-f0-9]+);?/g, function (_, hex) {
       
 40781         return String.fromCharCode(parseInt(hex, 16));
       
 40782       })
       
 40783       .replace(/&([^;\W]+;?)/g, function (m, e) {
       
 40784         var ee = e.replace(/;$/, '');
       
 40785         var target = ENTITIES[e] || (e.match(/;$/) && ENTITIES[ee]);
       
 40786             
       
 40787         if (typeof target === 'number') {
       
 40788           return String.fromCharCode(target);
       
 40789         }
       
 40790         else if (typeof target === 'string') {
       
 40791           return target;
       
 40792         }
       
 40793         else {
       
 40794           return m;
       
 40795         }
       
 40796       })
       
 40797 
       
 40798       return new this.constructor(s);
       
 40799     },
       
 40800 
       
 40801     endsWith: function(suffix) {
       
 40802       var l  = this.s.length - suffix.length;
       
 40803       return l >= 0 && this.s.indexOf(suffix, l) === l;
       
 40804     },
       
 40805 
       
 40806     escapeHTML: function() { //from underscore.string
       
 40807       return new this.constructor(this.s.replace(/[&<>"']/g, function(m){ return '&' + reversedEscapeChars[m] + ';'; }));
       
 40808     },
       
 40809 
       
 40810     ensureLeft: function(prefix) {
       
 40811       var s = this.s;
       
 40812       if (s.indexOf(prefix) === 0) {
       
 40813         return this;
       
 40814       } else {
       
 40815         return new this.constructor(prefix + s);
       
 40816       }
       
 40817     },
       
 40818 
       
 40819     ensureRight: function(suffix) {
       
 40820       var s = this.s;
       
 40821       if (this.endsWith(suffix))  {
       
 40822         return this;
       
 40823       } else {
       
 40824         return new this.constructor(s + suffix);
       
 40825       }
       
 40826     },
       
 40827 
       
 40828     humanize: function() { //modified from underscore.string
       
 40829       if (this.s === null || this.s === undefined)
       
 40830         return new this.constructor('')
       
 40831       var s = this.underscore().replace(/_id$/,'').replace(/_/g, ' ').trim().capitalize()
       
 40832       return new this.constructor(s)
       
 40833     },
       
 40834 
       
 40835     isAlpha: function() {
       
 40836       return !/[^a-z\xDF-\xFF]|^$/.test(this.s.toLowerCase());
       
 40837     },
       
 40838 
       
 40839     isAlphaNumeric: function() {
       
 40840       return !/[^0-9a-z\xDF-\xFF]/.test(this.s.toLowerCase());
       
 40841     },
       
 40842 
       
 40843     isEmpty: function() {
       
 40844       return this.s === null || this.s === undefined ? true : /^[\s\xa0]*$/.test(this.s);
       
 40845     },
       
 40846 
       
 40847     isLower: function() {
       
 40848       return this.isAlpha() && this.s.toLowerCase() === this.s;
       
 40849     },
       
 40850 
       
 40851     isNumeric: function() {
       
 40852       return !/[^0-9]/.test(this.s);
       
 40853     },
       
 40854 
       
 40855     isUpper: function() {
       
 40856       return this.isAlpha() && this.s.toUpperCase() === this.s;
       
 40857     },
       
 40858 
       
 40859     left: function(N) {
       
 40860       if (N >= 0) {
       
 40861         var s = this.s.substr(0, N);
       
 40862         return new this.constructor(s);
       
 40863       } else {
       
 40864         return this.right(-N);
       
 40865       }
       
 40866     },
       
 40867     
       
 40868     lines: function() { //convert windows newlines to unix newlines then convert to an Array of lines
       
 40869       return this.replaceAll('\r\n', '\n').s.split('\n');
       
 40870     },
       
 40871 
       
 40872     pad: function(len, ch) { //https://github.com/component/pad
       
 40873       if (ch == null) ch = ' ';
       
 40874       if (this.s.length >= len) return new this.constructor(this.s);
       
 40875       len = len - this.s.length;
       
 40876       var left = Array(Math.ceil(len / 2) + 1).join(ch);
       
 40877       var right = Array(Math.floor(len / 2) + 1).join(ch);
       
 40878       return new this.constructor(left + this.s + right);
       
 40879     },
       
 40880 
       
 40881     padLeft: function(len, ch) { //https://github.com/component/pad
       
 40882       if (ch == null) ch = ' ';
       
 40883       if (this.s.length >= len) return new this.constructor(this.s);
       
 40884       return new this.constructor(Array(len - this.s.length + 1).join(ch) + this.s);
       
 40885     },
       
 40886 
       
 40887     padRight: function(len, ch) { //https://github.com/component/pad
       
 40888       if (ch == null) ch = ' ';
       
 40889       if (this.s.length >= len) return new this.constructor(this.s);
       
 40890       return new this.constructor(this.s + Array(len - this.s.length + 1).join(ch));
       
 40891     },
       
 40892 
       
 40893     parseCSV: function(delimiter, qualifier, escape, lineDelimiter) { //try to parse no matter what
       
 40894       delimiter = delimiter || ',';
       
 40895       escape = escape || '\\'
       
 40896       if (typeof qualifier == 'undefined')
       
 40897         qualifier = '"';
       
 40898 
       
 40899       var i = 0, fieldBuffer = [], fields = [], len = this.s.length, inField = false, inUnqualifiedString = false, self = this;
       
 40900       var ca = function(i){return self.s.charAt(i)};
       
 40901       if (typeof lineDelimiter !== 'undefined') var rows = [];
       
 40902 
       
 40903       if (!qualifier)
       
 40904         inField = true;
       
 40905 
       
 40906       while (i < len) {
       
 40907         var current = ca(i);
       
 40908         switch (current) {
       
 40909           case escape:
       
 40910             //fix for issues #32 and #35
       
 40911             if (inField && ((escape !== qualifier) || ca(i+1) === qualifier)) {
       
 40912               i += 1;
       
 40913               fieldBuffer.push(ca(i));
       
 40914               break;
       
 40915             }
       
 40916             if (escape !== qualifier) break;
       
 40917           case qualifier:
       
 40918             inField = !inField;
       
 40919             break;
       
 40920           case delimiter:
       
 40921             if(inUnqualifiedString) {
       
 40922               inField=false;
       
 40923               inUnqualifiedString=false;
       
 40924             }
       
 40925             if (inField && qualifier)
       
 40926               fieldBuffer.push(current);
       
 40927             else {
       
 40928               fields.push(fieldBuffer.join(''))
       
 40929               fieldBuffer.length = 0;
       
 40930             }
       
 40931             break;
       
 40932           case lineDelimiter:
       
 40933             if(inUnqualifiedString) {
       
 40934               inField=false;
       
 40935               inUnqualifiedString=false;
       
 40936               fields.push(fieldBuffer.join(''))
       
 40937               rows.push(fields);
       
 40938               fields = [];
       
 40939               fieldBuffer.length = 0;
       
 40940             }
       
 40941             else if (inField) {
       
 40942               fieldBuffer.push(current);
       
 40943             } else {
       
 40944               if (rows) {
       
 40945                 fields.push(fieldBuffer.join(''))
       
 40946                 rows.push(fields);
       
 40947                 fields = [];
       
 40948                 fieldBuffer.length = 0;
       
 40949               }
       
 40950             }
       
 40951             break;
       
 40952           case ' ':
       
 40953             if (inField)
       
 40954               fieldBuffer.push(current);
       
 40955             break;
       
 40956           default:
       
 40957             if (inField)
       
 40958               fieldBuffer.push(current);
       
 40959             else if(current!==qualifier) {
       
 40960               fieldBuffer.push(current);
       
 40961               inField=true;
       
 40962               inUnqualifiedString=true;
       
 40963             }
       
 40964             break;
       
 40965         }
       
 40966         i += 1;
       
 40967       }
       
 40968 
       
 40969       fields.push(fieldBuffer.join(''));
       
 40970       if (rows) {
       
 40971         rows.push(fields);
       
 40972         return rows;
       
 40973       }
       
 40974       return fields;
       
 40975     },
       
 40976 
       
 40977     replaceAll: function(ss, r) {
       
 40978       //var s = this.s.replace(new RegExp(ss, 'g'), r);
       
 40979       var s = this.s.split(ss).join(r)
       
 40980       return new this.constructor(s);
       
 40981     },
       
 40982 
       
 40983     strip: function() {
       
 40984       var ss = this.s;
       
 40985       for(var i= 0, n=arguments.length; i<n; i++) {
       
 40986         ss = ss.split(arguments[i]).join('');
       
 40987       }
       
 40988       return new this.constructor(ss);
       
 40989     },
       
 40990 
       
 40991     right: function(N) {
       
 40992       if (N >= 0) {
       
 40993         var s = this.s.substr(this.s.length - N, N);
       
 40994         return new this.constructor(s);
       
 40995       } else {
       
 40996         return this.left(-N);
       
 40997       }
       
 40998     },
       
 40999 
       
 41000     setValue: function (s) {
       
 41001 	  initialize(this, s);
       
 41002 	  return this;
       
 41003     },
       
 41004 
       
 41005     slugify: function() {
       
 41006       var sl = (new S(new S(this.s).latinise().s.replace(/[^\w\s-]/g, '').toLowerCase())).dasherize().s;
       
 41007       if (sl.charAt(0) === '-')
       
 41008         sl = sl.substr(1);
       
 41009       return new this.constructor(sl);
       
 41010     },
       
 41011 
       
 41012     startsWith: function(prefix) {
       
 41013       return this.s.lastIndexOf(prefix, 0) === 0;
       
 41014     },
       
 41015 
       
 41016     stripPunctuation: function() {
       
 41017       //return new this.constructor(this.s.replace(/[\.,-\/#!$%\^&\*;:{}=\-_`~()]/g,""));
       
 41018       return new this.constructor(this.s.replace(/[^\w\s]|_/g, "").replace(/\s+/g, " "));
       
 41019     },
       
 41020 
       
 41021     stripTags: function() { //from sugar.js
       
 41022       var s = this.s, args = arguments.length > 0 ? arguments : [''];
       
 41023       multiArgs(args, function(tag) {
       
 41024         s = s.replace(RegExp('<\/?' + tag + '[^<>]*>', 'gi'), '');
       
 41025       });
       
 41026       return new this.constructor(s);
       
 41027     },
       
 41028 
       
 41029     template: function(values, opening, closing) {
       
 41030       var s = this.s
       
 41031       var opening = opening || Export.TMPL_OPEN
       
 41032       var closing = closing || Export.TMPL_CLOSE
       
 41033 
       
 41034       var open = opening.replace(/[-[\]()*\s]/g, "\\$&").replace(/\$/g, '\\$')
       
 41035       var close = closing.replace(/[-[\]()*\s]/g, "\\$&").replace(/\$/g, '\\$')
       
 41036       var r = new RegExp(open + '(.+?)' + close, 'g')
       
 41037         //, r = /\{\{(.+?)\}\}/g
       
 41038       var matches = s.match(r) || [];
       
 41039 
       
 41040       matches.forEach(function(match) {
       
 41041         var key = match.substring(opening.length, match.length - closing.length);//chop {{ and }}
       
 41042         if (typeof values[key] != 'undefined')
       
 41043           s = s.replace(match, values[key]);
       
 41044       });
       
 41045       return new this.constructor(s);
       
 41046     },
       
 41047 
       
 41048     times: function(n) {
       
 41049       return new this.constructor(new Array(n + 1).join(this.s));
       
 41050     },
       
 41051 
       
 41052     toBoolean: function() {
       
 41053       if (typeof this.orig === 'string') {
       
 41054         var s = this.s.toLowerCase();
       
 41055         return s === 'true' || s === 'yes' || s === 'on' || s === '1';
       
 41056       } else
       
 41057         return this.orig === true || this.orig === 1;
       
 41058     },
       
 41059 
       
 41060     toFloat: function(precision) {
       
 41061       var num = parseFloat(this.s)
       
 41062       if (precision)
       
 41063         return parseFloat(num.toFixed(precision))
       
 41064       else
       
 41065         return num
       
 41066     },
       
 41067 
       
 41068     toInt: function() { //thanks Google
       
 41069       // If the string starts with '0x' or '-0x', parse as hex.
       
 41070       return /^\s*-?0x/i.test(this.s) ? parseInt(this.s, 16) : parseInt(this.s, 10)
       
 41071     },
       
 41072 
       
 41073     trim: function() {
       
 41074       var s;
       
 41075       if (typeof __nsp.trim === 'undefined') 
       
 41076         s = this.s.replace(/(^\s*|\s*$)/g, '')
       
 41077       else 
       
 41078         s = this.s.trim()
       
 41079       return new this.constructor(s);
       
 41080     },
       
 41081 
       
 41082     trimLeft: function() {
       
 41083       var s;
       
 41084       if (__nsp.trimLeft)
       
 41085         s = this.s.trimLeft();
       
 41086       else
       
 41087         s = this.s.replace(/(^\s*)/g, '');
       
 41088       return new this.constructor(s);
       
 41089     },
       
 41090 
       
 41091     trimRight: function() {
       
 41092       var s;
       
 41093       if (__nsp.trimRight)
       
 41094         s = this.s.trimRight();
       
 41095       else
       
 41096         s = this.s.replace(/\s+$/, '');
       
 41097       return new this.constructor(s);
       
 41098     },
       
 41099 
       
 41100     truncate: function(length, pruneStr) { //from underscore.string, author: github.com/rwz
       
 41101       var str = this.s;
       
 41102 
       
 41103       length = ~~length;
       
 41104       pruneStr = pruneStr || '...';
       
 41105 
       
 41106       if (str.length <= length) return new this.constructor(str);
       
 41107 
       
 41108       var tmpl = function(c){ return c.toUpperCase() !== c.toLowerCase() ? 'A' : ' '; },
       
 41109         template = str.slice(0, length+1).replace(/.(?=\W*\w*$)/g, tmpl); // 'Hello, world' -> 'HellAA AAAAA'
       
 41110 
       
 41111       if (template.slice(template.length-2).match(/\w\w/))
       
 41112         template = template.replace(/\s*\S+$/, '');
       
 41113       else
       
 41114         template = new S(template.slice(0, template.length-1)).trimRight().s;
       
 41115 
       
 41116       return (template+pruneStr).length > str.length ? new S(str) : new S(str.slice(0, template.length)+pruneStr);
       
 41117     },
       
 41118 
       
 41119     toCSV: function() {
       
 41120       var delim = ',', qualifier = '"', escape = '\\', encloseNumbers = true, keys = false;
       
 41121       var dataArray = [];
       
 41122 
       
 41123       function hasVal(it) {
       
 41124         return it !== null && it !== '';
       
 41125       }
       
 41126 
       
 41127       if (typeof arguments[0] === 'object') {
       
 41128         delim = arguments[0].delimiter || delim;
       
 41129         delim = arguments[0].separator || delim;
       
 41130         qualifier = arguments[0].qualifier || qualifier;
       
 41131         encloseNumbers = !!arguments[0].encloseNumbers;
       
 41132         escape = arguments[0].escape || escape;
       
 41133         keys = !!arguments[0].keys;
       
 41134       } else if (typeof arguments[0] === 'string') {
       
 41135         delim = arguments[0];
       
 41136       }
       
 41137 
       
 41138       if (typeof arguments[1] === 'string')
       
 41139         qualifier = arguments[1];
       
 41140 
       
 41141       if (arguments[1] === null)
       
 41142         qualifier = null;
       
 41143 
       
 41144        if (this.orig instanceof Array)
       
 41145         dataArray  = this.orig;
       
 41146       else { //object
       
 41147         for (var key in this.orig)
       
 41148           if (this.orig.hasOwnProperty(key))
       
 41149             if (keys)
       
 41150               dataArray.push(key);
       
 41151             else
       
 41152               dataArray.push(this.orig[key]);
       
 41153       }
       
 41154 
       
 41155       var rep = escape + qualifier;
       
 41156       var buildString = [];
       
 41157       for (var i = 0; i < dataArray.length; ++i) {
       
 41158         var shouldQualify = hasVal(qualifier)
       
 41159         if (typeof dataArray[i] == 'number')
       
 41160           shouldQualify &= encloseNumbers;
       
 41161         
       
 41162         if (shouldQualify)
       
 41163           buildString.push(qualifier);
       
 41164         
       
 41165         if (dataArray[i] !== null && dataArray[i] !== undefined) {
       
 41166           var d = new S(dataArray[i]).replaceAll(qualifier, rep).s;
       
 41167           buildString.push(d);
       
 41168         } else 
       
 41169           buildString.push('')
       
 41170 
       
 41171         if (shouldQualify)
       
 41172           buildString.push(qualifier);
       
 41173         
       
 41174         if (delim)
       
 41175           buildString.push(delim);
       
 41176       }
       
 41177 
       
 41178       //chop last delim
       
 41179       //console.log(buildString.length)
       
 41180       buildString.length = buildString.length - 1;
       
 41181       return new this.constructor(buildString.join(''));
       
 41182     },
       
 41183 
       
 41184     toString: function() {
       
 41185       return this.s;
       
 41186     },
       
 41187 
       
 41188     //#modified from https://github.com/epeli/underscore.string
       
 41189     underscore: function() {
       
 41190       var s = this.trim().s.replace(/([a-z\d])([A-Z]+)/g, '$1_$2').replace(/[-\s]+/g, '_').toLowerCase();
       
 41191       if ((new S(this.s.charAt(0))).isUpper()) {
       
 41192         s = '_' + s;
       
 41193       }
       
 41194       return new this.constructor(s);
       
 41195     },
       
 41196 
       
 41197     unescapeHTML: function() { //from underscore.string
       
 41198       return new this.constructor(this.s.replace(/\&([^;]+);/g, function(entity, entityCode){
       
 41199         var match;
       
 41200 
       
 41201         if (entityCode in escapeChars) {
       
 41202           return escapeChars[entityCode];
       
 41203         } else if (match = entityCode.match(/^#x([\da-fA-F]+)$/)) {
       
 41204           return String.fromCharCode(parseInt(match[1], 16));
       
 41205         } else if (match = entityCode.match(/^#(\d+)$/)) {
       
 41206           return String.fromCharCode(~~match[1]);
       
 41207         } else {
       
 41208           return entity;
       
 41209         }
       
 41210       }));
       
 41211     },
       
 41212 
       
 41213     valueOf: function() {
       
 41214       return this.s.valueOf();
       
 41215     },
       
 41216 
       
 41217     //#Added a New Function called wrapHTML.
       
 41218     wrapHTML: function (tagName, tagAttrs) {
       
 41219       var s = this.s, el = (tagName == null) ? 'span' : tagName, elAttr = '', wrapped = '';
       
 41220       if(typeof tagAttrs == 'object') for(var prop in tagAttrs) elAttr += ' ' + prop + '="' +(new this.constructor(tagAttrs[prop])).escapeHTML() + '"';
       
 41221       s = wrapped.concat('<', el, elAttr, '>', this, '</', el, '>');
       
 41222       return new this.constructor(s);
       
 41223     }
       
 41224   }
       
 41225 
       
 41226   var methodsAdded = [];
       
 41227   function extendPrototype() {
       
 41228     for (var name in __sp) {
       
 41229       (function(name){
       
 41230         var func = __sp[name];
       
 41231         if (!__nsp.hasOwnProperty(name)) {
       
 41232           methodsAdded.push(name);
       
 41233           __nsp[name] = function() {
       
 41234             String.prototype.s = this;
       
 41235             return func.apply(this, arguments);
       
 41236           }
       
 41237         }
       
 41238       })(name);
       
 41239     }
       
 41240   }
       
 41241 
       
 41242   function restorePrototype() {
       
 41243     for (var i = 0; i < methodsAdded.length; ++i)
       
 41244       delete String.prototype[methodsAdded[i]];
       
 41245     methodsAdded.length = 0;
       
 41246   }
       
 41247 
       
 41248 
       
 41249 /*************************************
       
 41250 /* Attach Native JavaScript String Properties
       
 41251 /*************************************/
       
 41252 
       
 41253   var nativeProperties = getNativeStringProperties();
       
 41254   for (var name in nativeProperties) {
       
 41255     (function(name) {
       
 41256       var stringProp = __nsp[name];
       
 41257       if (typeof stringProp == 'function') {
       
 41258         //console.log(stringProp)
       
 41259         if (!__sp[name]) {
       
 41260           if (nativeProperties[name] === 'string') {
       
 41261             __sp[name] = function() {
       
 41262               //console.log(name)
       
 41263               return new this.constructor(stringProp.apply(this, arguments));
       
 41264             }
       
 41265           } else {
       
 41266             __sp[name] = stringProp;
       
 41267           }
       
 41268         }
       
 41269       }
       
 41270     })(name);
       
 41271   }
       
 41272 
       
 41273 
       
 41274 /*************************************
       
 41275 /* Function Aliases
       
 41276 /*************************************/
       
 41277 
       
 41278   __sp.repeat = __sp.times;
       
 41279   __sp.include = __sp.contains;
       
 41280   __sp.toInteger = __sp.toInt;
       
 41281   __sp.toBool = __sp.toBoolean;
       
 41282   __sp.decodeHTMLEntities = __sp.decodeHtmlEntities //ensure consistent casing scheme of 'HTML'
       
 41283 
       
 41284 
       
 41285 //******************************************************************************
       
 41286 // Set the constructor.  Without this, string.js objects are instances of
       
 41287 // Object instead of S.
       
 41288 //******************************************************************************
       
 41289 
       
 41290   __sp.constructor = S;
       
 41291 
       
 41292 
       
 41293 /*************************************
       
 41294 /* Private Functions
       
 41295 /*************************************/
       
 41296 
       
 41297   function getNativeStringProperties() {
       
 41298     var names = getNativeStringPropertyNames();
       
 41299     var retObj = {};
       
 41300 
       
 41301     for (var i = 0; i < names.length; ++i) {
       
 41302       var name = names[i];
       
 41303       var func = __nsp[name];
       
 41304       try {
       
 41305         var type = typeof func.apply('teststring', []);
       
 41306         retObj[name] = type;
       
 41307       } catch (e) {}
       
 41308     }
       
 41309     return retObj;
       
 41310   }
       
 41311 
       
 41312   function getNativeStringPropertyNames() {
       
 41313     var results = [];
       
 41314     if (Object.getOwnPropertyNames) {
       
 41315       results = Object.getOwnPropertyNames(__nsp);
       
 41316       results.splice(results.indexOf('valueOf'), 1);
       
 41317       results.splice(results.indexOf('toString'), 1);
       
 41318       return results;
       
 41319     } else { //meant for legacy cruft, this could probably be made more efficient
       
 41320       var stringNames = {};
       
 41321       var objectNames = [];
       
 41322       for (var name in String.prototype)
       
 41323         stringNames[name] = name;
       
 41324 
       
 41325       for (var name in Object.prototype)
       
 41326         delete stringNames[name];
       
 41327 
       
 41328       //stringNames['toString'] = 'toString'; //this was deleted with the rest of the object names
       
 41329       for (var name in stringNames) {
       
 41330         results.push(name);
       
 41331       }
       
 41332       return results;
       
 41333     }
       
 41334   }
       
 41335 
       
 41336   function Export(str) {
       
 41337     return new S(str);
       
 41338   };
       
 41339 
       
 41340   //attach exports to StringJSWrapper
       
 41341   Export.extendPrototype = extendPrototype;
       
 41342   Export.restorePrototype = restorePrototype;
       
 41343   Export.VERSION = VERSION;
       
 41344   Export.TMPL_OPEN = '{{';
       
 41345   Export.TMPL_CLOSE = '}}';
       
 41346   Export.ENTITIES = ENTITIES;
       
 41347 
       
 41348 
       
 41349 
       
 41350 /*************************************
       
 41351 /* Exports
       
 41352 /*************************************/
       
 41353 
       
 41354   if (typeof module !== 'undefined'  && typeof module.exports !== 'undefined') {
       
 41355     module.exports = Export;
       
 41356 
       
 41357   } else {
       
 41358 
       
 41359     if(typeof define === "function" && define.amd) {
       
 41360       define([], function() {
       
 41361         return Export;
       
 41362       });
       
 41363     } else {
       
 41364       window.S = Export;
       
 41365     }
       
 41366   }
       
 41367 
       
 41368 
       
 41369 /*************************************
       
 41370 /* 3rd Party Private Functions
       
 41371 /*************************************/
       
 41372 
       
 41373   //from sugar.js
       
 41374   function multiArgs(args, fn) {
       
 41375     var result = [], i;
       
 41376     for(i = 0; i < args.length; i++) {
       
 41377       result.push(args[i]);
       
 41378       if(fn) fn.call(args, args[i], i);
       
 41379     }
       
 41380     return result;
       
 41381   }
       
 41382 
       
 41383   //from underscore.string
       
 41384   var escapeChars = {
       
 41385     lt: '<',
       
 41386     gt: '>',
       
 41387     quot: '"',
       
 41388     apos: "'",
       
 41389     amp: '&'
       
 41390   };
       
 41391 
       
 41392   //from underscore.string
       
 41393   var reversedEscapeChars = {};
       
 41394   for(var key in escapeChars){ reversedEscapeChars[escapeChars[key]] = key; }
       
 41395 
       
 41396   ENTITIES = {
       
 41397     "amp" : "&",
       
 41398     "gt" : ">",
       
 41399     "lt" : "<",
       
 41400     "quot" : "\"",
       
 41401     "apos" : "'",
       
 41402     "AElig" : 198,
       
 41403     "Aacute" : 193,
       
 41404     "Acirc" : 194,
       
 41405     "Agrave" : 192,
       
 41406     "Aring" : 197,
       
 41407     "Atilde" : 195,
       
 41408     "Auml" : 196,
       
 41409     "Ccedil" : 199,
       
 41410     "ETH" : 208,
       
 41411     "Eacute" : 201,
       
 41412     "Ecirc" : 202,
       
 41413     "Egrave" : 200,
       
 41414     "Euml" : 203,
       
 41415     "Iacute" : 205,
       
 41416     "Icirc" : 206,
       
 41417     "Igrave" : 204,
       
 41418     "Iuml" : 207,
       
 41419     "Ntilde" : 209,
       
 41420     "Oacute" : 211,
       
 41421     "Ocirc" : 212,
       
 41422     "Ograve" : 210,
       
 41423     "Oslash" : 216,
       
 41424     "Otilde" : 213,
       
 41425     "Ouml" : 214,
       
 41426     "THORN" : 222,
       
 41427     "Uacute" : 218,
       
 41428     "Ucirc" : 219,
       
 41429     "Ugrave" : 217,
       
 41430     "Uuml" : 220,
       
 41431     "Yacute" : 221,
       
 41432     "aacute" : 225,
       
 41433     "acirc" : 226,
       
 41434     "aelig" : 230,
       
 41435     "agrave" : 224,
       
 41436     "aring" : 229,
       
 41437     "atilde" : 227,
       
 41438     "auml" : 228,
       
 41439     "ccedil" : 231,
       
 41440     "eacute" : 233,
       
 41441     "ecirc" : 234,
       
 41442     "egrave" : 232,
       
 41443     "eth" : 240,
       
 41444     "euml" : 235,
       
 41445     "iacute" : 237,
       
 41446     "icirc" : 238,
       
 41447     "igrave" : 236,
       
 41448     "iuml" : 239,
       
 41449     "ntilde" : 241,
       
 41450     "oacute" : 243,
       
 41451     "ocirc" : 244,
       
 41452     "ograve" : 242,
       
 41453     "oslash" : 248,
       
 41454     "otilde" : 245,
       
 41455     "ouml" : 246,
       
 41456     "szlig" : 223,
       
 41457     "thorn" : 254,
       
 41458     "uacute" : 250,
       
 41459     "ucirc" : 251,
       
 41460     "ugrave" : 249,
       
 41461     "uuml" : 252,
       
 41462     "yacute" : 253,
       
 41463     "yuml" : 255,
       
 41464     "copy" : 169,
       
 41465     "reg" : 174,
       
 41466     "nbsp" : 160,
       
 41467     "iexcl" : 161,
       
 41468     "cent" : 162,
       
 41469     "pound" : 163,
       
 41470     "curren" : 164,
       
 41471     "yen" : 165,
       
 41472     "brvbar" : 166,
       
 41473     "sect" : 167,
       
 41474     "uml" : 168,
       
 41475     "ordf" : 170,
       
 41476     "laquo" : 171,
       
 41477     "not" : 172,
       
 41478     "shy" : 173,
       
 41479     "macr" : 175,
       
 41480     "deg" : 176,
       
 41481     "plusmn" : 177,
       
 41482     "sup1" : 185,
       
 41483     "sup2" : 178,
       
 41484     "sup3" : 179,
       
 41485     "acute" : 180,
       
 41486     "micro" : 181,
       
 41487     "para" : 182,
       
 41488     "middot" : 183,
       
 41489     "cedil" : 184,
       
 41490     "ordm" : 186,
       
 41491     "raquo" : 187,
       
 41492     "frac14" : 188,
       
 41493     "frac12" : 189,
       
 41494     "frac34" : 190,
       
 41495     "iquest" : 191,
       
 41496     "times" : 215,
       
 41497     "divide" : 247,
       
 41498     "OElig;" : 338,
       
 41499     "oelig;" : 339,
       
 41500     "Scaron;" : 352,
       
 41501     "scaron;" : 353,
       
 41502     "Yuml;" : 376,
       
 41503     "fnof;" : 402,
       
 41504     "circ;" : 710,
       
 41505     "tilde;" : 732,
       
 41506     "Alpha;" : 913,
       
 41507     "Beta;" : 914,
       
 41508     "Gamma;" : 915,
       
 41509     "Delta;" : 916,
       
 41510     "Epsilon;" : 917,
       
 41511     "Zeta;" : 918,
       
 41512     "Eta;" : 919,
       
 41513     "Theta;" : 920,
       
 41514     "Iota;" : 921,
       
 41515     "Kappa;" : 922,
       
 41516     "Lambda;" : 923,
       
 41517     "Mu;" : 924,
       
 41518     "Nu;" : 925,
       
 41519     "Xi;" : 926,
       
 41520     "Omicron;" : 927,
       
 41521     "Pi;" : 928,
       
 41522     "Rho;" : 929,
       
 41523     "Sigma;" : 931,
       
 41524     "Tau;" : 932,
       
 41525     "Upsilon;" : 933,
       
 41526     "Phi;" : 934,
       
 41527     "Chi;" : 935,
       
 41528     "Psi;" : 936,
       
 41529     "Omega;" : 937,
       
 41530     "alpha;" : 945,
       
 41531     "beta;" : 946,
       
 41532     "gamma;" : 947,
       
 41533     "delta;" : 948,
       
 41534     "epsilon;" : 949,
       
 41535     "zeta;" : 950,
       
 41536     "eta;" : 951,
       
 41537     "theta;" : 952,
       
 41538     "iota;" : 953,
       
 41539     "kappa;" : 954,
       
 41540     "lambda;" : 955,
       
 41541     "mu;" : 956,
       
 41542     "nu;" : 957,
       
 41543     "xi;" : 958,
       
 41544     "omicron;" : 959,
       
 41545     "pi;" : 960,
       
 41546     "rho;" : 961,
       
 41547     "sigmaf;" : 962,
       
 41548     "sigma;" : 963,
       
 41549     "tau;" : 964,
       
 41550     "upsilon;" : 965,
       
 41551     "phi;" : 966,
       
 41552     "chi;" : 967,
       
 41553     "psi;" : 968,
       
 41554     "omega;" : 969,
       
 41555     "thetasym;" : 977,
       
 41556     "upsih;" : 978,
       
 41557     "piv;" : 982,
       
 41558     "ensp;" : 8194,
       
 41559     "emsp;" : 8195,
       
 41560     "thinsp;" : 8201,
       
 41561     "zwnj;" : 8204,
       
 41562     "zwj;" : 8205,
       
 41563     "lrm;" : 8206,
       
 41564     "rlm;" : 8207,
       
 41565     "ndash;" : 8211,
       
 41566     "mdash;" : 8212,
       
 41567     "lsquo;" : 8216,
       
 41568     "rsquo;" : 8217,
       
 41569     "sbquo;" : 8218,
       
 41570     "ldquo;" : 8220,
       
 41571     "rdquo;" : 8221,
       
 41572     "bdquo;" : 8222,
       
 41573     "dagger;" : 8224,
       
 41574     "Dagger;" : 8225,
       
 41575     "bull;" : 8226,
       
 41576     "hellip;" : 8230,
       
 41577     "permil;" : 8240,
       
 41578     "prime;" : 8242,
       
 41579     "Prime;" : 8243,
       
 41580     "lsaquo;" : 8249,
       
 41581     "rsaquo;" : 8250,
       
 41582     "oline;" : 8254,
       
 41583     "frasl;" : 8260,
       
 41584     "euro;" : 8364,
       
 41585     "image;" : 8465,
       
 41586     "weierp;" : 8472,
       
 41587     "real;" : 8476,
       
 41588     "trade;" : 8482,
       
 41589     "alefsym;" : 8501,
       
 41590     "larr;" : 8592,
       
 41591     "uarr;" : 8593,
       
 41592     "rarr;" : 8594,
       
 41593     "darr;" : 8595,
       
 41594     "harr;" : 8596,
       
 41595     "crarr;" : 8629,
       
 41596     "lArr;" : 8656,
       
 41597     "uArr;" : 8657,
       
 41598     "rArr;" : 8658,
       
 41599     "dArr;" : 8659,
       
 41600     "hArr;" : 8660,
       
 41601     "forall;" : 8704,
       
 41602     "part;" : 8706,
       
 41603     "exist;" : 8707,
       
 41604     "empty;" : 8709,
       
 41605     "nabla;" : 8711,
       
 41606     "isin;" : 8712,
       
 41607     "notin;" : 8713,
       
 41608     "ni;" : 8715,
       
 41609     "prod;" : 8719,
       
 41610     "sum;" : 8721,
       
 41611     "minus;" : 8722,
       
 41612     "lowast;" : 8727,
       
 41613     "radic;" : 8730,
       
 41614     "prop;" : 8733,
       
 41615     "infin;" : 8734,
       
 41616     "ang;" : 8736,
       
 41617     "and;" : 8743,
       
 41618     "or;" : 8744,
       
 41619     "cap;" : 8745,
       
 41620     "cup;" : 8746,
       
 41621     "int;" : 8747,
       
 41622     "there4;" : 8756,
       
 41623     "sim;" : 8764,
       
 41624     "cong;" : 8773,
       
 41625     "asymp;" : 8776,
       
 41626     "ne;" : 8800,
       
 41627     "equiv;" : 8801,
       
 41628     "le;" : 8804,
       
 41629     "ge;" : 8805,
       
 41630     "sub;" : 8834,
       
 41631     "sup;" : 8835,
       
 41632     "nsub;" : 8836,
       
 41633     "sube;" : 8838,
       
 41634     "supe;" : 8839,
       
 41635     "oplus;" : 8853,
       
 41636     "otimes;" : 8855,
       
 41637     "perp;" : 8869,
       
 41638     "sdot;" : 8901,
       
 41639     "lceil;" : 8968,
       
 41640     "rceil;" : 8969,
       
 41641     "lfloor;" : 8970,
       
 41642     "rfloor;" : 8971,
       
 41643     "lang;" : 9001,
       
 41644     "rang;" : 9002,
       
 41645     "loz;" : 9674,
       
 41646     "spades;" : 9824,
       
 41647     "clubs;" : 9827,
       
 41648     "hearts;" : 9829,
       
 41649     "diams;" : 9830
       
 41650   }
       
 41651 
       
 41652 
       
 41653 }).call(this);
       
 41654 
       
 41655 /*!
       
 41656  * Bootstrap v3.1.1 (http://getbootstrap.com)
       
 41657  * Copyright 2011-2014 Twitter, Inc.
       
 41658  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
       
 41659  */
       
 41660 
       
 41661 if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript requires jQuery') }
       
 41662 
       
 41663 /* ========================================================================
       
 41664  * Bootstrap: transition.js v3.1.1
       
 41665  * http://getbootstrap.com/javascript/#transitions
       
 41666  * ========================================================================
       
 41667  * Copyright 2011-2014 Twitter, Inc.
       
 41668  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
       
 41669  * ======================================================================== */
       
 41670 
       
 41671 
       
 41672 +function ($) {
       
 41673   'use strict';
       
 41674 
       
 41675   // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
       
 41676   // ============================================================
       
 41677 
       
 41678   function transitionEnd() {
       
 41679     var el = document.createElement('bootstrap')
       
 41680 
       
 41681     var transEndEventNames = {
       
 41682       'WebkitTransition' : 'webkitTransitionEnd',
       
 41683       'MozTransition'    : 'transitionend',
       
 41684       'OTransition'      : 'oTransitionEnd otransitionend',
       
 41685       'transition'       : 'transitionend'
       
 41686     }
       
 41687 
       
 41688     for (var name in transEndEventNames) {
       
 41689       if (el.style[name] !== undefined) {
       
 41690         return { end: transEndEventNames[name] }
       
 41691       }
       
 41692     }
       
 41693 
       
 41694     return false // explicit for ie8 (  ._.)
       
 41695   }
       
 41696 
       
 41697   // http://blog.alexmaccaw.com/css-transitions
       
 41698   $.fn.emulateTransitionEnd = function (duration) {
       
 41699     var called = false, $el = this
       
 41700     $(this).one($.support.transition.end, function () { called = true })
       
 41701     var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
       
 41702     setTimeout(callback, duration)
       
 41703     return this
       
 41704   }
       
 41705 
       
 41706   $(function () {
       
 41707     $.support.transition = transitionEnd()
       
 41708   })
       
 41709 
       
 41710 }(jQuery);
       
 41711 
       
 41712 /* ========================================================================
       
 41713  * Bootstrap: alert.js v3.1.1
       
 41714  * http://getbootstrap.com/javascript/#alerts
       
 41715  * ========================================================================
       
 41716  * Copyright 2011-2014 Twitter, Inc.
       
 41717  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
       
 41718  * ======================================================================== */
       
 41719 
       
 41720 
       
 41721 +function ($) {
       
 41722   'use strict';
       
 41723 
       
 41724   // ALERT CLASS DEFINITION
       
 41725   // ======================
       
 41726 
       
 41727   var dismiss = '[data-dismiss="alert"]'
       
 41728   var Alert   = function (el) {
       
 41729     $(el).on('click', dismiss, this.close)
       
 41730   }
       
 41731 
       
 41732   Alert.prototype.close = function (e) {
       
 41733     var $this    = $(this)
       
 41734     var selector = $this.attr('data-target')
       
 41735 
       
 41736     if (!selector) {
       
 41737       selector = $this.attr('href')
       
 41738       selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
       
 41739     }
       
 41740 
       
 41741     var $parent = $(selector)
       
 41742 
       
 41743     if (e) e.preventDefault()
       
 41744 
       
 41745     if (!$parent.length) {
       
 41746       $parent = $this.hasClass('alert') ? $this : $this.parent()
       
 41747     }
       
 41748 
       
 41749     $parent.trigger(e = $.Event('close.bs.alert'))
       
 41750 
       
 41751     if (e.isDefaultPrevented()) return
       
 41752 
       
 41753     $parent.removeClass('in')
       
 41754 
       
 41755     function removeElement() {
       
 41756       $parent.trigger('closed.bs.alert').remove()
       
 41757     }
       
 41758 
       
 41759     $.support.transition && $parent.hasClass('fade') ?
       
 41760       $parent
       
 41761         .one($.support.transition.end, removeElement)
       
 41762         .emulateTransitionEnd(150) :
       
 41763       removeElement()
       
 41764   }
       
 41765 
       
 41766 
       
 41767   // ALERT PLUGIN DEFINITION
       
 41768   // =======================
       
 41769 
       
 41770   var old = $.fn.alert
       
 41771 
       
 41772   $.fn.alert = function (option) {
       
 41773     return this.each(function () {
       
 41774       var $this = $(this)
       
 41775       var data  = $this.data('bs.alert')
       
 41776 
       
 41777       if (!data) $this.data('bs.alert', (data = new Alert(this)))
       
 41778       if (typeof option == 'string') data[option].call($this)
       
 41779     })
       
 41780   }
       
 41781 
       
 41782   $.fn.alert.Constructor = Alert
       
 41783 
       
 41784 
       
 41785   // ALERT NO CONFLICT
       
 41786   // =================
       
 41787 
       
 41788   $.fn.alert.noConflict = function () {
       
 41789     $.fn.alert = old
       
 41790     return this
       
 41791   }
       
 41792 
       
 41793 
       
 41794   // ALERT DATA-API
       
 41795   // ==============
       
 41796 
       
 41797   $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)
       
 41798 
       
 41799 }(jQuery);
       
 41800 
       
 41801 /* ========================================================================
       
 41802  * Bootstrap: button.js v3.1.1
       
 41803  * http://getbootstrap.com/javascript/#buttons
       
 41804  * ========================================================================
       
 41805  * Copyright 2011-2014 Twitter, Inc.
       
 41806  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
       
 41807  * ======================================================================== */
       
 41808 
       
 41809 
       
 41810 +function ($) {
       
 41811   'use strict';
       
 41812 
       
 41813   // BUTTON PUBLIC CLASS DEFINITION
       
 41814   // ==============================
       
 41815 
       
 41816   var Button = function (element, options) {
       
 41817     this.$element  = $(element)
       
 41818     this.options   = $.extend({}, Button.DEFAULTS, options)
       
 41819     this.isLoading = false
       
 41820   }
       
 41821 
       
 41822   Button.DEFAULTS = {
       
 41823     loadingText: 'loading...'
       
 41824   }
       
 41825 
       
 41826   Button.prototype.setState = function (state) {
       
 41827     var d    = 'disabled'
       
 41828     var $el  = this.$element
       
 41829     var val  = $el.is('input') ? 'val' : 'html'
       
 41830     var data = $el.data()
       
 41831 
       
 41832     state = state + 'Text'
       
 41833 
       
 41834     if (!data.resetText) $el.data('resetText', $el[val]())
       
 41835 
       
 41836     $el[val](data[state] || this.options[state])
       
 41837 
       
 41838     // push to event loop to allow forms to submit
       
 41839     setTimeout($.proxy(function () {
       
 41840       if (state == 'loadingText') {
       
 41841         this.isLoading = true
       
 41842         $el.addClass(d).attr(d, d)
       
 41843       } else if (this.isLoading) {
       
 41844         this.isLoading = false
       
 41845         $el.removeClass(d).removeAttr(d)
       
 41846       }
       
 41847     }, this), 0)
       
 41848   }
       
 41849 
       
 41850   Button.prototype.toggle = function () {
       
 41851     var changed = true
       
 41852     var $parent = this.$element.closest('[data-toggle="buttons"]')
       
 41853 
       
 41854     if ($parent.length) {
       
 41855       var $input = this.$element.find('input')
       
 41856       if ($input.prop('type') == 'radio') {
       
 41857         if ($input.prop('checked') && this.$element.hasClass('active')) changed = false
       
 41858         else $parent.find('.active').removeClass('active')
       
 41859       }
       
 41860       if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change')
       
 41861     }
       
 41862 
       
 41863     if (changed) this.$element.toggleClass('active')
       
 41864   }
       
 41865 
       
 41866 
       
 41867   // BUTTON PLUGIN DEFINITION
       
 41868   // ========================
       
 41869 
       
 41870   var old = $.fn.button
       
 41871 
       
 41872   $.fn.button = function (option) {
       
 41873     return this.each(function () {
       
 41874       var $this   = $(this)
       
 41875       var data    = $this.data('bs.button')
       
 41876       var options = typeof option == 'object' && option
       
 41877 
       
 41878       if (!data) $this.data('bs.button', (data = new Button(this, options)))
       
 41879 
       
 41880       if (option == 'toggle') data.toggle()
       
 41881       else if (option) data.setState(option)
       
 41882     })
       
 41883   }
       
 41884 
       
 41885   $.fn.button.Constructor = Button
       
 41886 
       
 41887 
       
 41888   // BUTTON NO CONFLICT
       
 41889   // ==================
       
 41890 
       
 41891   $.fn.button.noConflict = function () {
       
 41892     $.fn.button = old
       
 41893     return this
       
 41894   }
       
 41895 
       
 41896 
       
 41897   // BUTTON DATA-API
       
 41898   // ===============
       
 41899 
       
 41900   $(document).on('click.bs.button.data-api', '[data-toggle^=button]', function (e) {
       
 41901     var $btn = $(e.target)
       
 41902     if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
       
 41903     $btn.button('toggle')
       
 41904     e.preventDefault()
       
 41905   })
       
 41906 
       
 41907 }(jQuery);
       
 41908 
       
 41909 /* ========================================================================
       
 41910  * Bootstrap: carousel.js v3.1.1
       
 41911  * http://getbootstrap.com/javascript/#carousel
       
 41912  * ========================================================================
       
 41913  * Copyright 2011-2014 Twitter, Inc.
       
 41914  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
       
 41915  * ======================================================================== */
       
 41916 
       
 41917 
       
 41918 +function ($) {
       
 41919   'use strict';
       
 41920 
       
 41921   // CAROUSEL CLASS DEFINITION
       
 41922   // =========================
       
 41923 
       
 41924   var Carousel = function (element, options) {
       
 41925     this.$element    = $(element)
       
 41926     this.$indicators = this.$element.find('.carousel-indicators')
       
 41927     this.options     = options
       
 41928     this.paused      =
       
 41929     this.sliding     =
       
 41930     this.interval    =
       
 41931     this.$active     =
       
 41932     this.$items      = null
       
 41933 
       
 41934     this.options.pause == 'hover' && this.$element
       
 41935       .on('mouseenter', $.proxy(this.pause, this))
       
 41936       .on('mouseleave', $.proxy(this.cycle, this))
       
 41937   }
       
 41938 
       
 41939   Carousel.DEFAULTS = {
       
 41940     interval: 5000,
       
 41941     pause: 'hover',
       
 41942     wrap: true
       
 41943   }
       
 41944 
       
 41945   Carousel.prototype.cycle =  function (e) {
       
 41946     e || (this.paused = false)
       
 41947 
       
 41948     this.interval && clearInterval(this.interval)
       
 41949 
       
 41950     this.options.interval
       
 41951       && !this.paused
       
 41952       && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
       
 41953 
       
 41954     return this
       
 41955   }
       
 41956 
       
 41957   Carousel.prototype.getActiveIndex = function () {
       
 41958     this.$active = this.$element.find('.item.active')
       
 41959     this.$items  = this.$active.parent().children()
       
 41960 
       
 41961     return this.$items.index(this.$active)
       
 41962   }
       
 41963 
       
 41964   Carousel.prototype.to = function (pos) {
       
 41965     var that        = this
       
 41966     var activeIndex = this.getActiveIndex()
       
 41967 
       
 41968     if (pos > (this.$items.length - 1) || pos < 0) return
       
 41969 
       
 41970     if (this.sliding)       return this.$element.one('slid.bs.carousel', function () { that.to(pos) })
       
 41971     if (activeIndex == pos) return this.pause().cycle()
       
 41972 
       
 41973     return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos]))
       
 41974   }
       
 41975 
       
 41976   Carousel.prototype.pause = function (e) {
       
 41977     e || (this.paused = true)
       
 41978 
       
 41979     if (this.$element.find('.next, .prev').length && $.support.transition) {
       
 41980       this.$element.trigger($.support.transition.end)
       
 41981       this.cycle(true)
       
 41982     }
       
 41983 
       
 41984     this.interval = clearInterval(this.interval)
       
 41985 
       
 41986     return this
       
 41987   }
       
 41988 
       
 41989   Carousel.prototype.next = function () {
       
 41990     if (this.sliding) return
       
 41991     return this.slide('next')
       
 41992   }
       
 41993 
       
 41994   Carousel.prototype.prev = function () {
       
 41995     if (this.sliding) return
       
 41996     return this.slide('prev')
       
 41997   }
       
 41998 
       
 41999   Carousel.prototype.slide = function (type, next) {
       
 42000     var $active   = this.$element.find('.item.active')
       
 42001     var $next     = next || $active[type]()
       
 42002     var isCycling = this.interval
       
 42003     var direction = type == 'next' ? 'left' : 'right'
       
 42004     var fallback  = type == 'next' ? 'first' : 'last'
       
 42005     var that      = this
       
 42006 
       
 42007     if (!$next.length) {
       
 42008       if (!this.options.wrap) return
       
 42009       $next = this.$element.find('.item')[fallback]()
       
 42010     }
       
 42011 
       
 42012     if ($next.hasClass('active')) return this.sliding = false
       
 42013 
       
 42014     var e = $.Event('slide.bs.carousel', { relatedTarget: $next[0], direction: direction })
       
 42015     this.$element.trigger(e)
       
 42016     if (e.isDefaultPrevented()) return
       
 42017 
       
 42018     this.sliding = true
       
 42019 
       
 42020     isCycling && this.pause()
       
 42021 
       
 42022     if (this.$indicators.length) {
       
 42023       this.$indicators.find('.active').removeClass('active')
       
 42024       this.$element.one('slid.bs.carousel', function () {
       
 42025         var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()])
       
 42026         $nextIndicator && $nextIndicator.addClass('active')
       
 42027       })
       
 42028     }
       
 42029 
       
 42030     if ($.support.transition && this.$element.hasClass('slide')) {
       
 42031       $next.addClass(type)
       
 42032       $next[0].offsetWidth // force reflow
       
 42033       $active.addClass(direction)
       
 42034       $next.addClass(direction)
       
 42035       $active
       
 42036         .one($.support.transition.end, function () {
       
 42037           $next.removeClass([type, direction].join(' ')).addClass('active')
       
 42038           $active.removeClass(['active', direction].join(' '))
       
 42039           that.sliding = false
       
 42040           setTimeout(function () { that.$element.trigger('slid.bs.carousel') }, 0)
       
 42041         })
       
 42042         .emulateTransitionEnd($active.css('transition-duration').slice(0, -1) * 1000)
       
 42043     } else {
       
 42044       $active.removeClass('active')
       
 42045       $next.addClass('active')
       
 42046       this.sliding = false
       
 42047       this.$element.trigger('slid.bs.carousel')
       
 42048     }
       
 42049 
       
 42050     isCycling && this.cycle()
       
 42051 
       
 42052     return this
       
 42053   }
       
 42054 
       
 42055 
       
 42056   // CAROUSEL PLUGIN DEFINITION
       
 42057   // ==========================
       
 42058 
       
 42059   var old = $.fn.carousel
       
 42060 
       
 42061   $.fn.carousel = function (option) {
       
 42062     return this.each(function () {
       
 42063       var $this   = $(this)
       
 42064       var data    = $this.data('bs.carousel')
       
 42065       var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option)
       
 42066       var action  = typeof option == 'string' ? option : options.slide
       
 42067 
       
 42068       if (!data) $this.data('bs.carousel', (data = new Carousel(this, options)))
       
 42069       if (typeof option == 'number') data.to(option)
       
 42070       else if (action) data[action]()
       
 42071       else if (options.interval) data.pause().cycle()
       
 42072     })
       
 42073   }
       
 42074 
       
 42075   $.fn.carousel.Constructor = Carousel
       
 42076 
       
 42077 
       
 42078   // CAROUSEL NO CONFLICT
       
 42079   // ====================
       
 42080 
       
 42081   $.fn.carousel.noConflict = function () {
       
 42082     $.fn.carousel = old
       
 42083     return this
       
 42084   }
       
 42085 
       
 42086 
       
 42087   // CAROUSEL DATA-API
       
 42088   // =================
       
 42089 
       
 42090   $(document).on('click.bs.carousel.data-api', '[data-slide], [data-slide-to]', function (e) {
       
 42091     var $this   = $(this), href
       
 42092     var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
       
 42093     var options = $.extend({}, $target.data(), $this.data())
       
 42094     var slideIndex = $this.attr('data-slide-to')
       
 42095     if (slideIndex) options.interval = false
       
 42096 
       
 42097     $target.carousel(options)
       
 42098 
       
 42099     if (slideIndex = $this.attr('data-slide-to')) {
       
 42100       $target.data('bs.carousel').to(slideIndex)
       
 42101     }
       
 42102 
       
 42103     e.preventDefault()
       
 42104   })
       
 42105 
       
 42106   $(window).on('load', function () {
       
 42107     $('[data-ride="carousel"]').each(function () {
       
 42108       var $carousel = $(this)
       
 42109       $carousel.carousel($carousel.data())
       
 42110     })
       
 42111   })
       
 42112 
       
 42113 }(jQuery);
       
 42114 
       
 42115 /* ========================================================================
       
 42116  * Bootstrap: collapse.js v3.1.1
       
 42117  * http://getbootstrap.com/javascript/#collapse
       
 42118  * ========================================================================
       
 42119  * Copyright 2011-2014 Twitter, Inc.
       
 42120  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
       
 42121  * ======================================================================== */
       
 42122 
       
 42123 
       
 42124 +function ($) {
       
 42125   'use strict';
       
 42126 
       
 42127   // COLLAPSE PUBLIC CLASS DEFINITION
       
 42128   // ================================
       
 42129 
       
 42130   var Collapse = function (element, options) {
       
 42131     this.$element      = $(element)
       
 42132     this.options       = $.extend({}, Collapse.DEFAULTS, options)
       
 42133     this.transitioning = null
       
 42134 
       
 42135     if (this.options.parent) this.$parent = $(this.options.parent)
       
 42136     if (this.options.toggle) this.toggle()
       
 42137   }
       
 42138 
       
 42139   Collapse.DEFAULTS = {
       
 42140     toggle: true
       
 42141   }
       
 42142 
       
 42143   Collapse.prototype.dimension = function () {
       
 42144     var hasWidth = this.$element.hasClass('width')
       
 42145     return hasWidth ? 'width' : 'height'
       
 42146   }
       
 42147 
       
 42148   Collapse.prototype.show = function () {
       
 42149     if (this.transitioning || this.$element.hasClass('in')) return
       
 42150 
       
 42151     var startEvent = $.Event('show.bs.collapse')
       
 42152     this.$element.trigger(startEvent)
       
 42153     if (startEvent.isDefaultPrevented()) return
       
 42154 
       
 42155     var actives = this.$parent && this.$parent.find('> .panel > .in')
       
 42156 
       
 42157     if (actives && actives.length) {
       
 42158       var hasData = actives.data('bs.collapse')
       
 42159       if (hasData && hasData.transitioning) return
       
 42160       actives.collapse('hide')
       
 42161       hasData || actives.data('bs.collapse', null)
       
 42162     }
       
 42163 
       
 42164     var dimension = this.dimension()
       
 42165 
       
 42166     this.$element
       
 42167       .removeClass('collapse')
       
 42168       .addClass('collapsing')
       
 42169       [dimension](0)
       
 42170 
       
 42171     this.transitioning = 1
       
 42172 
       
 42173     var complete = function () {
       
 42174       this.$element
       
 42175         .removeClass('collapsing')
       
 42176         .addClass('collapse in')
       
 42177         [dimension]('auto')
       
 42178       this.transitioning = 0
       
 42179       this.$element.trigger('shown.bs.collapse')
       
 42180     }
       
 42181 
       
 42182     if (!$.support.transition) return complete.call(this)
       
 42183 
       
 42184     var scrollSize = $.camelCase(['scroll', dimension].join('-'))
       
 42185 
       
 42186     this.$element
       
 42187       .one($.support.transition.end, $.proxy(complete, this))
       
 42188       .emulateTransitionEnd(350)
       
 42189       [dimension](this.$element[0][scrollSize])
       
 42190   }
       
 42191 
       
 42192   Collapse.prototype.hide = function () {
       
 42193     if (this.transitioning || !this.$element.hasClass('in')) return
       
 42194 
       
 42195     var startEvent = $.Event('hide.bs.collapse')
       
 42196     this.$element.trigger(startEvent)
       
 42197     if (startEvent.isDefaultPrevented()) return
       
 42198 
       
 42199     var dimension = this.dimension()
       
 42200 
       
 42201     this.$element
       
 42202       [dimension](this.$element[dimension]())
       
 42203       [0].offsetHeight
       
 42204 
       
 42205     this.$element
       
 42206       .addClass('collapsing')
       
 42207       .removeClass('collapse')
       
 42208       .removeClass('in')
       
 42209 
       
 42210     this.transitioning = 1
       
 42211 
       
 42212     var complete = function () {
       
 42213       this.transitioning = 0
       
 42214       this.$element
       
 42215         .trigger('hidden.bs.collapse')
       
 42216         .removeClass('collapsing')
       
 42217         .addClass('collapse')
       
 42218     }
       
 42219 
       
 42220     if (!$.support.transition) return complete.call(this)
       
 42221 
       
 42222     this.$element
       
 42223       [dimension](0)
       
 42224       .one($.support.transition.end, $.proxy(complete, this))
       
 42225       .emulateTransitionEnd(350)
       
 42226   }
       
 42227 
       
 42228   Collapse.prototype.toggle = function () {
       
 42229     this[this.$element.hasClass('in') ? 'hide' : 'show']()
       
 42230   }
       
 42231 
       
 42232 
       
 42233   // COLLAPSE PLUGIN DEFINITION
       
 42234   // ==========================
       
 42235 
       
 42236   var old = $.fn.collapse
       
 42237 
       
 42238   $.fn.collapse = function (option) {
       
 42239     return this.each(function () {
       
 42240       var $this   = $(this)
       
 42241       var data    = $this.data('bs.collapse')
       
 42242       var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
       
 42243 
       
 42244       if (!data && options.toggle && option == 'show') option = !option
       
 42245       if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
       
 42246       if (typeof option == 'string') data[option]()
       
 42247     })
       
 42248   }
       
 42249 
       
 42250   $.fn.collapse.Constructor = Collapse
       
 42251 
       
 42252 
       
 42253   // COLLAPSE NO CONFLICT
       
 42254   // ====================
       
 42255 
       
 42256   $.fn.collapse.noConflict = function () {
       
 42257     $.fn.collapse = old
       
 42258     return this
       
 42259   }
       
 42260 
       
 42261 
       
 42262   // COLLAPSE DATA-API
       
 42263   // =================
       
 42264 
       
 42265   $(document).on('click.bs.collapse.data-api', '[data-toggle=collapse]', function (e) {
       
 42266     var $this   = $(this), href
       
 42267     var target  = $this.attr('data-target')
       
 42268         || e.preventDefault()
       
 42269         || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7
       
 42270     var $target = $(target)
       
 42271     var data    = $target.data('bs.collapse')
       
 42272     var option  = data ? 'toggle' : $this.data()
       
 42273     var parent  = $this.attr('data-parent')
       
 42274     var $parent = parent && $(parent)
       
 42275 
       
 42276     if (!data || !data.transitioning) {
       
 42277       if ($parent) $parent.find('[data-toggle=collapse][data-parent="' + parent + '"]').not($this).addClass('collapsed')
       
 42278       $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed')
       
 42279     }
       
 42280 
       
 42281     $target.collapse(option)
       
 42282   })
       
 42283 
       
 42284 }(jQuery);
       
 42285 
       
 42286 /* ========================================================================
       
 42287  * Bootstrap: dropdown.js v3.1.1
       
 42288  * http://getbootstrap.com/javascript/#dropdowns
       
 42289  * ========================================================================
       
 42290  * Copyright 2011-2014 Twitter, Inc.
       
 42291  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
       
 42292  * ======================================================================== */
       
 42293 
       
 42294 
       
 42295 +function ($) {
       
 42296   'use strict';
       
 42297 
       
 42298   // DROPDOWN CLASS DEFINITION
       
 42299   // =========================
       
 42300 
       
 42301   var backdrop = '.dropdown-backdrop'
       
 42302   var toggle   = '[data-toggle=dropdown]'
       
 42303   var Dropdown = function (element) {
       
 42304     $(element).on('click.bs.dropdown', this.toggle)
       
 42305   }
       
 42306 
       
 42307   Dropdown.prototype.toggle = function (e) {
       
 42308     var $this = $(this)
       
 42309 
       
 42310     if ($this.is('.disabled, :disabled')) return
       
 42311 
       
 42312     var $parent  = getParent($this)
       
 42313     var isActive = $parent.hasClass('open')
       
 42314 
       
 42315     clearMenus()
       
 42316 
       
 42317     if (!isActive) {
       
 42318       if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
       
 42319         // if mobile we use a backdrop because click events don't delegate
       
 42320         $('<div class="dropdown-backdrop"/>').insertAfter($(this)).on('click', clearMenus)
       
 42321       }
       
 42322 
       
 42323       var relatedTarget = { relatedTarget: this }
       
 42324       $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
       
 42325 
       
 42326       if (e.isDefaultPrevented()) return
       
 42327 
       
 42328       $parent
       
 42329         .toggleClass('open')
       
 42330         .trigger('shown.bs.dropdown', relatedTarget)
       
 42331 
       
 42332       $this.focus()
       
 42333     }
       
 42334 
       
 42335     return false
       
 42336   }
       
 42337 
       
 42338   Dropdown.prototype.keydown = function (e) {
       
 42339     if (!/(38|40|27)/.test(e.keyCode)) return
       
 42340 
       
 42341     var $this = $(this)
       
 42342 
       
 42343     e.preventDefault()
       
 42344     e.stopPropagation()
       
 42345 
       
 42346     if ($this.is('.disabled, :disabled')) return
       
 42347 
       
 42348     var $parent  = getParent($this)
       
 42349     var isActive = $parent.hasClass('open')
       
 42350 
       
 42351     if (!isActive || (isActive && e.keyCode == 27)) {
       
 42352       if (e.which == 27) $parent.find(toggle).focus()
       
 42353       return $this.click()
       
 42354     }
       
 42355 
       
 42356     var desc = ' li:not(.divider):visible a'
       
 42357     var $items = $parent.find('[role=menu]' + desc + ', [role=listbox]' + desc)
       
 42358 
       
 42359     if (!$items.length) return
       
 42360 
       
 42361     var index = $items.index($items.filter(':focus'))
       
 42362 
       
 42363     if (e.keyCode == 38 && index > 0)                 index--                        // up
       
 42364     if (e.keyCode == 40 && index < $items.length - 1) index++                        // down
       
 42365     if (!~index)                                      index = 0
       
 42366 
       
 42367     $items.eq(index).focus()
       
 42368   }
       
 42369 
       
 42370   function clearMenus(e) {
       
 42371     $(backdrop).remove()
       
 42372     $(toggle).each(function () {
       
 42373       var $parent = getParent($(this))
       
 42374       var relatedTarget = { relatedTarget: this }
       
 42375       if (!$parent.hasClass('open')) return
       
 42376       $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
       
 42377       if (e.isDefaultPrevented()) return
       
 42378       $parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
       
 42379     })
       
 42380   }
       
 42381 
       
 42382   function getParent($this) {
       
 42383     var selector = $this.attr('data-target')
       
 42384 
       
 42385     if (!selector) {
       
 42386       selector = $this.attr('href')
       
 42387       selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
       
 42388     }
       
 42389 
       
 42390     var $parent = selector && $(selector)
       
 42391 
       
 42392     return $parent && $parent.length ? $parent : $this.parent()
       
 42393   }
       
 42394 
       
 42395 
       
 42396   // DROPDOWN PLUGIN DEFINITION
       
 42397   // ==========================
       
 42398 
       
 42399   var old = $.fn.dropdown
       
 42400 
       
 42401   $.fn.dropdown = function (option) {
       
 42402     return this.each(function () {
       
 42403       var $this = $(this)
       
 42404       var data  = $this.data('bs.dropdown')
       
 42405 
       
 42406       if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))
       
 42407       if (typeof option == 'string') data[option].call($this)
       
 42408     })
       
 42409   }
       
 42410 
       
 42411   $.fn.dropdown.Constructor = Dropdown
       
 42412 
       
 42413 
       
 42414   // DROPDOWN NO CONFLICT
       
 42415   // ====================
       
 42416 
       
 42417   $.fn.dropdown.noConflict = function () {
       
 42418     $.fn.dropdown = old
       
 42419     return this
       
 42420   }
       
 42421 
       
 42422 
       
 42423   // APPLY TO STANDARD DROPDOWN ELEMENTS
       
 42424   // ===================================
       
 42425 
       
 42426   $(document)
       
 42427     .on('click.bs.dropdown.data-api', clearMenus)
       
 42428     .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
       
 42429     .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
       
 42430     .on('keydown.bs.dropdown.data-api', toggle + ', [role=menu], [role=listbox]', Dropdown.prototype.keydown)
       
 42431 
       
 42432 }(jQuery);
       
 42433 
       
 42434 /* ========================================================================
       
 42435  * Bootstrap: modal.js v3.1.1
       
 42436  * http://getbootstrap.com/javascript/#modals
       
 42437  * ========================================================================
       
 42438  * Copyright 2011-2014 Twitter, Inc.
       
 42439  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
       
 42440  * ======================================================================== */
       
 42441 
       
 42442 
       
 42443 +function ($) {
       
 42444   'use strict';
       
 42445 
       
 42446   // MODAL CLASS DEFINITION
       
 42447   // ======================
       
 42448 
       
 42449   var Modal = function (element, options) {
       
 42450     this.options   = options
       
 42451     this.$element  = $(element)
       
 42452     this.$backdrop =
       
 42453     this.isShown   = null
       
 42454 
       
 42455     if (this.options.remote) {
       
 42456       this.$element
       
 42457         .find('.modal-content')
       
 42458         .load(this.options.remote, $.proxy(function () {
       
 42459           this.$element.trigger('loaded.bs.modal')
       
 42460         }, this))
       
 42461     }
       
 42462   }
       
 42463 
       
 42464   Modal.DEFAULTS = {
       
 42465     backdrop: true,
       
 42466     keyboard: true,
       
 42467     show: true
       
 42468   }
       
 42469 
       
 42470   Modal.prototype.toggle = function (_relatedTarget) {
       
 42471     return this[!this.isShown ? 'show' : 'hide'](_relatedTarget)
       
 42472   }
       
 42473 
       
 42474   Modal.prototype.show = function (_relatedTarget) {
       
 42475     var that = this
       
 42476     var e    = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
       
 42477 
       
 42478     this.$element.trigger(e)
       
 42479 
       
 42480     if (this.isShown || e.isDefaultPrevented()) return
       
 42481 
       
 42482     this.isShown = true
       
 42483 
       
 42484     this.escape()
       
 42485 
       
 42486     this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
       
 42487 
       
 42488     this.backdrop(function () {
       
 42489       var transition = $.support.transition && that.$element.hasClass('fade')
       
 42490 
       
 42491       if (!that.$element.parent().length) {
       
 42492         that.$element.appendTo(document.body) // don't move modals dom position
       
 42493       }
       
 42494 
       
 42495       that.$element
       
 42496         .show()
       
 42497         .scrollTop(0)
       
 42498 
       
 42499       if (transition) {
       
 42500         that.$element[0].offsetWidth // force reflow
       
 42501       }
       
 42502 
       
 42503       that.$element
       
 42504         .addClass('in')
       
 42505         .attr('aria-hidden', false)
       
 42506 
       
 42507       that.enforceFocus()
       
 42508 
       
 42509       var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
       
 42510 
       
 42511       transition ?
       
 42512         that.$element.find('.modal-dialog') // wait for modal to slide in
       
 42513           .one($.support.transition.end, function () {
       
 42514             that.$element.focus().trigger(e)
       
 42515           })
       
 42516           .emulateTransitionEnd(300) :
       
 42517         that.$element.focus().trigger(e)
       
 42518     })
       
 42519   }
       
 42520 
       
 42521   Modal.prototype.hide = function (e) {
       
 42522     if (e) e.preventDefault()
       
 42523 
       
 42524     e = $.Event('hide.bs.modal')
       
 42525 
       
 42526     this.$element.trigger(e)
       
 42527 
       
 42528     if (!this.isShown || e.isDefaultPrevented()) return
       
 42529 
       
 42530     this.isShown = false
       
 42531 
       
 42532     this.escape()
       
 42533 
       
 42534     $(document).off('focusin.bs.modal')
       
 42535 
       
 42536     this.$element
       
 42537       .removeClass('in')
       
 42538       .attr('aria-hidden', true)
       
 42539       .off('click.dismiss.bs.modal')
       
 42540 
       
 42541     $.support.transition && this.$element.hasClass('fade') ?
       
 42542       this.$element
       
 42543         .one($.support.transition.end, $.proxy(this.hideModal, this))
       
 42544         .emulateTransitionEnd(300) :
       
 42545       this.hideModal()
       
 42546   }
       
 42547 
       
 42548   Modal.prototype.enforceFocus = function () {
       
 42549     $(document)
       
 42550       .off('focusin.bs.modal') // guard against infinite focus loop
       
 42551       .on('focusin.bs.modal', $.proxy(function (e) {
       
 42552         if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {
       
 42553           this.$element.focus()
       
 42554         }
       
 42555       }, this))
       
 42556   }
       
 42557 
       
 42558   Modal.prototype.escape = function () {
       
 42559     if (this.isShown && this.options.keyboard) {
       
 42560       this.$element.on('keyup.dismiss.bs.modal', $.proxy(function (e) {
       
 42561         e.which == 27 && this.hide()
       
 42562       }, this))
       
 42563     } else if (!this.isShown) {
       
 42564       this.$element.off('keyup.dismiss.bs.modal')
       
 42565     }
       
 42566   }
       
 42567 
       
 42568   Modal.prototype.hideModal = function () {
       
 42569     var that = this
       
 42570     this.$element.hide()
       
 42571     this.backdrop(function () {
       
 42572       that.removeBackdrop()
       
 42573       that.$element.trigger('hidden.bs.modal')
       
 42574     })
       
 42575   }
       
 42576 
       
 42577   Modal.prototype.removeBackdrop = function () {
       
 42578     this.$backdrop && this.$backdrop.remove()
       
 42579     this.$backdrop = null
       
 42580   }
       
 42581 
       
 42582   Modal.prototype.backdrop = function (callback) {
       
 42583     var animate = this.$element.hasClass('fade') ? 'fade' : ''
       
 42584 
       
 42585     if (this.isShown && this.options.backdrop) {
       
 42586       var doAnimate = $.support.transition && animate
       
 42587 
       
 42588       this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
       
 42589         .appendTo(document.body)
       
 42590 
       
 42591       this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {
       
 42592         if (e.target !== e.currentTarget) return
       
 42593         this.options.backdrop == 'static'
       
 42594           ? this.$element[0].focus.call(this.$element[0])
       
 42595           : this.hide.call(this)
       
 42596       }, this))
       
 42597 
       
 42598       if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
       
 42599 
       
 42600       this.$backdrop.addClass('in')
       
 42601 
       
 42602       if (!callback) return
       
 42603 
       
 42604       doAnimate ?
       
 42605         this.$backdrop
       
 42606           .one($.support.transition.end, callback)
       
 42607           .emulateTransitionEnd(150) :
       
 42608         callback()
       
 42609 
       
 42610     } else if (!this.isShown && this.$backdrop) {
       
 42611       this.$backdrop.removeClass('in')
       
 42612 
       
 42613       $.support.transition && this.$element.hasClass('fade') ?
       
 42614         this.$backdrop
       
 42615           .one($.support.transition.end, callback)
       
 42616           .emulateTransitionEnd(150) :
       
 42617         callback()
       
 42618 
       
 42619     } else if (callback) {
       
 42620       callback()
       
 42621     }
       
 42622   }
       
 42623 
       
 42624 
       
 42625   // MODAL PLUGIN DEFINITION
       
 42626   // =======================
       
 42627 
       
 42628   var old = $.fn.modal
       
 42629 
       
 42630   $.fn.modal = function (option, _relatedTarget) {
       
 42631     return this.each(function () {
       
 42632       var $this   = $(this)
       
 42633       var data    = $this.data('bs.modal')
       
 42634       var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)
       
 42635 
       
 42636       if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
       
 42637       if (typeof option == 'string') data[option](_relatedTarget)
       
 42638       else if (options.show) data.show(_relatedTarget)
       
 42639     })
       
 42640   }
       
 42641 
       
 42642   $.fn.modal.Constructor = Modal
       
 42643 
       
 42644 
       
 42645   // MODAL NO CONFLICT
       
 42646   // =================
       
 42647 
       
 42648   $.fn.modal.noConflict = function () {
       
 42649     $.fn.modal = old
       
 42650     return this
       
 42651   }
       
 42652 
       
 42653 
       
 42654   // MODAL DATA-API
       
 42655   // ==============
       
 42656 
       
 42657   $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
       
 42658     var $this   = $(this)
       
 42659     var href    = $this.attr('href')
       
 42660     var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) //strip for ie7
       
 42661     var option  = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
       
 42662 
       
 42663     if ($this.is('a')) e.preventDefault()
       
 42664 
       
 42665     $target
       
 42666       .modal(option, this)
       
 42667       .one('hide', function () {
       
 42668         $this.is(':visible') && $this.focus()
       
 42669       })
       
 42670   })
       
 42671 
       
 42672   $(document)
       
 42673     .on('show.bs.modal', '.modal', function () { $(document.body).addClass('modal-open') })
       
 42674     .on('hidden.bs.modal', '.modal', function () { $(document.body).removeClass('modal-open') })
       
 42675 
       
 42676 }(jQuery);
       
 42677 
       
 42678 /* ========================================================================
       
 42679  * Bootstrap: tooltip.js v3.1.1
       
 42680  * http://getbootstrap.com/javascript/#tooltip
       
 42681  * Inspired by the original jQuery.tipsy by Jason Frame
       
 42682  * ========================================================================
       
 42683  * Copyright 2011-2014 Twitter, Inc.
       
 42684  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
       
 42685  * ======================================================================== */
       
 42686 
       
 42687 
       
 42688 +function ($) {
       
 42689   'use strict';
       
 42690 
       
 42691   // TOOLTIP PUBLIC CLASS DEFINITION
       
 42692   // ===============================
       
 42693 
       
 42694   var Tooltip = function (element, options) {
       
 42695     this.type       =
       
 42696     this.options    =
       
 42697     this.enabled    =
       
 42698     this.timeout    =
       
 42699     this.hoverState =
       
 42700     this.$element   = null
       
 42701 
       
 42702     this.init('tooltip', element, options)
       
 42703   }
       
 42704 
       
 42705   Tooltip.DEFAULTS = {
       
 42706     animation: true,
       
 42707     placement: 'top',
       
 42708     selector: false,
       
 42709     template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
       
 42710     trigger: 'hover focus',
       
 42711     title: '',
       
 42712     delay: 0,
       
 42713     html: false,
       
 42714     container: false
       
 42715   }
       
 42716 
       
 42717   Tooltip.prototype.init = function (type, element, options) {
       
 42718     this.enabled  = true
       
 42719     this.type     = type
       
 42720     this.$element = $(element)
       
 42721     this.options  = this.getOptions(options)
       
 42722 
       
 42723     var triggers = this.options.trigger.split(' ')
       
 42724 
       
 42725     for (var i = triggers.length; i--;) {
       
 42726       var trigger = triggers[i]
       
 42727 
       
 42728       if (trigger == 'click') {
       
 42729         this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
       
 42730       } else if (trigger != 'manual') {
       
 42731         var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin'
       
 42732         var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
       
 42733 
       
 42734         this.$element.on(eventIn  + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
       
 42735         this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
       
 42736       }
       
 42737     }
       
 42738 
       
 42739     this.options.selector ?
       
 42740       (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
       
 42741       this.fixTitle()
       
 42742   }
       
 42743 
       
 42744   Tooltip.prototype.getDefaults = function () {
       
 42745     return Tooltip.DEFAULTS
       
 42746   }
       
 42747 
       
 42748   Tooltip.prototype.getOptions = function (options) {
       
 42749     options = $.extend({}, this.getDefaults(), this.$element.data(), options)
       
 42750 
       
 42751     if (options.delay && typeof options.delay == 'number') {
       
 42752       options.delay = {
       
 42753         show: options.delay,
       
 42754         hide: options.delay
       
 42755       }
       
 42756     }
       
 42757 
       
 42758     return options
       
 42759   }
       
 42760 
       
 42761   Tooltip.prototype.getDelegateOptions = function () {
       
 42762     var options  = {}
       
 42763     var defaults = this.getDefaults()
       
 42764 
       
 42765     this._options && $.each(this._options, function (key, value) {
       
 42766       if (defaults[key] != value) options[key] = value
       
 42767     })
       
 42768 
       
 42769     return options
       
 42770   }
       
 42771 
       
 42772   Tooltip.prototype.enter = function (obj) {
       
 42773     var self = obj instanceof this.constructor ?
       
 42774       obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
       
 42775 
       
 42776     clearTimeout(self.timeout)
       
 42777 
       
 42778     self.hoverState = 'in'
       
 42779 
       
 42780     if (!self.options.delay || !self.options.delay.show) return self.show()
       
 42781 
       
 42782     self.timeout = setTimeout(function () {
       
 42783       if (self.hoverState == 'in') self.show()
       
 42784     }, self.options.delay.show)
       
 42785   }
       
 42786 
       
 42787   Tooltip.prototype.leave = function (obj) {
       
 42788     var self = obj instanceof this.constructor ?
       
 42789       obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
       
 42790 
       
 42791     clearTimeout(self.timeout)
       
 42792 
       
 42793     self.hoverState = 'out'
       
 42794 
       
 42795     if (!self.options.delay || !self.options.delay.hide) return self.hide()
       
 42796 
       
 42797     self.timeout = setTimeout(function () {
       
 42798       if (self.hoverState == 'out') self.hide()
       
 42799     }, self.options.delay.hide)
       
 42800   }
       
 42801 
       
 42802   Tooltip.prototype.show = function () {
       
 42803     var e = $.Event('show.bs.' + this.type)
       
 42804 
       
 42805     if (this.hasContent() && this.enabled) {
       
 42806       this.$element.trigger(e)
       
 42807 
       
 42808       if (e.isDefaultPrevented()) return
       
 42809       var that = this;
       
 42810 
       
 42811       var $tip = this.tip()
       
 42812 
       
 42813       this.setContent()
       
 42814 
       
 42815       if (this.options.animation) $tip.addClass('fade')
       
 42816 
       
 42817       var placement = typeof this.options.placement == 'function' ?
       
 42818         this.options.placement.call(this, $tip[0], this.$element[0]) :
       
 42819         this.options.placement
       
 42820 
       
 42821       var autoToken = /\s?auto?\s?/i
       
 42822       var autoPlace = autoToken.test(placement)
       
 42823       if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
       
 42824 
       
 42825       $tip
       
 42826         .detach()
       
 42827         .css({ top: 0, left: 0, display: 'block' })
       
 42828         .addClass(placement)
       
 42829 
       
 42830       this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
       
 42831 
       
 42832       var pos          = this.getPosition()
       
 42833       var actualWidth  = $tip[0].offsetWidth
       
 42834       var actualHeight = $tip[0].offsetHeight
       
 42835 
       
 42836       if (autoPlace) {
       
 42837         var $parent = this.$element.parent()
       
 42838 
       
 42839         var orgPlacement = placement
       
 42840         var docScroll    = document.documentElement.scrollTop || document.body.scrollTop
       
 42841         var parentWidth  = this.options.container == 'body' ? window.innerWidth  : $parent.outerWidth()
       
 42842         var parentHeight = this.options.container == 'body' ? window.innerHeight : $parent.outerHeight()
       
 42843         var parentLeft   = this.options.container == 'body' ? 0 : $parent.offset().left
       
 42844 
       
 42845         placement = placement == 'bottom' && pos.top   + pos.height  + actualHeight - docScroll > parentHeight  ? 'top'    :
       
 42846                     placement == 'top'    && pos.top   - docScroll   - actualHeight < 0                         ? 'bottom' :
       
 42847                     placement == 'right'  && pos.right + actualWidth > parentWidth                              ? 'left'   :
       
 42848                     placement == 'left'   && pos.left  - actualWidth < parentLeft                               ? 'right'  :
       
 42849                     placement
       
 42850 
       
 42851         $tip
       
 42852           .removeClass(orgPlacement)
       
 42853           .addClass(placement)
       
 42854       }
       
 42855 
       
 42856       var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
       
 42857 
       
 42858       this.applyPlacement(calculatedOffset, placement)
       
 42859       this.hoverState = null
       
 42860 
       
 42861       var complete = function() {
       
 42862         that.$element.trigger('shown.bs.' + that.type)
       
 42863       }
       
 42864 
       
 42865       $.support.transition && this.$tip.hasClass('fade') ?
       
 42866         $tip
       
 42867           .one($.support.transition.end, complete)
       
 42868           .emulateTransitionEnd(150) :
       
 42869         complete()
       
 42870     }
       
 42871   }
       
 42872 
       
 42873   Tooltip.prototype.applyPlacement = function (offset, placement) {
       
 42874     var replace
       
 42875     var $tip   = this.tip()
       
 42876     var width  = $tip[0].offsetWidth
       
 42877     var height = $tip[0].offsetHeight
       
 42878 
       
 42879     // manually read margins because getBoundingClientRect includes difference
       
 42880     var marginTop = parseInt($tip.css('margin-top'), 10)
       
 42881     var marginLeft = parseInt($tip.css('margin-left'), 10)
       
 42882 
       
 42883     // we must check for NaN for ie 8/9
       
 42884     if (isNaN(marginTop))  marginTop  = 0
       
 42885     if (isNaN(marginLeft)) marginLeft = 0
       
 42886 
       
 42887     offset.top  = offset.top  + marginTop
       
 42888     offset.left = offset.left + marginLeft
       
 42889 
       
 42890     // $.fn.offset doesn't round pixel values
       
 42891     // so we use setOffset directly with our own function B-0
       
 42892     $.offset.setOffset($tip[0], $.extend({
       
 42893       using: function (props) {
       
 42894         $tip.css({
       
 42895           top: Math.round(props.top),
       
 42896           left: Math.round(props.left)
       
 42897         })
       
 42898       }
       
 42899     }, offset), 0)
       
 42900 
       
 42901     $tip.addClass('in')
       
 42902 
       
 42903     // check to see if placing tip in new offset caused the tip to resize itself
       
 42904     var actualWidth  = $tip[0].offsetWidth
       
 42905     var actualHeight = $tip[0].offsetHeight
       
 42906 
       
 42907     if (placement == 'top' && actualHeight != height) {
       
 42908       replace = true
       
 42909       offset.top = offset.top + height - actualHeight
       
 42910     }
       
 42911 
       
 42912     if (/bottom|top/.test(placement)) {
       
 42913       var delta = 0
       
 42914 
       
 42915       if (offset.left < 0) {
       
 42916         delta       = offset.left * -2
       
 42917         offset.left = 0
       
 42918 
       
 42919         $tip.offset(offset)
       
 42920 
       
 42921         actualWidth  = $tip[0].offsetWidth
       
 42922         actualHeight = $tip[0].offsetHeight
       
 42923       }
       
 42924 
       
 42925       this.replaceArrow(delta - width + actualWidth, actualWidth, 'left')
       
 42926     } else {
       
 42927       this.replaceArrow(actualHeight - height, actualHeight, 'top')
       
 42928     }
       
 42929 
       
 42930     if (replace) $tip.offset(offset)
       
 42931   }
       
 42932 
       
 42933   Tooltip.prototype.replaceArrow = function (delta, dimension, position) {
       
 42934     this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + '%') : '')
       
 42935   }
       
 42936 
       
 42937   Tooltip.prototype.setContent = function () {
       
 42938     var $tip  = this.tip()
       
 42939     var title = this.getTitle()
       
 42940 
       
 42941     $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
       
 42942     $tip.removeClass('fade in top bottom left right')
       
 42943   }
       
 42944 
       
 42945   Tooltip.prototype.hide = function () {
       
 42946     var that = this
       
 42947     var $tip = this.tip()
       
 42948     var e    = $.Event('hide.bs.' + this.type)
       
 42949 
       
 42950     function complete() {
       
 42951       if (that.hoverState != 'in') $tip.detach()
       
 42952       that.$element.trigger('hidden.bs.' + that.type)
       
 42953     }
       
 42954 
       
 42955     this.$element.trigger(e)
       
 42956 
       
 42957     if (e.isDefaultPrevented()) return
       
 42958 
       
 42959     $tip.removeClass('in')
       
 42960 
       
 42961     $.support.transition && this.$tip.hasClass('fade') ?
       
 42962       $tip
       
 42963         .one($.support.transition.end, complete)
       
 42964         .emulateTransitionEnd(150) :
       
 42965       complete()
       
 42966 
       
 42967     this.hoverState = null
       
 42968 
       
 42969     return this
       
 42970   }
       
 42971 
       
 42972   Tooltip.prototype.fixTitle = function () {
       
 42973     var $e = this.$element
       
 42974     if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
       
 42975       $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
       
 42976     }
       
 42977   }
       
 42978 
       
 42979   Tooltip.prototype.hasContent = function () {
       
 42980     return this.getTitle()
       
 42981   }
       
 42982 
       
 42983   Tooltip.prototype.getPosition = function () {
       
 42984     var el = this.$element[0]
       
 42985     return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : {
       
 42986       width: el.offsetWidth,
       
 42987       height: el.offsetHeight
       
 42988     }, this.$element.offset())
       
 42989   }
       
 42990 
       
 42991   Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
       
 42992     return placement == 'bottom' ? { top: pos.top + pos.height,   left: pos.left + pos.width / 2 - actualWidth / 2  } :
       
 42993            placement == 'top'    ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2  } :
       
 42994            placement == 'left'   ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
       
 42995         /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width   }
       
 42996   }
       
 42997 
       
 42998   Tooltip.prototype.getTitle = function () {
       
 42999     var title
       
 43000     var $e = this.$element
       
 43001     var o  = this.options
       
 43002 
       
 43003     title = $e.attr('data-original-title')
       
 43004       || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)
       
 43005 
       
 43006     return title
       
 43007   }
       
 43008 
       
 43009   Tooltip.prototype.tip = function () {
       
 43010     return this.$tip = this.$tip || $(this.options.template)
       
 43011   }
       
 43012 
       
 43013   Tooltip.prototype.arrow = function () {
       
 43014     return this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow')
       
 43015   }
       
 43016 
       
 43017   Tooltip.prototype.validate = function () {
       
 43018     if (!this.$element[0].parentNode) {
       
 43019       this.hide()
       
 43020       this.$element = null
       
 43021       this.options  = null
       
 43022     }
       
 43023   }
       
 43024 
       
 43025   Tooltip.prototype.enable = function () {
       
 43026     this.enabled = true
       
 43027   }
       
 43028 
       
 43029   Tooltip.prototype.disable = function () {
       
 43030     this.enabled = false
       
 43031   }
       
 43032 
       
 43033   Tooltip.prototype.toggleEnabled = function () {
       
 43034     this.enabled = !this.enabled
       
 43035   }
       
 43036 
       
 43037   Tooltip.prototype.toggle = function (e) {
       
 43038     var self = e ? $(e.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) : this
       
 43039     self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
       
 43040   }
       
 43041 
       
 43042   Tooltip.prototype.destroy = function () {
       
 43043     clearTimeout(this.timeout)
       
 43044     this.hide().$element.off('.' + this.type).removeData('bs.' + this.type)
       
 43045   }
       
 43046 
       
 43047 
       
 43048   // TOOLTIP PLUGIN DEFINITION
       
 43049   // =========================
       
 43050 
       
 43051   var old = $.fn.tooltip
       
 43052 
       
 43053   $.fn.tooltip = function (option) {
       
 43054     return this.each(function () {
       
 43055       var $this   = $(this)
       
 43056       var data    = $this.data('bs.tooltip')
       
 43057       var options = typeof option == 'object' && option
       
 43058 
       
 43059       if (!data && option == 'destroy') return
       
 43060       if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
       
 43061       if (typeof option == 'string') data[option]()
       
 43062     })
       
 43063   }
       
 43064 
       
 43065   $.fn.tooltip.Constructor = Tooltip
       
 43066 
       
 43067 
       
 43068   // TOOLTIP NO CONFLICT
       
 43069   // ===================
       
 43070 
       
 43071   $.fn.tooltip.noConflict = function () {
       
 43072     $.fn.tooltip = old
       
 43073     return this
       
 43074   }
       
 43075 
       
 43076 }(jQuery);
       
 43077 
       
 43078 /* ========================================================================
       
 43079  * Bootstrap: popover.js v3.1.1
       
 43080  * http://getbootstrap.com/javascript/#popovers
       
 43081  * ========================================================================
       
 43082  * Copyright 2011-2014 Twitter, Inc.
       
 43083  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
       
 43084  * ======================================================================== */
       
 43085 
       
 43086 
       
 43087 +function ($) {
       
 43088   'use strict';
       
 43089 
       
 43090   // POPOVER PUBLIC CLASS DEFINITION
       
 43091   // ===============================
       
 43092 
       
 43093   var Popover = function (element, options) {
       
 43094     this.init('popover', element, options)
       
 43095   }
       
 43096 
       
 43097   if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
       
 43098 
       
 43099   Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
       
 43100     placement: 'right',
       
 43101     trigger: 'click',
       
 43102     content: '',
       
 43103     template: '<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
       
 43104   })
       
 43105 
       
 43106 
       
 43107   // NOTE: POPOVER EXTENDS tooltip.js
       
 43108   // ================================
       
 43109 
       
 43110   Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)
       
 43111 
       
 43112   Popover.prototype.constructor = Popover
       
 43113 
       
 43114   Popover.prototype.getDefaults = function () {
       
 43115     return Popover.DEFAULTS
       
 43116   }
       
 43117 
       
 43118   Popover.prototype.setContent = function () {
       
 43119     var $tip    = this.tip()
       
 43120     var title   = this.getTitle()
       
 43121     var content = this.getContent()
       
 43122 
       
 43123     $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
       
 43124     $tip.find('.popover-content')[ // we use append for html objects to maintain js events
       
 43125       this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'
       
 43126     ](content)
       
 43127 
       
 43128     $tip.removeClass('fade top bottom left right in')
       
 43129 
       
 43130     // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
       
 43131     // this manually by checking the contents.
       
 43132     if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()
       
 43133   }
       
 43134 
       
 43135   Popover.prototype.hasContent = function () {
       
 43136     return this.getTitle() || this.getContent()
       
 43137   }
       
 43138 
       
 43139   Popover.prototype.getContent = function () {
       
 43140     var $e = this.$element
       
 43141     var o  = this.options
       
 43142 
       
 43143     return $e.attr('data-content')
       
 43144       || (typeof o.content == 'function' ?
       
 43145             o.content.call($e[0]) :
       
 43146             o.content)
       
 43147   }
       
 43148 
       
 43149   Popover.prototype.arrow = function () {
       
 43150     return this.$arrow = this.$arrow || this.tip().find('.arrow')
       
 43151   }
       
 43152 
       
 43153   Popover.prototype.tip = function () {
       
 43154     if (!this.$tip) this.$tip = $(this.options.template)
       
 43155     return this.$tip
       
 43156   }
       
 43157 
       
 43158 
       
 43159   // POPOVER PLUGIN DEFINITION
       
 43160   // =========================
       
 43161 
       
 43162   var old = $.fn.popover
       
 43163 
       
 43164   $.fn.popover = function (option) {
       
 43165     return this.each(function () {
       
 43166       var $this   = $(this)
       
 43167       var data    = $this.data('bs.popover')
       
 43168       var options = typeof option == 'object' && option
       
 43169 
       
 43170       if (!data && option == 'destroy') return
       
 43171       if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
       
 43172       if (typeof option == 'string') data[option]()
       
 43173     })
       
 43174   }
       
 43175 
       
 43176   $.fn.popover.Constructor = Popover
       
 43177 
       
 43178 
       
 43179   // POPOVER NO CONFLICT
       
 43180   // ===================
       
 43181 
       
 43182   $.fn.popover.noConflict = function () {
       
 43183     $.fn.popover = old
       
 43184     return this
       
 43185   }
       
 43186 
       
 43187 }(jQuery);
       
 43188 
       
 43189 /* ========================================================================
       
 43190  * Bootstrap: scrollspy.js v3.1.1
       
 43191  * http://getbootstrap.com/javascript/#scrollspy
       
 43192  * ========================================================================
       
 43193  * Copyright 2011-2014 Twitter, Inc.
       
 43194  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
       
 43195  * ======================================================================== */
       
 43196 
       
 43197 
       
 43198 +function ($) {
       
 43199   'use strict';
       
 43200 
       
 43201   // SCROLLSPY CLASS DEFINITION
       
 43202   // ==========================
       
 43203 
       
 43204   function ScrollSpy(element, options) {
       
 43205     var href
       
 43206     var process  = $.proxy(this.process, this)
       
 43207 
       
 43208     this.$element       = $(element).is('body') ? $(window) : $(element)
       
 43209     this.$body          = $('body')
       
 43210     this.$scrollElement = this.$element.on('scroll.bs.scroll-spy.data-api', process)
       
 43211     this.options        = $.extend({}, ScrollSpy.DEFAULTS, options)
       
 43212     this.selector       = (this.options.target
       
 43213       || ((href = $(element).attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
       
 43214       || '') + ' .nav li > a'
       
 43215     this.offsets        = $([])
       
 43216     this.targets        = $([])
       
 43217     this.activeTarget   = null
       
 43218 
       
 43219     this.refresh()
       
 43220     this.process()
       
 43221   }
       
 43222 
       
 43223   ScrollSpy.DEFAULTS = {
       
 43224     offset: 10
       
 43225   }
       
 43226 
       
 43227   ScrollSpy.prototype.refresh = function () {
       
 43228     var offsetMethod = this.$element[0] == window ? 'offset' : 'position'
       
 43229 
       
 43230     this.offsets = $([])
       
 43231     this.targets = $([])
       
 43232 
       
 43233     var self     = this
       
 43234     var $targets = this.$body
       
 43235       .find(this.selector)
       
 43236       .map(function () {
       
 43237         var $el   = $(this)
       
 43238         var href  = $el.data('target') || $el.attr('href')
       
 43239         var $href = /^#./.test(href) && $(href)
       
 43240 
       
 43241         return ($href
       
 43242           && $href.length
       
 43243           && $href.is(':visible')
       
 43244           && [[ $href[offsetMethod]().top + (!$.isWindow(self.$scrollElement.get(0)) && self.$scrollElement.scrollTop()), href ]]) || null
       
 43245       })
       
 43246       .sort(function (a, b) { return a[0] - b[0] })
       
 43247       .each(function () {
       
 43248         self.offsets.push(this[0])
       
 43249         self.targets.push(this[1])
       
 43250       })
       
 43251   }
       
 43252 
       
 43253   ScrollSpy.prototype.process = function () {
       
 43254     var scrollTop    = this.$scrollElement.scrollTop() + this.options.offset
       
 43255     var scrollHeight = this.$scrollElement[0].scrollHeight || this.$body[0].scrollHeight
       
 43256     var maxScroll    = scrollHeight - this.$scrollElement.height()
       
 43257     var offsets      = this.offsets
       
 43258     var targets      = this.targets
       
 43259     var activeTarget = this.activeTarget
       
 43260     var i
       
 43261 
       
 43262     if (scrollTop >= maxScroll) {
       
 43263       return activeTarget != (i = targets.last()[0]) && this.activate(i)
       
 43264     }
       
 43265 
       
 43266     if (activeTarget && scrollTop <= offsets[0]) {
       
 43267       return activeTarget != (i = targets[0]) && this.activate(i)
       
 43268     }
       
 43269 
       
 43270     for (i = offsets.length; i--;) {
       
 43271       activeTarget != targets[i]
       
 43272         && scrollTop >= offsets[i]
       
 43273         && (!offsets[i + 1] || scrollTop <= offsets[i + 1])
       
 43274         && this.activate( targets[i] )
       
 43275     }
       
 43276   }
       
 43277 
       
 43278   ScrollSpy.prototype.activate = function (target) {
       
 43279     this.activeTarget = target
       
 43280 
       
 43281     $(this.selector)
       
 43282       .parentsUntil(this.options.target, '.active')
       
 43283       .removeClass('active')
       
 43284 
       
 43285     var selector = this.selector +
       
 43286         '[data-target="' + target + '"],' +
       
 43287         this.selector + '[href="' + target + '"]'
       
 43288 
       
 43289     var active = $(selector)
       
 43290       .parents('li')
       
 43291       .addClass('active')
       
 43292 
       
 43293     if (active.parent('.dropdown-menu').length) {
       
 43294       active = active
       
 43295         .closest('li.dropdown')
       
 43296         .addClass('active')
       
 43297     }
       
 43298 
       
 43299     active.trigger('activate.bs.scrollspy')
       
 43300   }
       
 43301 
       
 43302 
       
 43303   // SCROLLSPY PLUGIN DEFINITION
       
 43304   // ===========================
       
 43305 
       
 43306   var old = $.fn.scrollspy
       
 43307 
       
 43308   $.fn.scrollspy = function (option) {
       
 43309     return this.each(function () {
       
 43310       var $this   = $(this)
       
 43311       var data    = $this.data('bs.scrollspy')
       
 43312       var options = typeof option == 'object' && option
       
 43313 
       
 43314       if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))
       
 43315       if (typeof option == 'string') data[option]()
       
 43316     })
       
 43317   }
       
 43318 
       
 43319   $.fn.scrollspy.Constructor = ScrollSpy
       
 43320 
       
 43321 
       
 43322   // SCROLLSPY NO CONFLICT
       
 43323   // =====================
       
 43324 
       
 43325   $.fn.scrollspy.noConflict = function () {
       
 43326     $.fn.scrollspy = old
       
 43327     return this
       
 43328   }
       
 43329 
       
 43330 
       
 43331   // SCROLLSPY DATA-API
       
 43332   // ==================
       
 43333 
       
 43334   $(window).on('load', function () {
       
 43335     $('[data-spy="scroll"]').each(function () {
       
 43336       var $spy = $(this)
       
 43337       $spy.scrollspy($spy.data())
       
 43338     })
       
 43339   })
       
 43340 
       
 43341 }(jQuery);
       
 43342 
       
 43343 /* ========================================================================
       
 43344  * Bootstrap: tab.js v3.1.1
       
 43345  * http://getbootstrap.com/javascript/#tabs
       
 43346  * ========================================================================
       
 43347  * Copyright 2011-2014 Twitter, Inc.
       
 43348  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
       
 43349  * ======================================================================== */
       
 43350 
       
 43351 
       
 43352 +function ($) {
       
 43353   'use strict';
       
 43354 
       
 43355   // TAB CLASS DEFINITION
       
 43356   // ====================
       
 43357 
       
 43358   var Tab = function (element) {
       
 43359     this.element = $(element)
       
 43360   }
       
 43361 
       
 43362   Tab.prototype.show = function () {
       
 43363     var $this    = this.element
       
 43364     var $ul      = $this.closest('ul:not(.dropdown-menu)')
       
 43365     var selector = $this.data('target')
       
 43366 
       
 43367     if (!selector) {
       
 43368       selector = $this.attr('href')
       
 43369       selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
       
 43370     }
       
 43371 
       
 43372     if ($this.parent('li').hasClass('active')) return
       
 43373 
       
 43374     var previous = $ul.find('.active:last a')[0]
       
 43375     var e        = $.Event('show.bs.tab', {
       
 43376       relatedTarget: previous
       
 43377     })
       
 43378 
       
 43379     $this.trigger(e)
       
 43380 
       
 43381     if (e.isDefaultPrevented()) return
       
 43382 
       
 43383     var $target = $(selector)
       
 43384 
       
 43385     this.activate($this.parent('li'), $ul)
       
 43386     this.activate($target, $target.parent(), function () {
       
 43387       $this.trigger({
       
 43388         type: 'shown.bs.tab',
       
 43389         relatedTarget: previous
       
 43390       })
       
 43391     })
       
 43392   }
       
 43393 
       
 43394   Tab.prototype.activate = function (element, container, callback) {
       
 43395     var $active    = container.find('> .active')
       
 43396     var transition = callback
       
 43397       && $.support.transition
       
 43398       && $active.hasClass('fade')
       
 43399 
       
 43400     function next() {
       
 43401       $active
       
 43402         .removeClass('active')
       
 43403         .find('> .dropdown-menu > .active')
       
 43404         .removeClass('active')
       
 43405 
       
 43406       element.addClass('active')
       
 43407 
       
 43408       if (transition) {
       
 43409         element[0].offsetWidth // reflow for transition
       
 43410         element.addClass('in')
       
 43411       } else {
       
 43412         element.removeClass('fade')
       
 43413       }
       
 43414 
       
 43415       if (element.parent('.dropdown-menu')) {
       
 43416         element.closest('li.dropdown').addClass('active')
       
 43417       }
       
 43418 
       
 43419       callback && callback()
       
 43420     }
       
 43421 
       
 43422     transition ?
       
 43423       $active
       
 43424         .one($.support.transition.end, next)
       
 43425         .emulateTransitionEnd(150) :
       
 43426       next()
       
 43427 
       
 43428     $active.removeClass('in')
       
 43429   }
       
 43430 
       
 43431 
       
 43432   // TAB PLUGIN DEFINITION
       
 43433   // =====================
       
 43434 
       
 43435   var old = $.fn.tab
       
 43436 
       
 43437   $.fn.tab = function ( option ) {
       
 43438     return this.each(function () {
       
 43439       var $this = $(this)
       
 43440       var data  = $this.data('bs.tab')
       
 43441 
       
 43442       if (!data) $this.data('bs.tab', (data = new Tab(this)))
       
 43443       if (typeof option == 'string') data[option]()
       
 43444     })
       
 43445   }
       
 43446 
       
 43447   $.fn.tab.Constructor = Tab
       
 43448 
       
 43449 
       
 43450   // TAB NO CONFLICT
       
 43451   // ===============
       
 43452 
       
 43453   $.fn.tab.noConflict = function () {
       
 43454     $.fn.tab = old
       
 43455     return this
       
 43456   }
       
 43457 
       
 43458 
       
 43459   // TAB DATA-API
       
 43460   // ============
       
 43461 
       
 43462   $(document).on('click.bs.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
       
 43463     e.preventDefault()
       
 43464     $(this).tab('show')
       
 43465   })
       
 43466 
       
 43467 }(jQuery);
       
 43468 
       
 43469 /* ========================================================================
       
 43470  * Bootstrap: affix.js v3.1.1
       
 43471  * http://getbootstrap.com/javascript/#affix
       
 43472  * ========================================================================
       
 43473  * Copyright 2011-2014 Twitter, Inc.
       
 43474  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
       
 43475  * ======================================================================== */
       
 43476 
       
 43477 
       
 43478 +function ($) {
       
 43479   'use strict';
       
 43480 
       
 43481   // AFFIX CLASS DEFINITION
       
 43482   // ======================
       
 43483 
       
 43484   var Affix = function (element, options) {
       
 43485     this.options = $.extend({}, Affix.DEFAULTS, options)
       
 43486     this.$window = $(window)
       
 43487       .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))
       
 43488       .on('click.bs.affix.data-api',  $.proxy(this.checkPositionWithEventLoop, this))
       
 43489 
       
 43490     this.$element     = $(element)
       
 43491     this.affixed      =
       
 43492     this.unpin        =
       
 43493     this.pinnedOffset = null
       
 43494 
       
 43495     this.checkPosition()
       
 43496   }
       
 43497 
       
 43498   Affix.RESET = 'affix affix-top affix-bottom'
       
 43499 
       
 43500   Affix.DEFAULTS = {
       
 43501     offset: 0
       
 43502   }
       
 43503 
       
 43504   Affix.prototype.getPinnedOffset = function () {
       
 43505     if (this.pinnedOffset) return this.pinnedOffset
       
 43506     this.$element.removeClass(Affix.RESET).addClass('affix')
       
 43507     var scrollTop = this.$window.scrollTop()
       
 43508     var position  = this.$element.offset()
       
 43509     return (this.pinnedOffset = position.top - scrollTop)
       
 43510   }
       
 43511 
       
 43512   Affix.prototype.checkPositionWithEventLoop = function () {
       
 43513     setTimeout($.proxy(this.checkPosition, this), 1)
       
 43514   }
       
 43515 
       
 43516   Affix.prototype.checkPosition = function () {
       
 43517     if (!this.$element.is(':visible')) return
       
 43518 
       
 43519     var scrollHeight = $(document).height()
       
 43520     var scrollTop    = this.$window.scrollTop()
       
 43521     var position     = this.$element.offset()
       
 43522     var offset       = this.options.offset
       
 43523     var offsetTop    = offset.top
       
 43524     var offsetBottom = offset.bottom
       
 43525 
       
 43526     if (this.affixed == 'top') position.top += scrollTop
       
 43527 
       
 43528     if (typeof offset != 'object')         offsetBottom = offsetTop = offset
       
 43529     if (typeof offsetTop == 'function')    offsetTop    = offset.top(this.$element)
       
 43530     if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)
       
 43531 
       
 43532     var affix = this.unpin   != null && (scrollTop + this.unpin <= position.top) ? false :
       
 43533                 offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ? 'bottom' :
       
 43534                 offsetTop    != null && (scrollTop <= offsetTop) ? 'top' : false
       
 43535 
       
 43536     if (this.affixed === affix) return
       
 43537     if (this.unpin) this.$element.css('top', '')
       
 43538 
       
 43539     var affixType = 'affix' + (affix ? '-' + affix : '')
       
 43540     var e         = $.Event(affixType + '.bs.affix')
       
 43541 
       
 43542     this.$element.trigger(e)
       
 43543 
       
 43544     if (e.isDefaultPrevented()) return
       
 43545 
       
 43546     this.affixed = affix
       
 43547     this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null
       
 43548 
       
 43549     this.$element
       
 43550       .removeClass(Affix.RESET)
       
 43551       .addClass(affixType)
       
 43552       .trigger($.Event(affixType.replace('affix', 'affixed')))
       
 43553 
       
 43554     if (affix == 'bottom') {
       
 43555       this.$element.offset({ top: scrollHeight - offsetBottom - this.$element.height() })
       
 43556     }
       
 43557   }
       
 43558 
       
 43559 
       
 43560   // AFFIX PLUGIN DEFINITION
       
 43561   // =======================
       
 43562 
       
 43563   var old = $.fn.affix
       
 43564 
       
 43565   $.fn.affix = function (option) {
       
 43566     return this.each(function () {
       
 43567       var $this   = $(this)
       
 43568       var data    = $this.data('bs.affix')
       
 43569       var options = typeof option == 'object' && option
       
 43570 
       
 43571       if (!data) $this.data('bs.affix', (data = new Affix(this, options)))
       
 43572       if (typeof option == 'string') data[option]()
       
 43573     })
       
 43574   }
       
 43575 
       
 43576   $.fn.affix.Constructor = Affix
       
 43577 
       
 43578 
       
 43579   // AFFIX NO CONFLICT
       
 43580   // =================
       
 43581 
       
 43582   $.fn.affix.noConflict = function () {
       
 43583     $.fn.affix = old
       
 43584     return this
       
 43585   }
       
 43586 
       
 43587 
       
 43588   // AFFIX DATA-API
       
 43589   // ==============
       
 43590 
       
 43591   $(window).on('load', function () {
       
 43592     $('[data-spy="affix"]').each(function () {
       
 43593       var $spy = $(this)
       
 43594       var data = $spy.data()
       
 43595 
       
 43596       data.offset = data.offset || {}
       
 43597 
       
 43598       if (data.offsetBottom) data.offset.bottom = data.offsetBottom
       
 43599       if (data.offsetTop)    data.offset.top    = data.offsetTop
       
 43600 
       
 43601       $spy.affix(data)
       
 43602     })
       
 43603   })
       
 43604 
       
 43605 }(jQuery);