PageSourceSearch

https://toolbox.bme.de/dist/js/bme2014.js

js bme.de collected 2026-09-24 09:26:47 UTC 842,596 bytes, 25,725 lines download raw bytes

1/*!
2 * jQuery JavaScript Library v1.9.1
3 * http://jquery.com/
4 *
5 * Includes Sizzle.js
6 * http://sizzlejs.com/
7 *
8 * Copyright 2005, 2012 jQuery Foundation, Inc. and other contributors
9 * Released under the MIT license
10 * http://jquery.org/license
11 *
12 * Date: 2013-2-4
13 */
14(function( window, undefined ) {
15
16// Can't do this because several apps including ASP.NET trace
17// the stack via arguments.caller.callee and Firefox dies if
18// you try to trace through "use strict" call chains. (#13335)
19// Support: Firefox 18+
20//"use strict";
21var
22	// The deferred used on DOM ready
23	readyList,
24
25	// A central reference to the root jQuery(document)
26	rootjQuery,
27
28	// Support: IE<9
29	// For `typeof node.method` instead of `node.method !== undefined`
30	core_strundefined = typeof undefined,
31
32	// Use the correct document accordingly with window argument (sandbox)
33	document = window.document,
34	location = window.location,
35
36	// Map over jQuery in case of overwrite
37	_jQuery = window.jQuery,
38
39	// Map over the $ in case of overwrite
40	_$ = window.$,
41
42	// [[Class]] -> type pairs
43	class2type = {},
44
45	// List of deleted data cache ids, so we can reuse them
46	core_deletedIds = [],
47
48	core_version = "1.9.1",
49
50	// Save a reference to some core methods
51	core_concat = core_deletedIds.concat,
52	core_push = core_deletedIds.push,
53	core_slice = core_deletedIds.slice,
54	core_indexOf = core_deletedIds.indexOf,
55	core_toString = class2type.toString,
56	core_hasOwn = class2type.hasOwnProperty,
57	core_trim = core_version.trim,
58
59	// Define a local copy of jQuery
60	jQuery = function( selector, context ) {
61		// The jQuery object is actually just the init constructor 'enhanced'
62		return new jQuery.fn.init( selector, context, rootjQuery );
63	},
64
65	// Used for matching numbers
66	core_pnum = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,
67
68	// Used for splitting on whitespace
69	core_rnotwhite = /\S+/g,
70
71	// Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE)
72	rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
73
74	// A simple way to check for HTML strings
75	// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
76	// Strict HTML recognition (#11290: must start with <)
77	rquickExpr = /^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/,
78
79	// Match a standalone tag
80	rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/,
81
82	// JSON RegExp
83	rvalidchars = /^[\],:{}\s]*$/,
84	rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
85	rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,
86	rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,
87
88	// Matches dashed string for camelizing
89	rmsPrefix = /^-ms-/,
90	rdashAlpha = /-([\da-z])/gi,
91
92	// Used by jQuery.camelCase as callback to replace()
93	fcamelCase = function( all, letter ) {
94		return letter.toUpperCase();
95	},
96
97	// The ready event handler
98	completed = function( event ) {
99
100		// readyState === "complete" is good enough for us to call the dom ready in oldIE
101		if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) {
102			detach();
103			jQuery.ready();
104		}
105	},
106	// Clean-up method for dom ready events
107	detach = function() {
108		if ( document.addEventListener ) {
109			document.removeEventListener( "DOMContentLoaded", completed, false );
110			window.removeEventListener( "load", completed, false );
111
112		} else {
113			document.detachEvent( "onreadystatechange", completed );
114			window.detachEvent( "onload", completed );
115		}
116	};
117
118jQuery.fn = jQuery.prototype = {
119	// The current version of jQuery being used
120	jquery: core_version,
121
122	constructor: jQuery,
123	init: function( selector, context, rootjQuery ) {
124		var match, elem;
125
126		// HANDLE: $(""), $(null), $(undefined), $(false)
127		if ( !selector ) {
128			return this;
129		}
130
131		// Handle HTML strings
132		if ( typeof selector === "string" ) {
133			if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
134				// Assume that strings that start and end with <> are HTML and skip the regex check
135				match = [ null, selector, null ];
136
137			} else {
138				match = rquickExpr.exec( selector );
139			}
140
141			// Match html or make sure no context is specified for #id
142			if ( match && (match[1] || !context) ) {
143
144				// HANDLE: $(html) -> $(array)
145				if ( match[1] ) {
146					context = context instanceof jQuery ? context[0] : context;
147
148					// scripts is true for back-compat
149					jQuery.merge( this, jQuery.parseHTML(
150						match[1],
151						context && context.nodeType ? context.ownerDocument || context : document,
152						true
153					) );
154
155					// HANDLE: $(html, props)
156					if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
157						for ( match in context ) {
158							// Properties of context are called as methods if possible
159							if ( jQuery.isFunction( this[ match ] ) ) {
160								this[ match ]( context[ match ] );
161
162							// ...and otherwise set as attributes
163							} else {
164								this.attr( match, context[ match ] );
165							}
166						}
167					}
168
169					return this;
170
171				// HANDLE: $(#id)
172				} else {
173					elem = document.getElementById( match[2] );
174
175					// Check parentNode to catch when Blackberry 4.6 returns
176					// nodes that are no longer in the document #6963
177					if ( elem && elem.parentNode ) {
178						// Handle the case where IE and Opera return items
179						// by name instead of ID
180						if ( elem.id !== match[2] ) {
181							return rootjQuery.find( selector );
182						}
183
184						// Otherwise, we inject the element directly into the jQuery object
185						this.length = 1;
186						this[0] = elem;
187					}
188
189					this.context = document;
190					this.selector = selector;
191					return this;
192				}
193
194			// HANDLE: $(expr, $(...))
195			} else if ( !context || context.jquery ) {
196				return ( context || rootjQuery ).find( selector );
197
198			// HANDLE: $(expr, context)
199			// (which is just equivalent to: $(context).find(expr)
200			} else {
201				return this.constructor( context ).find( selector );
202			}
203
204		// HANDLE: $(DOMElement)
205		} else if ( selector.nodeType ) {
206			this.context = this[0] = selector;
207			this.length = 1;
208			return this;
209
210		// HANDLE: $(function)
211		// Shortcut for document ready
212		} else if ( jQuery.isFunction( selector ) ) {
213			return rootjQuery.ready( selector );
214		}
215
216		if ( selector.selector !== undefined ) {
217			this.selector = selector.selector;
218			this.context = selector.context;
219		}
220
221		return jQuery.makeArray( selector, this );
222	},
223
224	// Start with an empty selector
225	selector: "",
226
227	// The default length of a jQuery object is 0
228	length: 0,
229
230	// The number of elements contained in the matched element set
231	size: function() {
232		return this.length;
233	},
234
235	toArray: function() {
236		return core_slice.call( this );
237	},
238
239	// Get the Nth element in the matched element set OR
240	// Get the whole matched element set as a clean array
241	get: function( num ) {
242		return num == null ?
243
244			// Return a 'clean' array
245			this.toArray() :
246
247			// Return just the object
248			( num < 0 ? this[ this.length + num ] : this[ num ] );
249	},
250
251	// Take an array of elements and push it onto the stack
252	// (returning the new matched element set)
253	pushStack: function( elems ) {
254
255		// Build a new jQuery matched element set
256		var ret = jQuery.merge( this.constructor(), elems );
257
258		// Add the old object onto the stack (as a reference)
259		ret.prevObject = this;
260		ret.context = this.context;
261
262		// Return the newly-formed element set
263		return ret;
264	},
265
266	// Execute a callback for every element in the matched set.
267	// (You can seed the arguments with an array of args, but this is
268	// only used internally.)
269	each: function( callback, args ) {
270		return jQuery.each( this, callback, args );
271	},
272
273	ready: function( fn ) {
274		// Add the callback
275		jQuery.ready.promise().done( fn );
276
277		return this;
278	},
279
280	slice: function() {
281		return this.pushStack( core_slice.apply( this, arguments ) );
282	},
283
284	first: function() {
285		return this.eq( 0 );
286	},
287
288	last: function() {
289		return this.eq( -1 );
290	},
291
292	eq: function( i ) {
293		var len = this.length,
294			j = +i + ( i < 0 ? len : 0 );
295		return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );
296	},
297
298	map: function( callback ) {
299		return this.pushStack( jQuery.map(this, function( elem, i ) {
300			return callback.call( elem, i, elem );
301		}));
302	},
303
304	end: function() {
305		return this.prevObject || this.constructor(null);
306	},
307
308	// For internal use only.
309	// Behaves like an Array's method, not like a jQuery method.
310	push: core_push,
311	sort: [].sort,
312	splice: [].splice
313};
314
315// Give the init function the jQuery prototype for later instantiation
316jQuery.fn.init.prototype = jQuery.fn;
317
318jQuery.extend = jQuery.fn.extend = function() {
319	var src, copyIsArray, copy, name, options, clone,
320		target = arguments[0] || {},
321		i = 1,
322		length = arguments.length,
323		deep = false;
324
325	// Handle a deep copy situation
326	if ( typeof target === "boolean" ) {
327		deep = target;
328		target = arguments[1] || {};
329		// skip the boolean and the target
330		i = 2;
331	}
332
333	// Handle case when target is a string or something (possible in deep copy)
334	if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
335		target = {};
336	}
337
338	// extend jQuery itself if only one argument is passed
339	if ( length === i ) {
340		target = this;
341		--i;
342	}
343
344	for ( ; i < length; i++ ) {
345		// Only deal with non-null/undefined values
346		if ( (options = arguments[ i ]) != null ) {
347			// Extend the base object
348			for ( name in options ) {
349				src = target[ name ];
350				copy = options[ name ];
351
352				// Prevent never-ending loop
353				if ( target === copy ) {
354					continue;
355				}
356
357				// Recurse if we're merging plain objects or arrays
358				if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
359					if ( copyIsArray ) {
360						copyIsArray = false;
361						clone = src && jQuery.isArray(src) ? src : [];
362
363					} else {
364						clone = src && jQuery.isPlainObject(src) ? src : {};
365					}
366
367					// Never move original objects, clone them
368					target[ name ] = jQuery.extend( deep, clone, copy );
369
370				// Don't bring in undefined values
371				} else if ( copy !== undefined ) {
372					target[ name ] = copy;
373				}
374			}
375		}
376	}
377
378	// Return the modified object
379	return target;
380};
381
382jQuery.extend({
383	noConflict: function( deep ) {
384		if ( window.$ === jQuery ) {
385			window.$ = _$;
386		}
387
388		if ( deep && window.jQuery === jQuery ) {
389			window.jQuery = _jQuery;
390		}
391
392		return jQuery;
393	},
394
395	// Is the DOM ready to be used? Set to true once it occurs.
396	isReady: false,
397
398	// A counter to track how many items to wait for before
399	// the ready event fires. See #6781
400	readyWait: 1,
401
402	// Hold (or release) the ready event
403	holdReady: function( hold ) {
404		if ( hold ) {
405			jQuery.readyWait++;
406		} else {
407			jQuery.ready( true );
408		}
409	},
410
411	// Handle when the DOM is ready
412	ready: function( wait ) {
413
414		// Abort if there are pending holds or we're already ready
415		if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
416			return;
417		}
418
419		// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
420		if ( !document.body ) {
421			return setTimeout( jQuery.ready );
422		}
423
424		// Remember that the DOM is ready
425		jQuery.isReady = true;
426
427		// If a normal DOM Ready event fired, decrement, and wait if need be
428		if ( wait !== true && --jQuery.readyWait > 0 ) {
429			return;
430		}
431
432		// If there are functions bound, to execute
433		readyList.resolveWith( document, [ jQuery ] );
434
435		// Trigger any bound ready events
436		if ( jQuery.fn.trigger ) {
437			jQuery( document ).trigger("ready").off("ready");
438		}
439	},
440
441	// See test/unit/core.js for details concerning isFunction.
442	// Since version 1.3, DOM methods and functions like alert
443	// aren't supported. They return false on IE (#2968).
444	isFunction: function( obj ) {
445		return jQuery.type(obj) === "function";
446	},
447
448	isArray: Array.isArray || function( obj ) {
449		return jQuery.type(obj) === "array";
450	},
451
452	isWindow: function( obj ) {
453		return obj != null && obj == obj.window;
454	},
455
456	isNumeric: function( obj ) {
457		return !isNaN( parseFloat(obj) ) && isFinite( obj );
458	},
459
460	type: function( obj ) {
461		if ( obj == null ) {
462			return String( obj );
463		}
464		return typeof obj === "object" || typeof obj === "function" ?
465			class2type[ core_toString.call(obj) ] || "object" :
466			typeof obj;
467	},
468
469	isPlainObject: function( obj ) {
470		// Must be an Object.
471		// Because of IE, we also have to check the presence of the constructor property.
472		// Make sure that DOM nodes and window objects don't pass through, as well
473		if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
474			return false;
475		}
476
477		try {
478			// Not own constructor property must be Object
479			if ( obj.constructor &&
480				!core_hasOwn.call(obj, "constructor") &&
481				!core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
482				return false;
483			}
484		} catch ( e ) {
485			// IE8,9 Will throw exceptions on certain host objects #9897
486			return false;
487		}
488
489		// Own properties are enumerated firstly, so to speed up,
490		// if last one is own, then all properties are own.
491
492		var key;
493		for ( key in obj ) {}
494
495		return key === undefined || core_hasOwn.call( obj, key );
496	},
497
498	isEmptyObject: function( obj ) {
499		var name;
500		for ( name in obj ) {
501			return false;
502		}
503		return true;
504	},
505
506	error: function( msg ) {
507		throw new Error( msg );
508	},
509
510	// data: string of html
511	// context (optional): If specified, the fragment will be created in this context, defaults to document
512	// keepScripts (optional): If true, will include scripts passed in the html string
513	parseHTML: function( data, context, keepScripts ) {
514		if ( !data || typeof data !== "string" ) {
515			return null;
516		}
517		if ( typeof context === "boolean" ) {
518			keepScripts = context;
519			context = false;
520		}
521		context = context || document;
522
523		var parsed = rsingleTag.exec( data ),
524			scripts = !keepScripts && [];
525
526		// Single tag
527		if ( parsed ) {
528			return [ context.createElement( parsed[1] ) ];
529		}
530
531		parsed = jQuery.buildFragment( [ data ], context, scripts );
532		if ( scripts ) {
533			jQuery( scripts ).remove();
534		}
535		return jQuery.merge( [], parsed.childNodes );
536	},
537
538	parseJSON: function( data ) {
539		// Attempt to parse using the native JSON parser first
540		if ( window.JSON && window.JSON.parse ) {
541			return window.JSON.parse( data );
542		}
543
544		if ( data === null ) {
545			return data;
546		}
547
548		if ( typeof data === "string" ) {
549
550			// Make sure leading/trailing whitespace is removed (IE can't handle it)
551			data = jQuery.trim( data );
552
553			if ( data ) {
554				// Make sure the incoming data is actual JSON
555				// Logic borrowed from http://json.org/json2.js
556				if ( rvalidchars.test( data.replace( rvalidescape, "@" )
557					.replace( rvalidtokens, "]" )
558					.replace( rvalidbraces, "")) ) {
559
560					return ( new Function( "return " + data ) )();
561				}
562			}
563		}
564
565		jQuery.error( "Invalid JSON: " + data );
566	},
567
568	// Cross-browser xml parsing
569	parseXML: function( data ) {
570		var xml, tmp;
571		if ( !data || typeof data !== "string" ) {
572			return null;
573		}
574		try {
575			if ( window.DOMParser ) { // Standard
576				tmp = new DOMParser();
577				xml = tmp.parseFromString( data , "text/xml" );
578			} else { // IE
579				xml = new ActiveXObject( "Microsoft.XMLDOM" );
580				xml.async = "false";
581				xml.loadXML( data );
582			}
583		} catch( e ) {
584			xml = undefined;
585		}
586		if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
587			jQuery.error( "Invalid XML: " + data );
588		}
589		return xml;
590	},
591
592	noop: function() {},
593
594	// Evaluates a script in a global context
595	// Workarounds based on findings by Jim Driscoll
596	// http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
597	globalEval: function( data ) {
598		if ( data && jQuery.trim( data ) ) {
599			// We use execScript on Internet Explorer
600			// We use an anonymous function so that context is window
601			// rather than jQuery in Firefox
602			( window.execScript || function( data ) {
603				window[ "eval" ].call( window, data );
604			} )( data );
605		}
606	},
607
608	// Convert dashed to camelCase; used by the css and data modules
609	// Microsoft forgot to hump their vendor prefix (#9572)
610	camelCase: function( string ) {
611		return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
612	},
613
614	nodeName: function( elem, name ) {
615		return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
616	},
617
618	// args is for internal usage only
619	each: function( obj, callback, args ) {
620		var value,
621			i = 0,
622			length = obj.length,
623			isArray = isArraylike( obj );
624
625		if ( args ) {
626			if ( isArray ) {
627				for ( ; i < length; i++ ) {
628					value = callback.apply( obj[ i ], args );
629
630					if ( value === false ) {
631						break;
632					}
633				}
634			} else {
635				for ( i in obj ) {
636					value = callback.apply( obj[ i ], args );
637
638					if ( value === false ) {
639						break;
640					}
641				}
642			}
643
644		// A special, fast, case for the most common use of each
645		} else {
646			if ( isArray ) {
647				for ( ; i < length; i++ ) {
648					value = callback.call( obj[ i ], i, obj[ i ] );
649
650					if ( value === false ) {
651						break;
652					}
653				}
654			} else {
655				for ( i in obj ) {
656					value = callback.call( obj[ i ], i, obj[ i ] );
657
658					if ( value === false ) {
659						break;
660					}
661				}
662			}
663		}
664
665		return obj;
666	},
667
668	// Use native String.trim function wherever possible
669	trim: core_trim && !core_trim.call("\uFEFF\xA0") ?
670		function( text ) {
671			return text == null ?
672				"" :
673				core_trim.call( text );
674		} :
675
676		// Otherwise use our own trimming functionality
677		function( text ) {
678			return text == null ?
679				"" :
680				( text + "" ).replace( rtrim, "" );
681		},
682
683	// results is for internal usage only
684	makeArray: function( arr, results ) {
685		var ret = results || [];
686
687		if ( arr != null ) {
688			if ( isArraylike( Object(arr) ) ) {
689				jQuery.merge( ret,
690					typeof arr === "string" ?
691					[ arr ] : arr
692				);
693			} else {
694				core_push.call( ret, arr );
695			}
696		}
697
698		return ret;
699	},
700
701	inArray: function( elem, arr, i ) {
702		var len;
703
704		if ( arr ) {
705			if ( core_indexOf ) {
706				return core_indexOf.call( arr, elem, i );
707			}
708
709			len = arr.length;
710			i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
711
712			for ( ; i < len; i++ ) {
713				// Skip accessing in sparse arrays
714				if ( i in arr && arr[ i ] === elem ) {
715					return i;
716				}
717			}
718		}
719
720		return -1;
721	},
722
723	merge: function( first, second ) {
724		var l = second.length,
725			i = first.length,
726			j = 0;
727
728		if ( typeof l === "number" ) {
729			for ( ; j < l; j++ ) {
730				first[ i++ ] = second[ j ];
731			}
732		} else {
733			while ( second[j] !== undefined ) {
734				first[ i++ ] = second[ j++ ];
735			}
736		}
737
738		first.length = i;
739
740		return first;
741	},
742
743	grep: function( elems, callback, inv ) {
744		var retVal,
745			ret = [],
746			i = 0,
747			length = elems.length;
748		inv = !!inv;
749
750		// Go through the array, only saving the items
751		// that pass the validator function
752		for ( ; i < length; i++ ) {
753			retVal = !!callback( elems[ i ], i );
754			if ( inv !== retVal ) {
755				ret.push( elems[ i ] );
756			}
757		}
758
759		return ret;
760	},
761
762	// arg is for internal usage only
763	map: function( elems, callback, arg ) {
764		var value,
765			i = 0,
766			length = elems.length,
767			isArray = isArraylike( elems ),
768			ret = [];
769
770		// Go through the array, translating each of the items to their
771		if ( isArray ) {
772			for ( ; i < length; i++ ) {
773				value = callback( elems[ i ], i, arg );
774
775				if ( value != null ) {
776					ret[ ret.length ] = value;
777				}
778			}
779
780		// Go through every key on the object,
781		} else {
782			for ( i in elems ) {
783				value = callback( elems[ i ], i, arg );
784
785				if ( value != null ) {
786					ret[ ret.length ] = value;
787				}
788			}
789		}
790
791		// Flatten any nested arrays
792		return core_concat.apply( [], ret );
793	},
794
795	// A global GUID counter for objects
796	guid: 1,
797
798	// Bind a function to a context, optionally partially applying any
799	// arguments.
800	proxy: function( fn, context ) {
801		var args, proxy, tmp;
802
803		if ( typeof context === "string" ) {
804			tmp = fn[ context ];
805			context = fn;
806			fn = tmp;
807		}
808
809		// Quick check to determine if target is callable, in the spec
810		// this throws a TypeError, but we will just return undefined.
811		if ( !jQuery.isFunction( fn ) ) {
812			return undefined;
813		}
814
815		// Simulated bind
816		args = core_slice.call( arguments, 2 );
817		proxy = function() {
818			return fn.apply( context || this, args.concat( core_slice.call( arguments ) ) );
819		};
820
821		// Set the guid of unique handler to the same of original handler, so it can be removed
822		proxy.guid = fn.guid = fn.guid || jQuery.guid++;
823
824		return proxy;
825	},
826
827	// Multifunctional method to get and set values of a collection
828	// The value/s can optionally be executed if it's a function
829	access: function( elems, fn, key, value, chainable, emptyGet, raw ) {
830		var i = 0,
831			length = elems.length,
832			bulk = key == null;
833
834		// Sets many values
835		if ( jQuery.type( key ) === "object" ) {
836			chainable = true;
837			for ( i in key ) {
838				jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
839			}
840
841		// Sets one value
842		} else if ( value !== undefined ) {
843			chainable = true;
844
845			if ( !jQuery.isFunction( value ) ) {
846				raw = true;
847			}
848
849			if ( bulk ) {
850				// Bulk operations run against the entire set
851				if ( raw ) {
852					fn.call( elems, value );
853					fn = null;
854
855				// ...except when executing function values
856				} else {
857					bulk = fn;
858					fn = function( elem, key, value ) {
859						return bulk.call( jQuery( elem ), value );
860					};
861				}
862			}
863
864			if ( fn ) {
865				for ( ; i < length; i++ ) {
866					fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
867				}
868			}
869		}
870
871		return chainable ?
872			elems :
873
874			// Gets
875			bulk ?
876				fn.call( elems ) :
877				length ? fn( elems[0], key ) : emptyGet;
878	},
879
880	now: function() {
881		return ( new Date() ).getTime();
882	}
883});
884
885jQuery.ready.promise = function( obj ) {
886	if ( !readyList ) {
887
888		readyList = jQuery.Deferred();
889
890		// Catch cases where $(document).ready() is called after the browser event has already occurred.
891		// we once tried to use readyState "interactive" here, but it caused issues like the one
892		// discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
893		if ( document.readyState === "complete" ) {
894			// Handle it asynchronously to allow scripts the opportunity to delay ready
895			setTimeout( jQuery.ready );
896
897		// Standards-based browsers support DOMContentLoaded
898		} else if ( document.addEventListener ) {
899			// Use the handy event callback
900			document.addEventListener( "DOMContentLoaded", completed, false );
901
902			// A fallback to window.onload, that will always work
903			window.addEventListener( "load", completed, false );
904
905		// If IE event model is used
906		} else {
907			// Ensure firing before onload, maybe late but safe also for iframes
908			document.attachEvent( "onreadystatechange", completed );
909
910			// A fallback to window.onload, that will always work
911			window.attachEvent( "onload", completed );
912
913			// If IE and not a frame
914			// continually check to see if the document is ready
915			var top = false;
916
917			try {
918				top = window.frameElement == null && document.documentElement;
919			} catch(e) {}
920
921			if ( top && top.doScroll ) {
922				(function doScrollCheck() {
923					if ( !jQuery.isReady ) {
924
925						try {
926							// Use the trick by Diego Perini
927							// http://javascript.nwbox.com/IEContentLoaded/
928							top.doScroll("left");
929						} catch(e) {
930							return setTimeout( doScrollCheck, 50 );
931						}
932
933						// detach all dom ready events
934						detach();
935
936						// and execute any waiting functions
937						jQuery.ready();
938					}
939				})();
940			}
941		}
942	}
943	return readyList.promise( obj );
944};
945
946// Populate the class2type map
947jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
948	class2type[ "[object " + name + "]" ] = name.toLowerCase();
949});
950
951function isArraylike( obj ) {
952	var length = obj.length,
953		type = jQuery.type( obj );
954
955	if ( jQuery.isWindow( obj ) ) {
956		return false;
957	}
958
959	if ( obj.nodeType === 1 && length ) {
960		return true;
961	}
962
963	return type === "array" || type !== "function" &&
964		( length === 0 ||
965		typeof length === "number" && length > 0 && ( length - 1 ) in obj );
966}
967
968// All jQuery objects should point back to these
969rootjQuery = jQuery(document);
970// String to Object options format cache
971var optionsCache = {};
972
973// Convert String-formatted options into Object-formatted ones and store in cache
974function createOptions( options ) {
975	var object = optionsCache[ options ] = {};
976	jQuery.each( options.match( core_rnotwhite ) || [], function( _, flag ) {
977		object[ flag ] = true;
978	});
979	return object;
980}
981
982/*
983 * Create a callback list using the following parameters:
984 *
985 *	options: an optional list of space-separated options that will change how
986 *			the callback list behaves or a more traditional option object
987 *
988 * By default a callback list will act like an event callback list and can be
989 * "fired" multiple times.
990 *
991 * Possible options:
992 *
993 *	once:			will ensure the callback list can only be fired once (like a Deferred)
994 *
995 *	memory:			will keep track of previous values and will call any callback added
996 *					after the list has been fired right away with the latest "memorized"
997 *					values (like a Deferred)
998 *
999 *	unique:			will ensure a callback can only be added once (no duplicate in the list)
1000 *
1001 *	stopOnFalse:	interrupt callings when a callback returns false
1002 *
1003 */
1004jQuery.Callbacks = function( options ) {
1005
1006	// Convert options from String-formatted to Object-formatted if needed
1007	// (we check in cache first)
1008	options = typeof options === "string" ?
1009		( optionsCache[ options ] || createOptions( options ) ) :
1010		jQuery.extend( {}, options );
1011
1012	var // Flag to know if list is currently firing
1013		firing,
1014		// Last fire value (for non-forgettable lists)
1015		memory,
1016		// Flag to know if list was already fired
1017		fired,
1018		// End of the loop when firing
1019		firingLength,
1020		// Index of currently firing callback (modified by remove if needed)
1021		firingIndex,
1022		// First callback to fire (used internally by add and fireWith)
1023		firingStart,
1024		// Actual callback list
1025		list = [],
1026		// Stack of fire calls for repeatable lists
1027		stack = !options.once && [],
1028		// Fire callbacks
1029		fire = function( data ) {
1030			memory = options.memory && data;
1031			fired = true;
1032			firingIndex = firingStart || 0;
1033			firingStart = 0;
1034			firingLength = list.length;
1035			firing = true;
1036			for ( ; list && firingIndex < firingLength; firingIndex++ ) {
1037				if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
1038					memory = false; // To prevent further calls using add
1039					break;
1040				}
1041			}
1042			firing = false;
1043			if ( list ) {
1044				if ( stack ) {
1045					if ( stack.length ) {
1046						fire( stack.shift() );
1047					}
1048				} else if ( memory ) {
1049					list = [];
1050				} else {
1051					self.disable();
1052				}
1053			}
1054		},
1055		// Actual Callbacks object
1056		self = {
1057			// Add a callback or a collection of callbacks to the list
1058			add: function() {
1059				if ( list ) {
1060					// First, we save the current length
1061					var start = list.length;
1062					(function add( args ) {
1063						jQuery.each( args, function( _, arg ) {
1064							var type = jQuery.type( arg );
1065							if ( type === "function" ) {
1066								if ( !options.unique || !self.has( arg ) ) {
1067									list.push( arg );
1068								}
1069							} else if ( arg && arg.length && type !== "string" ) {
1070								// Inspect recursively
1071								add( arg );
1072							}
1073						});
1074					})( arguments );
1075					// Do we need to add the callbacks to the
1076					// current firing batch?
1077					if ( firing ) {
1078						firingLength = list.length;
1079					// With memory, if we're not firing then
1080					// we should call right away
1081					} else if ( memory ) {
1082						firingStart = start;
1083						fire( memory );
1084					}
1085				}
1086				return this;
1087			},
1088			// Remove a callback from the list
1089			remove: function() {
1090				if ( list ) {
1091					jQuery.each( arguments, function( _, arg ) {
1092						var index;
1093						while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
1094							list.splice( index, 1 );
1095							// Handle firing indexes
1096							if ( firing ) {
1097								if ( index <= firingLength ) {
1098									firingLength--;
1099								}
1100								if ( index <= firingIndex ) {
1101									firingIndex--;
1102								}
1103							}
1104						}
1105					});
1106				}
1107				return this;
1108			},
1109			// Check if a given callback is in the list.
1110			// If no argument is given, return whether or not list has callbacks attached.
1111			has: function( fn ) {
1112				return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
1113			},
1114			// Remove all callbacks from the list
1115			empty: function() {
1116				list = [];
1117				return this;
1118			},
1119			// Have the list do nothing anymore
1120			disable: function() {
1121				list = stack = memory = undefined;
1122				return this;
1123			},
1124			// Is it disabled?
1125			disabled: function() {
1126				return !list;
1127			},
1128			// Lock the list in its current state
1129			lock: function() {
1130				stack = undefined;
1131				if ( !memory ) {
1132					self.disable();
1133				}
1134				return this;
1135			},
1136			// Is it locked?
1137			locked: function() {
1138				return !stack;
1139			},
1140			// Call all callbacks with the given context and arguments
1141			fireWith: function( context, args ) {
1142				args = args || [];
1143				args = [ context, args.slice ? args.slice() : args ];
1144				if ( list && ( !fired || stack ) ) {
1145					if ( firing ) {
1146						stack.push( args );
1147					} else {
1148						fire( args );
1149					}
1150				}
1151				return this;
1152			},
1153			// Call all the callbacks with the given arguments
1154			fire: function() {
1155				self.fireWith( this, arguments );
1156				return this;
1157			},
1158			// To know if the callbacks have already been called at least once
1159			fired: function() {
1160				return !!fired;
1161			}
1162		};
1163
1164	return self;
1165};
1166jQuery.extend({
1167
1168	Deferred: function( func ) {
1169		var tuples = [
1170				// action, add listener, listener list, final state
1171				[ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
1172				[ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
1173				[ "notify", "progress", jQuery.Callbacks("memory") ]
1174			],
1175			state = "pending",
1176			promise = {
1177				state: function() {
1178					return state;
1179				},
1180				always: function() {
1181					deferred.done( arguments ).fail( arguments );
1182					return this;
1183				},
1184				then: function( /* fnDone, fnFail, fnProgress */ ) {
1185					var fns = arguments;
1186					return jQuery.Deferred(function( newDefer ) {
1187						jQuery.each( tuples, function( i, tuple ) {
1188							var action = tuple[ 0 ],
1189								fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
1190							// deferred[ done | fail | progress ] for forwarding actions to newDefer
1191							deferred[ tuple[1] ](function() {
1192								var returned = fn && fn.apply( this, arguments );
1193								if ( returned && jQuery.isFunction( returned.promise ) ) {
1194									returned.promise()
1195										.done( newDefer.resolve )
1196										.fail( newDefer.reject )
1197										.progress( newDefer.notify );
1198								} else {
1199									newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
1200								}
1201							});
1202						});
1203						fns = null;
1204					}).promise();
1205				},
1206				// Get a promise for this deferred
1207				// If obj is provided, the promise aspect is added to the object
1208				promise: function( obj ) {
1209					return obj != null ? jQuery.extend( obj, promise ) : promise;
1210				}
1211			},
1212			deferred = {};
1213
1214		// Keep pipe for back-compat
1215		promise.pipe = promise.then;
1216
1217		// Add list-specific methods
1218		jQuery.each( tuples, function( i, tuple ) {
1219			var list = tuple[ 2 ],
1220				stateString = tuple[ 3 ];
1221
1222			// promise[ done | fail | progress ] = list.add
1223			promise[ tuple[1] ] = list.add;
1224
1225			// Handle state
1226			if ( stateString ) {
1227				list.add(function() {
1228					// state = [ resolved | rejected ]
1229					state = stateString;
1230
1231				// [ reject_list | resolve_list ].disable; progress_list.lock
1232				}, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
1233			}
1234
1235			// deferred[ resolve | reject | notify ]
1236			deferred[ tuple[0] ] = function() {
1237				deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
1238				return this;
1239			};
1240			deferred[ tuple[0] + "With" ] = list.fireWith;
1241		});
1242
1243		// Make the deferred a promise
1244		promise.promise( deferred );
1245
1246		// Call given func if any
1247		if ( func ) {
1248			func.call( deferred, deferred );
1249		}
1250
1251		// All done!
1252		return deferred;
1253	},
1254
1255	// Deferred helper
1256	when: function( subordinate /* , ..., subordinateN */ ) {
1257		var i = 0,
1258			resolveValues = core_slice.call( arguments ),
1259			length = resolveValues.length,
1260
1261			// the count of uncompleted subordinates
1262			remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
1263
1264			// the master Deferred. If resolveValues consist of only a single Deferred, just use that.
1265			deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
1266
1267			// Update function for both resolve and progress values
1268			updateFunc = function( i, contexts, values ) {
1269				return function( value ) {
1270					contexts[ i ] = this;
1271					values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value;
1272					if( values === progressValues ) {
1273						deferred.notifyWith( contexts, values );
1274					} else if ( !( --remaining ) ) {
1275						deferred.resolveWith( contexts, values );
1276					}
1277				};
1278			},
1279
1280			progressValues, progressContexts, resolveContexts;
1281
1282		// add listeners to Deferred subordinates; treat others as resolved
1283		if ( length > 1 ) {
1284			progressValues = new Array( length );
1285			progressContexts = new Array( length );
1286			resolveContexts = new Array( length );
1287			for ( ; i < length; i++ ) {
1288				if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
1289					resolveValues[ i ].promise()
1290						.done( updateFunc( i, resolveContexts, resolveValues ) )
1291						.fail( deferred.reject )
1292						.progress( updateFunc( i, progressContexts, progressValues ) );
1293				} else {
1294					--remaining;
1295				}
1296			}
1297		}
1298
1299		// if we're not waiting on anything, resolve the master
1300		if ( !remaining ) {
1301			deferred.resolveWith( resolveContexts, resolveValues );
1302		}
1303
1304		return deferred.promise();
1305	}
1306});
1307jQuery.support = (function() {
1308
1309	var support, all, a,
1310		input, select, fragment,
1311		opt, eventName, isSupported, i,
1312		div = document.createElement("div");
1313
1314	// Setup
1315	div.setAttribute( "className", "t" );
1316	div.innerHTML = "  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
1317
1318	// Support tests won't run in some limited or non-browser environments
1319	all = div.getElementsByTagName("*");
1320	a = div.getElementsByTagName("a")[ 0 ];
1321	if ( !all || !a || !all.length ) {
1322		return {};
1323	}
1324
1325	// First batch of tests
1326	select = document.createElement("select");
1327	opt = select.appendChild( document.createElement("option") );
1328	input = div.getElementsByTagName("input")[ 0 ];
1329
1330	a.style.cssText = "top:1px;float:left;opacity:.5";
1331	support = {
1332		// Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
1333		getSetAttribute: div.className !== "t",
1334
1335		// IE strips leading whitespace when .innerHTML is used
1336		leadingWhitespace: div.firstChild.nodeType === 3,
1337
1338		// Make sure that tbody elements aren't automatically inserted
1339		// IE will insert them into empty tables
1340		tbody: !div.getElementsByTagName("tbody").length,
1341
1342		// Make sure that link elements get serialized correctly by innerHTML
1343		// This requires a wrapper element in IE
1344		htmlSerialize: !!div.getElementsByTagName("link").length,
1345
1346		// Get the style information from getAttribute
1347		// (IE uses .cssText instead)
1348		style: /top/.test( a.getAttribute("style") ),
1349
1350		// Make sure that URLs aren't manipulated
1351		// (IE normalizes it by default)
1352		hrefNormalized: a.getAttribute("href") === "/a",
1353
1354		// Make sure that element opacity exists
1355		// (IE uses filter instead)
1356		// Use a regex to work around a WebKit issue. See #5145
1357		opacity: /^0.5/.test( a.style.opacity ),
1358
1359		// Verify style float existence
1360		// (IE uses styleFloat instead of cssFloat)
1361		cssFloat: !!a.style.cssFloat,
1362
1363		// Check the default checkbox/radio value ("" on WebKit; "on" elsewhere)
1364		checkOn: !!input.value,
1365
1366		// Make sure that a selected-by-default option has a working selected property.
1367		// (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
1368		optSelected: opt.selected,
1369
1370		// Tests for enctype support on a form (#6743)
1371		enctype: !!document.createElement("form").enctype,
1372
1373		// Makes sure cloning an html5 element does not cause problems
1374		// Where outerHTML is undefined, this still works
1375		html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav></:nav>",
1376
1377		// jQuery.support.boxModel DEPRECATED in 1.8 since we don't support Quirks Mode
1378		boxModel: document.compatMode === "CSS1Compat",
1379
1380		// Will be defined later
1381		deleteExpando: true,
1382		noCloneEvent: true,
1383		inlineBlockNeedsLayout: false,
1384		shrinkWrapBlocks: false,
1385		reliableMarginRight: true,
1386		boxSizingReliable: true,
1387		pixelPosition: false
1388	};
1389
1390	// Make sure checked status is properly cloned
1391	input.checked = true;
1392	support.noCloneChecked = input.cloneNode( true ).checked;
1393
1394	// Make sure that the options inside disabled selects aren't marked as disabled
1395	// (WebKit marks them as disabled)
1396	select.disabled = true;
1397	support.optDisabled = !opt.disabled;
1398
1399	// Support: IE<9
1400	try {
1401		delete div.test;
1402	} catch( e ) {
1403		support.deleteExpando = false;
1404	}
1405
1406	// Check if we can trust getAttribute("value")
1407	input = document.createElement("input");
1408	input.setAttribute( "value", "" );
1409	support.input = input.getAttribute( "value" ) === "";
1410
1411	// Check if an input maintains its value after becoming a radio
1412	input.value = "t";
1413	input.setAttribute( "type", "radio" );
1414	support.radioValue = input.value === "t";
1415
1416	// #11217 - WebKit loses check when the name is after the checked attribute
1417	input.setAttribute( "checked", "t" );
1418	input.setAttribute( "name", "t" );
1419
1420	fragment = document.createDocumentFragment();
1421	fragment.appendChild( input );
1422
1423	// Check if a disconnected checkbox will retain its checked
1424	// value of true after appended to the DOM (IE6/7)
1425	support.appendChecked = input.checked;
1426
1427	// WebKit doesn't clone checked state correctly in fragments
1428	support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
1429
1430	// Support: IE<9
1431	// Opera does not clone events (and typeof div.attachEvent === undefined).
1432	// IE9-10 clones events bound via attachEvent, but they don't trigger with .click()
1433	if ( div.attachEvent ) {
1434		div.attachEvent( "onclick", function() {
1435			support.noCloneEvent = false;
1436		});
1437
1438		div.cloneNode( true ).click();
1439	}
1440
1441	// Support: IE<9 (lack submit/change bubble), Firefox 17+ (lack focusin event)
1442	// Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP), test/csp.php
1443	for ( i in { submit: true, change: true, focusin: true }) {
1444		div.setAttribute( eventName = "on" + i, "t" );
1445
1446		support[ i + "Bubbles" ] = eventName in window || div.attributes[ eventName ].expando === false;
1447	}
1448
1449	div.style.backgroundClip = "content-box";
1450	div.cloneNode( true ).style.backgroundClip = "";
1451	support.clearCloneStyle = div.style.backgroundClip === "content-box";
1452
1453	// Run tests that need a body at doc ready
1454	jQuery(function() {
1455		var container, marginDiv, tds,
1456			divReset = "padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",
1457			body = document.getElementsByTagName("body")[0];
1458
1459		if ( !body ) {
1460			// Return for frameset docs that don't have a body
1461			return;
1462		}
1463
1464		container = document.createElement("div");
1465		container.style.cssText = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px";
1466
1467		body.appendChild( container ).appendChild( div );
1468
1469		// Support: IE8
1470		// Check if table cells still have offsetWidth/Height when they are set
1471		// to display:none and there are still other visible table cells in a
1472		// table row; if so, offsetWidth/Height are not reliable for use when
1473		// determining if an element has been hidden directly using
1474		// display:none (it is still safe to use offsets if a parent element is
1475		// hidden; don safety goggles and see bug #4512 for more information).
1476		div.innerHTML = "<table><tr><td></td><td>t</td></tr></table>";
1477		tds = div.getElementsByTagName("td");
1478		tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none";
1479		isSupported = ( tds[ 0 ].offsetHeight === 0 );
1480
1481		tds[ 0 ].style.display = "";
1482		tds[ 1 ].style.display = "none";
1483
1484		// Support: IE8
1485		// Check if empty table cells still have offsetWidth/Height
1486		support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
1487
1488		// Check box-sizing and margin behavior
1489		div.innerHTML = "";
1490		div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;";
1491		support.boxSizing = ( div.offsetWidth === 4 );
1492		support.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== 1 );
1493
1494		// Use window.getComputedStyle because jsdom on node.js will break without it.
1495		if ( window.getComputedStyle ) {
1496			support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%";
1497			support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px";
1498
1499			// Check if div with explicit width and no margin-right incorrectly
1500			// gets computed margin-right based on width of container. (#3333)
1501			// Fails in WebKit before Feb 2011 nightlies
1502			// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
1503			marginDiv = div.appendChild( document.createElement("div") );
1504			marginDiv.style.cssText = div.style.cssText = divReset;
1505			marginDiv.style.marginRight = marginDiv.style.width = "0";
1506			div.style.width = "1px";
1507
1508			support.reliableMarginRight =
1509				!parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight );
1510		}
1511
1512		if ( typeof div.style.zoom !== core_strundefined ) {
1513			// Support: IE<8
1514			// Check if natively block-level elements act like inline-block
1515			// elements when setting their display to 'inline' and giving
1516			// them layout
1517			div.innerHTML = "";
1518			div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1";
1519			support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 );
1520
1521			// Support: IE6
1522			// Check if elements with layout shrink-wrap their children
1523			div.style.display = "block";
1524			div.innerHTML = "<div></div>";
1525			div.firstChild.style.width = "5px";
1526			support.shrinkWrapBlocks = ( div.offsetWidth !== 3 );
1527
1528			if ( support.inlineBlockNeedsLayout ) {
1529				// Prevent IE 6 from affecting layout for positioned elements #11048
1530				// Prevent IE from shrinking the body in IE 7 mode #12869
1531				// Support: IE<8
1532				body.style.zoom = 1;
1533			}
1534		}
1535
1536		body.removeChild( container );
1537
1538		// Null elements to avoid leaks in IE
1539		container = div = tds = marginDiv = null;
1540	});
1541
1542	// Null elements to avoid leaks in IE
1543	all = select = fragment = opt = a = input = null;
1544
1545	return support;
1546})();
1547
1548var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/,
1549	rmultiDash = /([A-Z])/g;
1550
1551function internalData( elem, name, data, pvt /* Internal Use Only */ ){
1552	if ( !jQuery.acceptData( elem ) ) {
1553		return;
1554	}
1555
1556	var thisCache, ret,
1557		internalKey = jQuery.expando,
1558		getByName = typeof name === "string",
1559
1560		// We have to handle DOM nodes and JS objects differently because IE6-7
1561		// can't GC object references properly across the DOM-JS boundary
1562		isNode = elem.nodeType,
1563
1564		// Only DOM nodes need the global jQuery cache; JS object data is
1565		// attached directly to the object so GC can occur automatically
1566		cache = isNode ? jQuery.cache : elem,
1567
1568		// Only defining an ID for JS objects if its cache already exists allows
1569		// the code to shortcut on the same path as a DOM node with no cache
1570		id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey;
1571
1572	// Avoid doing any more work than we need to when trying to get data on an
1573	// object that has no data at all
1574	if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && getByName && data === undefined ) {
1575		return;
1576	}
1577
1578	if ( !id ) {
1579		// Only DOM nodes need a new unique ID for each element since their data
1580		// ends up in the global cache
1581		if ( isNode ) {
1582			elem[ internalKey ] = id = core_deletedIds.pop() || jQuery.guid++;
1583		} else {
1584			id = internalKey;
1585		}
1586	}
1587
1588	if ( !cache[ id ] ) {
1589		cache[ id ] = {};
1590
1591		// Avoids exposing jQuery metadata on plain JS objects when the object
1592		// is serialized using JSON.stringify
1593		if ( !isNode ) {
1594			cache[ id ].toJSON = jQuery.noop;
1595		}
1596	}
1597
1598	// An object can be passed to jQuery.data instead of a key/value pair; this gets
1599	// shallow copied over onto the existing cache
1600	if ( typeof name === "object" || typeof name === "function" ) {
1601		if ( pvt ) {
1602			cache[ id ] = jQuery.extend( cache[ id ], name );
1603		} else {
1604			cache[ id ].data = jQuery.extend( cache[ id ].data, name );
1605		}
1606	}
1607
1608	thisCache = cache[ id ];
1609
1610	// jQuery data() is stored in a separate object inside the object's internal data
1611	// cache in order to avoid key collisions between internal data and user-defined
1612	// data.
1613	if ( !pvt ) {
1614		if ( !thisCache.data ) {
1615			thisCache.data = {};
1616		}
1617
1618		thisCache = thisCache.data;
1619	}
1620
1621	if ( data !== undefined ) {
1622		thisCache[ jQuery.camelCase( name ) ] = data;
1623	}
1624
1625	// Check for both converted-to-camel and non-converted data property names
1626	// If a data property was specified
1627	if ( getByName ) {
1628
1629		// First Try to find as-is property data
1630		ret = thisCache[ name ];
1631
1632		// Test for null|undefined property data
1633		if ( ret == null ) {
1634
1635			// Try to find the camelCased property
1636			ret = thisCache[ jQuery.camelCase( name ) ];
1637		}
1638	} else {
1639		ret = thisCache;
1640	}
1641
1642	return ret;
1643}
1644
1645function internalRemoveData( elem, name, pvt ) {
1646	if ( !jQuery.acceptData( elem ) ) {
1647		return;
1648	}
1649
1650	var i, l, thisCache,
1651		isNode = elem.nodeType,
1652
1653		// See jQuery.data for more information
1654		cache = isNode ? jQuery.cache : elem,
1655		id = isNode ? elem[ jQuery.expando ] : jQuery.expando;
1656
1657	// If there is already no cache entry for this object, there is no
1658	// purpose in continuing
1659	if ( !cache[ id ] ) {
1660		return;
1661	}
1662
1663	if ( name ) {
1664
1665		thisCache = pvt ? cache[ id ] : cache[ id ].data;
1666
1667		if ( thisCache ) {
1668
1669			// Support array or space separated string names for data keys
1670			if ( !jQuery.isArray( name ) ) {
1671
1672				// try the string as a key before any manipulation
1673				if ( name in thisCache ) {
1674					name = [ name ];
1675				} else {
1676
1677					// split the camel cased version by spaces unless a key with the spaces exists
1678					name = jQuery.camelCase( name );
1679					if ( name in thisCache ) {
1680						name = [ name ];
1681					} else {
1682						name = name.split(" ");
1683					}
1684				}
1685			} else {
1686				// If "name" is an array of keys...
1687				// When data is initially created, via ("key", "val") signature,
1688				// keys will be converted to camelCase.
1689				// Since there is no way to tell _how_ a key was added, remove
1690				// both plain key and camelCase key. #12786
1691				// This will only penalize the array argument path.
1692				name = name.concat( jQuery.map( name, jQuery.camelCase ) );
1693			}
1694
1695			for ( i = 0, l = name.length; i < l; i++ ) {
1696				delete thisCache[ name[i] ];
1697			}
1698
1699			// If there is no data left in the cache, we want to continue
1700			// and let the cache object itself get destroyed
1701			if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) {
1702				return;
1703			}
1704		}
1705	}
1706
1707	// See jQuery.data for more information
1708	if ( !pvt ) {
1709		delete cache[ id ].data;
1710
1711		// Don't destroy the parent cache unless the internal data object
1712		// had been the only thing left in it
1713		if ( !isEmptyDataObject( cache[ id ] ) ) {
1714			return;
1715		}
1716	}
1717
1718	// Destroy the cache
1719	if ( isNode ) {
1720		jQuery.cleanData( [ elem ], true );
1721
1722	// Use delete when supported for expandos or `cache` is not a window per isWindow (#10080)
1723	} else if ( jQuery.support.deleteExpando || cache != cache.window ) {
1724		delete cache[ id ];
1725
1726	// When all else fails, null
1727	} else {
1728		cache[ id ] = null;
1729	}
1730}
1731
1732jQuery.extend({
1733	cache: {},
1734
1735	// Unique for each copy of jQuery on the page
1736	// Non-digits removed to match rinlinejQuery
1737	expando: "jQuery" + ( core_version + Math.random() ).replace( /\D/g, "" ),
1738
1739	// The following elements throw uncatchable exceptions if you
1740	// attempt to add expando properties to them.
1741	noData: {
1742		"embed": true,
1743		// Ban all objects except for Flash (which handle expandos)
1744		"object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",
1745		"applet": true
1746	},
1747
1748	hasData: function( elem ) {
1749		elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
1750		return !!elem && !isEmptyDataObject( elem );
1751	},
1752
1753	data: function( elem, name, data ) {
1754		return internalData( elem, name, data );
1755	},
1756
1757	removeData: function( elem, name ) {
1758		return internalRemoveData( elem, name );
1759	},
1760
1761	// For internal use only.
1762	_data: function( elem, name, data ) {
1763		return internalData( elem, name, data, true );
1764	},
1765
1766	_removeData: function( elem, name ) {
1767		return internalRemoveData( elem, name, true );
1768	},
1769
1770	// A method for determining if a DOM node can handle the data expando
1771	acceptData: function( elem ) {
1772		// Do not set data on non-element because it will not be cleared (#8335).
1773		if ( elem.nodeType && elem.nodeType !== 1 && elem.nodeType !== 9 ) {
1774			return false;
1775		}
1776
1777		var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ];
1778
1779		// nodes accept data unless otherwise specified; rejection can be conditional
1780		return !noData || noData !== true && elem.getAttribute("classid") === noData;
1781	}
1782});
1783
1784jQuery.fn.extend({
1785	data: function( key, value ) {
1786		var attrs, name,
1787			elem = this[0],
1788			i = 0,
1789			data = null;
1790
1791		// Gets all values
1792		if ( key === undefined ) {
1793			if ( this.length ) {
1794				data = jQuery.data( elem );
1795
1796				if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
1797					attrs = elem.attributes;
1798					for ( ; i < attrs.length; i++ ) {
1799						name = attrs[i].name;
1800
1801						if ( !name.indexOf( "data-" ) ) {
1802							name = jQuery.camelCase( name.slice(5) );
1803
1804							dataAttr( elem, name, data[ name ] );
1805						}
1806					}
1807					jQuery._data( elem, "parsedAttrs", true );
1808				}
1809			}
1810
1811			return data;
1812		}
1813
1814		// Sets multiple values
1815		if ( typeof key === "object" ) {
1816			return this.each(function() {
1817				jQuery.data( this, key );
1818			});
1819		}
1820
1821		return jQuery.access( this, function( value ) {
1822
1823			if ( value === undefined ) {
1824				// Try to fetch any internally stored data first
1825				return elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : null;
1826			}
1827
1828			this.each(function() {
1829				jQuery.data( this, key, value );
1830			});
1831		}, null, value, arguments.length > 1, null, true );
1832	},
1833
1834	removeData: function( key ) {
1835		return this.each(function() {
1836			jQuery.removeData( this, key );
1837		});
1838	}
1839});
1840
1841function dataAttr( elem, key, data ) {
1842	// If nothing was found internally, try to fetch any
1843	// data from the HTML5 data-* attribute
1844	if ( data === undefined && elem.nodeType === 1 ) {
1845
1846		var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
1847
1848		data = elem.getAttribute( name );
1849
1850		if ( typeof data === "string" ) {
1851			try {
1852				data = data === "true" ? true :
1853					data === "false" ? false :
1854					data === "null" ? null :
1855					// Only convert to a number if it doesn't change the string
1856					+data + "" === data ? +data :
1857					rbrace.test( data ) ? jQuery.parseJSON( data ) :
1858						data;
1859			} catch( e ) {}
1860
1861			// Make sure we set the data so it isn't changed later
1862			jQuery.data( elem, key, data );
1863
1864		} else {
1865			data = undefined;
1866		}
1867	}
1868
1869	return data;
1870}
1871
1872// checks a cache object for emptiness
1873function isEmptyDataObject( obj ) {
1874	var name;
1875	for ( name in obj ) {
1876
1877		// if the public data object is empty, the private is still empty
1878		if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
1879			continue;
1880		}
1881		if ( name !== "toJSON" ) {
1882			return false;
1883		}
1884	}
1885
1886	return true;
1887}
1888jQuery.extend({
1889	queue: function( elem, type, data ) {
1890		var queue;
1891
1892		if ( elem ) {
1893			type = ( type || "fx" ) + "queue";
1894			queue = jQuery._data( elem, type );
1895
1896			// Speed up dequeue by getting out quickly if this is just a lookup
1897			if ( data ) {
1898				if ( !queue || jQuery.isArray(data) ) {
1899					queue = jQuery._data( elem, type, jQuery.makeArray(data) );
1900				} else {
1901					queue.push( data );
1902				}
1903			}
1904			return queue || [];
1905		}
1906	},
1907
1908	dequeue: function( elem, type ) {
1909		type = type || "fx";
1910
1911		var queue = jQuery.queue( elem, type ),
1912			startLength = queue.length,
1913			fn = queue.shift(),
1914			hooks = jQuery._queueHooks( elem, type ),
1915			next = function() {
1916				jQuery.dequeue( elem, type );
1917			};
1918
1919		// If the fx queue is dequeued, always remove the progress sentinel
1920		if ( fn === "inprogress" ) {
1921			fn = queue.shift();
1922			startLength--;
1923		}
1924
1925		hooks.cur = fn;
1926		if ( fn ) {
1927
1928			// Add a progress sentinel to prevent the fx queue from being
1929			// automatically dequeued
1930			if ( type === "fx" ) {
1931				queue.unshift( "inprogress" );
1932			}
1933
1934			// clear up the last queue stop function
1935			delete hooks.stop;
1936			fn.call( elem, next, hooks );
1937		}
1938
1939		if ( !startLength && hooks ) {
1940			hooks.empty.fire();
1941		}
1942	},
1943
1944	// not intended for public consumption - generates a queueHooks object, or returns the current one
1945	_queueHooks: function( elem, type ) {
1946		var key = type + "queueHooks";
1947		return jQuery._data( elem, key ) || jQuery._data( elem, key, {
1948			empty: jQuery.Callbacks("once memory").add(function() {
1949				jQuery._removeData( elem, type + "queue" );
1950				jQuery._removeData( elem, key );
1951			})
1952		});
1953	}
1954});
1955
1956jQuery.fn.extend({
1957	queue: function( type, data ) {
1958		var setter = 2;
1959
1960		if ( typeof type !== "string" ) {
1961			data = type;
1962			type = "fx";
1963			setter--;
1964		}
1965
1966		if ( arguments.length < setter ) {
1967			return jQuery.queue( this[0], type );
1968		}
1969
1970		return data === undefined ?
1971			this :
1972			this.each(function() {
1973				var queue = jQuery.queue( this, type, data );
1974
1975				// ensure a hooks for this queue
1976				jQuery._queueHooks( this, type );
1977
1978				if ( type === "fx" && queue[0] !== "inprogress" ) {
1979					jQuery.dequeue( this, type );
1980				}
1981			});
1982	},
1983	dequeue: function( type ) {
1984		return this.each(function() {
1985			jQuery.dequeue( this, type );
1986		});
1987	},
1988	// Based off of the plugin by Clint Helfers, with permission.
1989	// http://blindsignals.com/index.php/2009/07/jquery-delay/
1990	delay: function( time, type ) {
1991		time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
1992		type = type || "fx";
1993
1994		return this.queue( type, function( next, hooks ) {
1995			var timeout = setTimeout( next, time );
1996			hooks.stop = function() {
1997				clearTimeout( timeout );
1998			};
1999		});
2000	},
2001	clearQueue: function( type ) {
2002		return this.queue( type || "fx", [] );
2003	},
2004	// Get a promise resolved when queues of a certain type
2005	// are emptied (fx is the type by default)
2006	promise: function( type, obj ) {
2007		var tmp,
2008			count = 1,
2009			defer = jQuery.Deferred(),
2010			elements = this,
2011			i = this.length,
2012			resolve = function() {
2013				if ( !( --count ) ) {
2014					defer.resolveWith( elements, [ elements ] );
2015				}
2016			};
2017
2018		if ( typeof type !== "string" ) {
2019			obj = type;
2020			type = undefined;
2021		}
2022		type = type || "fx";
2023
2024		while( i-- ) {
2025			tmp = jQuery._data( elements[ i ], type + "queueHooks" );
2026			if ( tmp && tmp.empty ) {
2027				count++;
2028				tmp.empty.add( resolve );
2029			}
2030		}
2031		resolve();
2032		return defer.promise( obj );
2033	}
2034});
2035var nodeHook, boolHook,
2036	rclass = /[\t\r\n]/g,
2037	rreturn = /\r/g,
2038	rfocusable = /^(?:input|select|textarea|button|object)$/i,
2039	rclickable = /^(?:a|area)$/i,
2040	rboolean = /^(?:checked|selected|autofocus|autoplay|async|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped)$/i,
2041	ruseDefault = /^(?:checked|selected)$/i,
2042	getSetAttribute = jQuery.support.getSetAttribute,
2043	getSetInput = jQuery.support.input;
2044
2045jQuery.fn.extend({
2046	attr: function( name, value ) {
2047		return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
2048	},
2049
2050	removeAttr: function( name ) {
2051		return this.each(function() {
2052			jQuery.removeAttr( this, name );
2053		});
2054	},
2055
2056	prop: function( name, value ) {
2057		return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );
2058	},
2059
2060	removeProp: function( name ) {
2061		name = jQuery.propFix[ name ] || name;
2062		return this.each(function() {
2063			// try/catch handles cases where IE balks (such as removing a property on window)
2064			try {
2065				this[ name ] = undefined;
2066				delete this[ name ];
2067			} catch( e ) {}
2068		});
2069	},
2070
2071	addClass: function( value ) {
2072		var classes, elem, cur, clazz, j,
2073			i = 0,
2074			len = this.length,
2075			proceed = typeof value === "string" && value;
2076
2077		if ( jQuery.isFunction( value ) ) {
2078			return this.each(function( j ) {
2079				jQuery( this ).addClass( value.call( this, j, this.className ) );
2080			});
2081		}
2082
2083		if ( proceed ) {
2084			// The disjunction here is for better compressibility (see removeClass)
2085			classes = ( value || "" ).match( core_rnotwhite ) || [];
2086
2087			for ( ; i < len; i++ ) {
2088				elem = this[ i ];
2089				cur = elem.nodeType === 1 && ( elem.className ?
2090					( " " + elem.className + " " ).replace( rclass, " " ) :
2091					" "
2092				);
2093
2094				if ( cur ) {
2095					j = 0;
2096					while ( (clazz = classes[j++]) ) {
2097						if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
2098							cur += clazz + " ";
2099						}
2100					}
2101					elem.className = jQuery.trim( cur );
2102
2103				}
2104			}
2105		}
2106
2107		return this;
2108	},
2109
2110	removeClass: function( value ) {
2111		var classes, elem, cur, clazz, j,
2112			i = 0,
2113			len = this.length,
2114			proceed = arguments.length === 0 || typeof value === "string" && value;
2115
2116		if ( jQuery.isFunction( value ) ) {
2117			return this.each(function( j ) {
2118				jQuery( this ).removeClass( value.call( this, j, this.className ) );
2119			});
2120		}
2121		if ( proceed ) {
2122			classes = ( value || "" ).match( core_rnotwhite ) || [];
2123
2124			for ( ; i < len; i++ ) {
2125				elem = this[ i ];
2126				// This expression is here for better compressibility (see addClass)
2127				cur = elem.nodeType === 1 && ( elem.className ?
2128					( " " + elem.className + " " ).replace( rclass, " " ) :
2129					""
2130				);
2131
2132				if ( cur ) {
2133					j = 0;
2134					while ( (clazz = classes[j++]) ) {
2135						// Remove *all* instances
2136						while ( cur.indexOf( " " + clazz + " " ) >= 0 ) {
2137							cur = cur.replace( " " + clazz + " ", " " );
2138						}
2139					}
2140					elem.className = value ? jQuery.trim( cur ) : "";
2141				}
2142			}
2143		}
2144
2145		return this;
2146	},
2147
2148	toggleClass: function( value, stateVal ) {
2149		var type = typeof value,
2150			isBool = typeof stateVal === "boolean";
2151
2152		if ( jQuery.isFunction( value ) ) {
2153			return this.each(function( i ) {
2154				jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
2155			});
2156		}
2157
2158		return this.each(function() {
2159			if ( type === "string" ) {
2160				// toggle individual class names
2161				var className,
2162					i = 0,
2163					self = jQuery( this ),
2164					state = stateVal,
2165					classNames = value.match( core_rnotwhite ) || [];
2166
2167				while ( (className = classNames[ i++ ]) ) {
2168					// check each className given, space separated list
2169					state = isBool ? state : !self.hasClass( className );
2170					self[ state ? "addClass" : "removeClass" ]( className );
2171				}
2172
2173			// Toggle whole class name
2174			} else if ( type === core_strundefined || type === "boolean" ) {
2175				if ( this.className ) {
2176					// store className if set
2177					jQuery._data( this, "__className__", this.className );
2178				}
2179
2180				// If the element has a class name or if we're passed "false",
2181				// then remove the whole classname (if there was one, the above saved it).
2182				// Otherwise bring back whatever was previously saved (if anything),
2183				// falling back to the empty string if nothing was stored.
2184				this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
2185			}
2186		});
2187	},
2188
2189	hasClass: function( selector ) {
2190		var className = " " + selector + " ",
2191			i = 0,
2192			l = this.length;
2193		for ( ; i < l; i++ ) {
2194			if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
2195				return true;
2196			}
2197		}
2198
2199		return false;
2200	},
2201
2202	val: function( value ) {
2203		var ret, hooks, isFunction,
2204			elem = this[0];
2205
2206		if ( !arguments.length ) {
2207			if ( elem ) {
2208				hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
2209
2210				if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
2211					return ret;
2212				}
2213
2214				ret = elem.value;
2215
2216				return typeof ret === "string" ?
2217					// handle most common string cases
2218					ret.replace(rreturn, "") :
2219					// handle cases where value is null/undef or number
2220					ret == null ? "" : ret;
2221			}
2222
2223			return;
2224		}
2225
2226		isFunction = jQuery.isFunction( value );
2227
2228		return this.each(function( i ) {
2229			var val,
2230				self = jQuery(this);
2231
2232			if ( this.nodeType !== 1 ) {
2233				return;
2234			}
2235
2236			if ( isFunction ) {
2237				val = value.call( this, i, self.val() );
2238			} else {
2239				val = value;
2240			}
2241
2242			// Treat null/undefined as ""; convert numbers to string
2243			if ( val == null ) {
2244				val = "";
2245			} else if ( typeof val === "number" ) {
2246				val += "";
2247			} else if ( jQuery.isArray( val ) ) {
2248				val = jQuery.map(val, function ( value ) {
2249					return value == null ? "" : value + "";
2250				});
2251			}
2252
2253			hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
2254
2255			// If set returns undefined, fall back to normal setting
2256			if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
2257				this.value = val;
2258			}
2259		});
2260	}
2261});
2262
2263jQuery.extend({
2264	valHooks: {
2265		option: {
2266			get: function( elem ) {
2267				// attributes.value is undefined in Blackberry 4.7 but
2268				// uses .value. See #6932
2269				var val = elem.attributes.value;
2270				return !val || val.specified ? elem.value : elem.text;
2271			}
2272		},
2273		select: {
2274			get: function( elem ) {
2275				var value, option,
2276					options = elem.options,
2277					index = elem.selectedIndex,
2278					one = elem.type === "select-one" || index < 0,
2279					values = one ? null : [],
2280					max = one ? index + 1 : options.length,
2281					i = index < 0 ?
2282						max :
2283						one ? index : 0;
2284
2285				// Loop through all the selected options
2286				for ( ; i < max; i++ ) {
2287					option = options[ i ];
2288
2289					// oldIE doesn't update selected after form reset (#2551)
2290					if ( ( option.selected || i === index ) &&
2291							// Don't return options that are disabled or in a disabled optgroup
2292							( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) &&
2293							( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
2294
2295						// Get the specific value for the option
2296						value = jQuery( option ).val();
2297
2298						// We don't need an array for one selects
2299						if ( one ) {
2300							return value;
2301						}
2302
2303						// Multi-Selects return an array
2304						values.push( value );
2305					}
2306				}
2307
2308				return values;
2309			},
2310
2311			set: function( elem, value ) {
2312				var values = jQuery.makeArray( value );
2313
2314				jQuery(elem).find("option").each(function() {
2315					this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
2316				});
2317
2318				if ( !values.length ) {
2319					elem.selectedIndex = -1;
2320				}
2321				return values;
2322			}
2323		}
2324	},
2325
2326	attr: function( elem, name, value ) {
2327		var hooks, notxml, ret,
2328			nType = elem.nodeType;
2329
2330		// don't get/set attributes on text, comment and attribute nodes
2331		if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
2332			return;
2333		}
2334
2335		// Fallback to prop when attributes are not supported
2336		if ( typeof elem.getAttribute === core_strundefined ) {
2337			return jQuery.prop( elem, name, value );
2338		}
2339
2340		notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
2341
2342		// All attributes are lowercase
2343		// Grab necessary hook if one is defined
2344		if ( notxml ) {
2345			name = name.toLowerCase();
2346			hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook );
2347		}
2348
2349		if ( value !== undefined ) {
2350
2351			if ( value === null ) {
2352				jQuery.removeAttr( elem, name );
2353
2354			} else if ( hooks && notxml && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
2355				return ret;
2356
2357			} else {
2358				elem.setAttribute( name, value + "" );
2359				return value;
2360			}
2361
2362		} else if ( hooks && notxml && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
2363			return ret;
2364
2365		} else {
2366
2367			// In IE9+, Flash objects don't have .getAttribute (#12945)
2368			// Support: IE9+
2369			if ( typeof elem.getAttribute !== core_strundefined ) {
2370				ret =  elem.getAttribute( name );
2371			}
2372
2373			// Non-existent attributes return null, we normalize to undefined
2374			return ret == null ?
2375				undefined :
2376				ret;
2377		}
2378	},
2379
2380	removeAttr: function( elem, value ) {
2381		var name, propName,
2382			i = 0,
2383			attrNames = value && value.match( core_rnotwhite );
2384
2385		if ( attrNames && elem.nodeType === 1 ) {
2386			while ( (name = attrNames[i++]) ) {
2387				propName = jQuery.propFix[ name ] || name;
2388
2389				// Boolean attributes get special treatment (#10870)
2390				if ( rboolean.test( name ) ) {
2391					// Set corresponding property to false for boolean attributes
2392					// Also clear defaultChecked/defaultSelected (if appropriate) for IE<8
2393					if ( !getSetAttribute && ruseDefault.test( name ) ) {
2394						elem[ jQuery.camelCase( "default-" + name ) ] =
2395							elem[ propName ] = false;
2396					} else {
2397						elem[ propName ] = false;
2398					}
2399
2400				// See #9699 for explanation of this approach (setting first, then removal)
2401				} else {
2402					jQuery.attr( elem, name, "" );
2403				}
2404
2405				elem.removeAttribute( getSetAttribute ? name : propName );
2406			}
2407		}
2408	},
2409
2410	attrHooks: {
2411		type: {
2412			set: function( elem, value ) {
2413				if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
2414					// Setting the type on a radio button after the value resets the value in IE6-9
2415					// Reset value to default in case type is set after value during creation
2416					var val = elem.value;
2417					elem.setAttribute( "type", value );
2418					if ( val ) {
2419						elem.value = val;
2420					}
2421					return value;
2422				}
2423			}
2424		}
2425	},
2426
2427	propFix: {
2428		tabindex: "tabIndex",
2429		readonly: "readOnly",
2430		"for": "htmlFor",
2431		"class": "className",
2432		maxlength: "maxLength",
2433		cellspacing: "cellSpacing",
2434		cellpadding: "cellPadding",
2435		rowspan: "rowSpan",
2436		colspan: "colSpan",
2437		usemap: "useMap",
2438		frameborder: "frameBorder",
2439		contenteditable: "contentEditable"
2440	},
2441
2442	prop: function( elem, name, value ) {
2443		var ret, hooks, notxml,
2444			nType = elem.nodeType;
2445
2446		// don't get/set properties on text, comment and attribute nodes
2447		if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
2448			return;
2449		}
2450
2451		notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
2452
2453		if ( notxml ) {
2454			// Fix name and attach hooks
2455			name = jQuery.propFix[ name ] || name;
2456			hooks = jQuery.propHooks[ name ];
2457		}
2458
2459		if ( value !== undefined ) {
2460			if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
2461				return ret;
2462
2463			} else {
2464				return ( elem[ name ] = value );
2465			}
2466
2467		} else {
2468			if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
2469				return ret;
2470
2471			} else {
2472				return elem[ name ];
2473			}
2474		}
2475	},
2476
2477	propHooks: {
2478		tabIndex: {
2479			get: function( elem ) {
2480				// elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
2481				// http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
2482				var attributeNode = elem.getAttributeNode("tabindex");
2483
2484				return attributeNode && attributeNode.specified ?
2485					parseInt( attributeNode.value, 10 ) :
2486					rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
2487						0 :
2488						undefined;
2489			}
2490		}
2491	}
2492});
2493
2494// Hook for boolean attributes
2495boolHook = {
2496	get: function( elem, name ) {
2497		var
2498			// Use .prop to determine if this attribute is understood as boolean
2499			prop = jQuery.prop( elem, name ),
2500
2501			// Fetch it accordingly
2502			attr = typeof prop === "boolean" && elem.getAttribute( name ),
2503			detail = typeof prop === "boolean" ?
2504
2505				getSetInput && getSetAttribute ?
2506					attr != null :
2507					// oldIE fabricates an empty string for missing boolean attributes
2508					// and conflates checked/selected into attroperties
2509					ruseDefault.test( name ) ?
2510						elem[ jQuery.camelCase( "default-" + name ) ] :
2511						!!attr :
2512
2513				// fetch an attribute node for properties not recognized as boolean
2514				elem.getAttributeNode( name );
2515
2516		return detail && detail.value !== false ?
2517			name.toLowerCase() :
2518			undefined;
2519	},
2520	set: function( elem, value, name ) {
2521		if ( value === false ) {
2522			// Remove boolean attributes when set to false
2523			jQuery.removeAttr( elem, name );
2524		} else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
2525			// IE<8 needs the *property* name
2526			elem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name );
2527
2528		// Use defaultChecked and defaultSelected for oldIE
2529		} else {
2530			elem[ jQuery.camelCase( "default-" + name ) ] = elem[ name ] = true;
2531		}
2532
2533		return name;
2534	}
2535};
2536
2537// fix oldIE value attroperty
2538if ( !getSetInput || !getSetAttribute ) {
2539	jQuery.attrHooks.value = {
2540		get: function( elem, name ) {
2541			var ret = elem.getAttributeNode( name );
2542			return jQuery.nodeName( elem, "input" ) ?
2543
2544				// Ignore the value *property* by using defaultValue
2545				elem.defaultValue :
2546
2547				ret && ret.specified ? ret.value : undefined;
2548		},
2549		set: function( elem, value, name ) {
2550			if ( jQuery.nodeName( elem, "input" ) ) {
2551				// Does not return so that setAttribute is also used
2552				elem.defaultValue = value;
2553			} else {
2554				// Use nodeHook if defined (#1954); otherwise setAttribute is fine
2555				return nodeHook && nodeHook.set( elem, value, name );
2556			}
2557		}
2558	};
2559}
2560
2561// IE6/7 do not support getting/setting some attributes with get/setAttribute
2562if ( !getSetAttribute ) {
2563
2564	// Use this for any attribute in IE6/7
2565	// This fixes almost every IE6/7 issue
2566	nodeHook = jQuery.valHooks.button = {
2567		get: function( elem, name ) {
2568			var ret = elem.getAttributeNode( name );
2569			return ret && ( name === "id" || name === "name" || name === "coords" ? ret.value !== "" : ret.specified ) ?
2570				ret.value :
2571				undefined;
2572		},
2573		set: function( elem, value, name ) {
2574			// Set the existing or create a new attribute node
2575			var ret = elem.getAttributeNode( name );
2576			if ( !ret ) {
2577				elem.setAttributeNode(
2578					(ret = elem.ownerDocument.createAttribute( name ))
2579				);
2580			}
2581
2582			ret.value = value += "";
2583
2584			// Break association with cloned elements by also using setAttribute (#9646)
2585			return name === "value" || value === elem.getAttribute( name ) ?
2586				value :
2587				undefined;
2588		}
2589	};
2590
2591	// Set contenteditable to false on removals(#10429)
2592	// Setting to empty string throws an error as an invalid value
2593	jQuery.attrHooks.contenteditable = {
2594		get: nodeHook.get,
2595		set: function( elem, value, name ) {
2596			nodeHook.set( elem, value === "" ? false : value, name );
2597		}
2598	};
2599
2600	// Set width and height to auto instead of 0 on empty string( Bug #8150 )
2601	// This is for removals
2602	jQuery.each([ "width", "height" ], function( i, name ) {
2603		jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
2604			set: function( elem, value ) {
2605				if ( value === "" ) {
2606					elem.setAttribute( name, "auto" );
2607					return value;
2608				}
2609			}
2610		});
2611	});
2612}
2613
2614
2615// Some attributes require a special call on IE
2616// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
2617if ( !jQuery.support.hrefNormalized ) {
2618	jQuery.each([ "href", "src", "width", "height" ], function( i, name ) {
2619		jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
2620			get: function( elem ) {
2621				var ret = elem.getAttribute( name, 2 );
2622				return ret == null ? undefined : ret;
2623			}
2624		});
2625	});
2626
2627	// href/src property should get the full normalized URL (#10299/#12915)
2628	jQuery.each([ "href", "src" ], function( i, name ) {
2629		jQuery.propHooks[ name ] = {
2630			get: function( elem ) {
2631				return elem.getAttribute( name, 4 );
2632			}
2633		};
2634	});
2635}
2636
2637if ( !jQuery.support.style ) {
2638	jQuery.attrHooks.style = {
2639		get: function( elem ) {
2640			// Return undefined in the case of empty string
2641			// Note: IE uppercases css property names, but if we were to .toLowerCase()
2642			// .cssText, that would destroy case senstitivity in URL's, like in "background"
2643			return elem.style.cssText || undefined;
2644		},
2645		set: function( elem, value ) {
2646			return ( elem.style.cssText = value + "" );
2647		}
2648	};
2649}
2650
2651// Safari mis-reports the default selected property of an option
2652// Accessing the parent's selectedIndex property fixes it
2653if ( !jQuery.support.optSelected ) {
2654	jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, {
2655		get: function( elem ) {
2656			var parent = elem.parentNode;
2657
2658			if ( parent ) {
2659				parent.selectedIndex;
2660
2661				// Make sure that it also works with optgroups, see #5701
2662				if ( parent.parentNode ) {
2663					parent.parentNode.selectedIndex;
2664				}
2665			}
2666			return null;
2667		}
2668	});
2669}
2670
2671// IE6/7 call enctype encoding
2672if ( !jQuery.support.enctype ) {
2673	jQuery.propFix.enctype = "encoding";
2674}
2675
2676// Radios and checkboxes getter/setter
2677if ( !jQuery.support.checkOn ) {
2678	jQuery.each([ "radio", "checkbox" ], function() {
2679		jQuery.valHooks[ this ] = {
2680			get: function( elem ) {
2681				// Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
2682				return elem.getAttribute("value") === null ? "on" : elem.value;
2683			}
2684		};
2685	});
2686}
2687jQuery.each([ "radio", "checkbox" ], function() {
2688	jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], {
2689		set: function( elem, value ) {
2690			if ( jQuery.isArray( value ) ) {
2691				return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
2692			}
2693		}
2694	});
2695});
2696var rformElems = /^(?:input|select|textarea)$/i,
2697	rkeyEvent = /^key/,
2698	rmouseEvent = /^(?:mouse|contextmenu)|click/,
2699	rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
2700	rtypenamespace = /^([^.]*)(?:\.(.+)|)$/;
2701
2702function returnTrue() {
2703	return true;
2704}
2705
2706function returnFalse() {
2707	return false;
2708}
2709
2710/*
2711 * Helper functions for managing events -- not part of the public interface.
2712 * Props to Dean Edwards' addEvent library for many of the ideas.
2713 */
2714jQuery.event = {
2715
2716	global: {},
2717
2718	add: function( elem, types, handler, data, selector ) {
2719		var tmp, events, t, handleObjIn,
2720			special, eventHandle, handleObj,
2721			handlers, type, namespaces, origType,
2722			elemData = jQuery._data( elem );
2723
2724		// Don't attach events to noData or text/comment nodes (but allow plain objects)
2725		if ( !elemData ) {
2726			return;
2727		}
2728
2729		// Caller can pass in an object of custom data in lieu of the handler
2730		if ( handler.handler ) {
2731			handleObjIn = handler;
2732			handler = handleObjIn.handler;
2733			selector = handleObjIn.selector;
2734		}
2735
2736		// Make sure that the handler has a unique ID, used to find/remove it later
2737		if ( !handler.guid ) {
2738			handler.guid = jQuery.guid++;
2739		}
2740
2741		// Init the element's event structure and main handler, if this is the first
2742		if ( !(events = elemData.events) ) {
2743			events = elemData.events = {};
2744		}
2745		if ( !(eventHandle = elemData.handle) ) {
2746			eventHandle = elemData.handle = function( e ) {
2747				// Discard the second event of a jQuery.event.trigger() and
2748				// when an event is called after a page has unloaded
2749				return typeof jQuery !== core_strundefined && (!e || jQuery.event.triggered !== e.type) ?
2750					jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
2751					undefined;
2752			};
2753			// Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
2754			eventHandle.elem = elem;
2755		}
2756
2757		// Handle multiple events separated by a space
2758		// jQuery(...).bind("mouseover mouseout", fn);
2759		types = ( types || "" ).match( core_rnotwhite ) || [""];
2760		t = types.length;
2761		while ( t-- ) {
2762			tmp = rtypenamespace.exec( types[t] ) || [];
2763			type = origType = tmp[1];
2764			namespaces = ( tmp[2] || "" ).split( "." ).sort();
2765
2766			// If event changes its type, use the special event handlers for the changed type
2767			special = jQuery.event.special[ type ] || {};
2768
2769			// If selector defined, determine special event api type, otherwise given type
2770			type = ( selector ? special.delegateType : special.bindType ) || type;
2771
2772			// Update special based on newly reset type
2773			special = jQuery.event.special[ type ] || {};
2774
2775			// handleObj is passed to all event handlers
2776			handleObj = jQuery.extend({
2777				type: type,
2778				origType: origType,
2779				data: data,
2780				handler: handler,
2781				guid: handler.guid,
2782				selector: selector,
2783				needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
2784				namespace: namespaces.join(".")
2785			}, handleObjIn );
2786
2787			// Init the event handler queue if we're the first
2788			if ( !(handlers = events[ type ]) ) {
2789				handlers = events[ type ] = [];
2790				handlers.delegateCount = 0;
2791
2792				// Only use addEventListener/attachEvent if the special events handler returns false
2793				if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
2794					// Bind the global event handler to the element
2795					if ( elem.addEventListener ) {
2796						elem.addEventListener( type, eventHandle, false );
2797
2798					} else if ( elem.attachEvent ) {
2799						elem.attachEvent( "on" + type, eventHandle );
2800					}
2801				}
2802			}
2803
2804			if ( special.add ) {
2805				special.add.call( elem, handleObj );
2806
2807				if ( !handleObj.handler.guid ) {
2808					handleObj.handler.guid = handler.guid;
2809				}
2810			}
2811
2812			// Add to the element's handler list, delegates in front
2813			if ( selector ) {
2814				handlers.splice( handlers.delegateCount++, 0, handleObj );
2815			} else {
2816				handlers.push( handleObj );
2817			}
2818
2819			// Keep track of which events have ever been used, for event optimization
2820			jQuery.event.global[ type ] = true;
2821		}
2822
2823		// Nullify elem to prevent memory leaks in IE
2824		elem = null;
2825	},
2826
2827	// Detach an event or set of events from an element
2828	remove: function( elem, types, handler, selector, mappedTypes ) {
2829		var j, handleObj, tmp,
2830			origCount, t, events,
2831			special, handlers, type,
2832			namespaces, origType,
2833			elemData = jQuery.hasData( elem ) && jQuery._data( elem );
2834
2835		if ( !elemData || !(events = elemData.events) ) {
2836			return;
2837		}
2838
vendor: 8,375 bytes, lines 2839-3101
2839		// Once for each type.namespace in types; type may be omitted
2840		types = ( types || "" ).match( core_rnotwhite ) || [""];
2841		t = types.length;
2842		while ( t-- ) {
2843			tmp = rtypenamespace.exec( types[t] ) || [];
2844			type = origType = tmp[1];
2845			namespaces = ( tmp[2] || "" ).split( "." ).sort();
2846
2847			// Unbind all events (on this namespace, if provided) for the element
2848			if ( !type ) {
2849				for ( type in events ) {
2850					jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
2851				}
2852				continue;
2853			}
2854
2855			special = jQuery.event.special[ type ] || {};
2856			type = ( selector ? special.delegateType : special.bindType ) || type;
2857			handlers = events[ type ] || [];
2858			tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" );
2859
2860			// Remove matching events
2861			origCount = j = handlers.length;
2862			while ( j-- ) {
2863				handleObj = handlers[ j ];
2864
2865				if ( ( mappedTypes || origType === handleObj.origType ) &&
2866					( !handler || handler.guid === handleObj.guid ) &&
2867					( !tmp || tmp.test( handleObj.namespace ) ) &&
2868					( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
2869					handlers.splice( j, 1 );
2870
2871					if ( handleObj.selector ) {
2872						handlers.delegateCount--;
2873					}
2874					if ( special.remove ) {
2875						special.remove.call( elem, handleObj );
2876					}
2877				}
2878			}
2879
2880			// Remove generic event handler if we removed something and no more handlers exist
2881			// (avoids potential for endless recursion during removal of special event handlers)
2882			if ( origCount && !handlers.length ) {
2883				if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
2884					jQuery.removeEvent( elem, type, elemData.handle );
2885				}
2886
2887				delete events[ type ];
2888			}
2889		}
2890
2891		// Remove the expando if it's no longer used
2892		if ( jQuery.isEmptyObject( events ) ) {
2893			delete elemData.handle;
2894
2895			// removeData also checks for emptiness and clears the expando if empty
2896			// so use it instead of delete
2897			jQuery._removeData( elem, "events" );
2898		}
2899	},
2900
2901	trigger: function( event, data, elem, onlyHandlers ) {
2902		var handle, ontype, cur,
2903			bubbleType, special, tmp, i,
2904			eventPath = [ elem || document ],
2905			type = core_hasOwn.call( event, "type" ) ? event.type : event,
2906			namespaces = core_hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : [];
2907
2908		cur = tmp = elem = elem || document;
2909
2910		// Don't do events on text and comment nodes
2911		if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
2912			return;
2913		}
2914
2915		// focus/blur morphs to focusin/out; ensure we're not firing them right now
2916		if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
2917			return;
2918		}
2919
2920		if ( type.indexOf(".") >= 0 ) {
2921			// Namespaced trigger; create a regexp to match event type in handle()
2922			namespaces = type.split(".");
2923			type = namespaces.shift();
2924			namespaces.sort();
2925		}
2926		ontype = type.indexOf(":") < 0 && "on" + type;
2927
2928		// Caller can pass in a jQuery.Event object, Object, or just an event type string
2929		event = event[ jQuery.expando ] ?
2930			event :
2931			new jQuery.Event( type, typeof event === "object" && event );
2932
2933		event.isTrigger = true;
2934		event.namespace = namespaces.join(".");
2935		event.namespace_re = event.namespace ?
2936			new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) :
2937			null;
2938
2939		// Clean up the event in case it is being reused
2940		event.result = undefined;
2941		if ( !event.target ) {
2942			event.target = elem;
2943		}
2944
2945		// Clone any incoming data and prepend the event, creating the handler arg list
2946		data = data == null ?
2947			[ event ] :
2948			jQuery.makeArray( data, [ event ] );
2949
2950		// Allow special events to draw outside the lines
2951		special = jQuery.event.special[ type ] || {};
2952		if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
2953			return;
2954		}
2955
2956		// Determine event propagation path in advance, per W3C events spec (#9951)
2957		// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
2958		if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
2959
2960			bubbleType = special.delegateType || type;
2961			if ( !rfocusMorph.test( bubbleType + type ) ) {
2962				cur = cur.parentNode;
2963			}
2964			for ( ; cur; cur = cur.parentNode ) {
2965				eventPath.push( cur );
2966				tmp = cur;
2967			}
2968
2969			// Only add window if we got to document (e.g., not plain obj or detached DOM)
2970			if ( tmp === (elem.ownerDocument || document) ) {
2971				eventPath.push( tmp.defaultView || tmp.parentWindow || window );
2972			}
2973		}
2974
2975		// Fire handlers on the event path
2976		i = 0;
2977		while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {
2978
2979			event.type = i > 1 ?
2980				bubbleType :
2981				special.bindType || type;
2982
2983			// jQuery handler
2984			handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
2985			if ( handle ) {
2986				handle.apply( cur, data );
2987			}
2988
2989			// Native handler
2990			handle = ontype && cur[ ontype ];
2991			if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) {
2992				event.preventDefault();
2993			}
2994		}
2995		event.type = type;
2996
2997		// If nobody prevented the default action, do it now
2998		if ( !onlyHandlers && !event.isDefaultPrevented() ) {
2999
3000			if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) &&
3001				!(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) {
3002
3003				// Call a native DOM method on the target with the same name name as the event.
3004				// Can't use an .isFunction() check here because IE6/7 fails that test.
3005				// Don't do default actions on window, that's where global variables be (#6170)
3006				if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) {
3007
3008					// Don't re-trigger an onFOO event when we call its FOO() method
3009					tmp = elem[ ontype ];
3010
3011					if ( tmp ) {
3012						elem[ ontype ] = null;
3013					}
3014
3015					// Prevent re-triggering of the same event, since we already bubbled it above
3016					jQuery.event.triggered = type;
3017					try {
3018						elem[ type ]();
3019					} catch ( e ) {
3020						// IE<9 dies on focus/blur to hidden element (#1486,#12518)
3021						// only reproducible on winXP IE8 native, not IE9 in IE8 mode
3022					}
3023					jQuery.event.triggered = undefined;
3024
3025					if ( tmp ) {
3026						elem[ ontype ] = tmp;
3027					}
3028				}
3029			}
3030		}
3031
3032		return event.result;
3033	},
3034
3035	dispatch: function( event ) {
3036
3037		// Make a writable jQuery.Event from the native event object
3038		event = jQuery.event.fix( event );
3039
3040		var i, ret, handleObj, matched, j,
3041			handlerQueue = [],
3042			args = core_slice.call( arguments ),
3043			handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [],
3044			special = jQuery.event.special[ event.type ] || {};
3045
3046		// Use the fix-ed jQuery.Event rather than the (read-only) native event
3047		args[0] = event;
3048		event.delegateTarget = this;
3049
3050		// Call the preDispatch hook for the mapped type, and let it bail if desired
3051		if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
3052			return;
3053		}
3054
3055		// Determine handlers
3056		handlerQueue = jQuery.event.handlers.call( this, event, handlers );
3057
3058		// Run delegates first; they may want to stop propagation beneath us
3059		i = 0;
3060		while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {
3061			event.currentTarget = matched.elem;
3062
3063			j = 0;
3064			while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {
3065
3066				// Triggered event must either 1) have no namespace, or
3067				// 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
3068				if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {
3069
3070					event.handleObj = handleObj;
3071					event.data = handleObj.data;
3072
3073					ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
3074							.apply( matched.elem, args );
3075
3076					if ( ret !== undefined ) {
3077						if ( (event.result = ret) === false ) {
3078							event.preventDefault();
3079							event.stopPropagation();
3080						}
3081					}
3082				}
3083			}
3084		}
3085
3086		// Call the postDispatch hook for the mapped type
3087		if ( special.postDispatch ) {
3088			special.postDispatch.call( this, event );
3089		}
3090
3091		return event.result;
3092	},
3093
3094	handlers: function( event, handlers ) {
3095		var sel, handleObj, matches, i,
3096			handlerQueue = [],
3097			delegateCount = handlers.delegateCount,
3098			cur = event.target;
3099
3100		// Find delegate handlers
3101		// Black-hole SVG <use> instance trees (#13180)
3102		// Avoid non-left-click bubbling in Firefox (#3861)
3103		if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) {
3104
3105			for ( ; cur != this; cur = cur.parentNode || this ) {
3106
3107				// Don't check non-elements (#13208)
3108				// Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
3109				if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) {
3110					matches = [];
3111					for ( i = 0; i < delegateCount; i++ ) {
3112						handleObj = handlers[ i ];
3113
3114						// Don't conflict with Object.prototype properties (#13203)
3115						sel = handleObj.selector + " ";
3116
3117						if ( matches[ sel ] === undefined ) {
3118							matches[ sel ] = handleObj.needsContext ?
3119								jQuery( sel, this ).index( cur ) >= 0 :
3120								jQuery.find( sel, this, null, [ cur ] ).length;
3121						}
3122						if ( matches[ sel ] ) {
3123							matches.push( handleObj );
3124						}
3125					}
3126					if ( matches.length ) {
3127						handlerQueue.push({ elem: cur, handlers: matches });
3128					}
3129				}
3130			}
3131		}
3132
3133		// Add the remaining (directly-bound) handlers
3134		if ( delegateCount < handlers.length ) {
3135			handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });
3136		}
3137
3138		return handlerQueue;
3139	},
3140
3141	fix: function( event ) {
3142		if ( event[ jQuery.expando ] ) {
3143			return event;
3144		}
3145
3146		// Create a writable copy of the event object and normalize some properties
3147		var i, prop, copy,
3148			type = event.type,
3149			originalEvent = event,
3150			fixHook = this.fixHooks[ type ];
3151
3152		if ( !fixHook ) {
3153			this.fixHooks[ type ] = fixHook =
3154				rmouseEvent.test( type ) ? this.mouseHooks :
3155				rkeyEvent.test( type ) ? this.keyHooks :
3156				{};
3157		}
3158		copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
3159
3160		event = new jQuery.Event( originalEvent );
3161
3162		i = copy.length;
3163		while ( i-- ) {
3164			prop = copy[ i ];
3165			event[ prop ] = originalEvent[ prop ];
3166		}
3167
3168		// Support: IE<9
3169		// Fix target property (#1925)
3170		if ( !event.target ) {
3171			event.target = originalEvent.srcElement || document;
3172		}
3173
3174		// Support: Chrome 23+, Safari?
3175		// Target should not be a text node (#504, #13143)
3176		if ( event.target.nodeType === 3 ) {
3177			event.target = event.target.parentNode;
3178		}
3179
3180		// Support: IE<9
3181		// For mouse/key events, metaKey==false if it's undefined (#3368, #11328)
3182		event.metaKey = !!event.metaKey;
3183
3184		return fixHook.filter ? fixHook.filter( event, originalEvent ) : event;
3185	},
3186
3187	// Includes some event props shared by KeyEvent and MouseEvent
3188	props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
3189
3190	fixHooks: {},
3191
3192	keyHooks: {
3193		props: "char charCode key keyCode".split(" "),
3194		filter: function( event, original ) {
3195
3196			// Add which for key events
3197			if ( event.which == null ) {
3198				event.which = original.charCode != null ? original.charCode : original.keyCode;
3199			}
3200
3201			return event;
3202		}
3203	},
3204
3205	mouseHooks: {
3206		props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
3207		filter: function( event, original ) {
3208			var body, eventDoc, doc,
3209				button = original.button,
3210				fromElement = original.fromElement;
3211
3212			// Calculate pageX/Y if missing and clientX/Y available
3213			if ( event.pageX == null && original.clientX != null ) {
3214				eventDoc = event.target.ownerDocument || document;
3215				doc = eventDoc.documentElement;
3216				body = eventDoc.body;
3217
3218				event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
3219				event.pageY = original.clientY + ( doc && doc.scrollTop  || body && body.scrollTop  || 0 ) - ( doc && doc.clientTop  || body && body.clientTop  || 0 );
3220			}
3221
3222			// Add relatedTarget, if necessary
3223			if ( !event.relatedTarget && fromElement ) {
3224				event.relatedTarget = fromElement === event.target ? original.toElement : fromElement;
3225			}
3226
3227			// Add which for click: 1 === left; 2 === middle; 3 === right
3228			// Note: button is not normalized, so don't use it
3229			if ( !event.which && button !== undefined ) {
3230				event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
3231			}
3232
3233			return event;
3234		}
3235	},
3236
3237	special: {
3238		load: {
3239			// Prevent triggered image.load events from bubbling to window.load
3240			noBubble: true
3241		},
3242		click: {
3243			// For checkbox, fire native event so checked state will be right
3244			trigger: function() {
3245				if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) {
3246					this.click();
3247					return false;
3248				}
3249			}
3250		},
3251		focus: {
3252			// Fire native event if possible so blur/focus sequence is correct
3253			trigger: function() {
3254				if ( this !== document.activeElement && this.focus ) {
3255					try {
3256						this.focus();
3257						return false;
3258					} catch ( e ) {
3259						// Support: IE<9
3260						// If we error on focus to hidden element (#1486, #12518),
3261						// let .trigger() run the handlers
3262					}
3263				}
3264			},
3265			delegateType: "focusin"
3266		},
3267		blur: {
3268			trigger: function() {
3269				if ( this === document.activeElement && this.blur ) {
3270					this.blur();
3271					return false;
3272				}
3273			},
3274			delegateType: "focusout"
3275		},
3276
3277		beforeunload: {
3278			postDispatch: function( event ) {
3279
3280				// Even when returnValue equals to undefined Firefox will still show alert
3281				if ( event.result !== undefined ) {
3282					event.originalEvent.returnValue = event.result;
3283				}
3284			}
3285		}
3286	},
3287
3288	simulate: function( type, elem, event, bubble ) {
3289		// Piggyback on a donor event to simulate a different one.
3290		// Fake originalEvent to avoid donor's stopPropagation, but if the
3291		// simulated event prevents default then we do the same on the donor.
3292		var e = jQuery.extend(
3293			new jQuery.Event(),
3294			event,
3295			{ type: type,
3296				isSimulated: true,
3297				originalEvent: {}
3298			}
3299		);
3300		if ( bubble ) {
3301			jQuery.event.trigger( e, null, elem );
3302		} else {
3303			jQuery.event.dispatch.call( elem, e );
3304		}
3305		if ( e.isDefaultPrevented() ) {
3306			event.preventDefault();
3307		}
3308	}
3309};
3310
3311jQuery.removeEvent = document.removeEventListener ?
3312	function( elem, type, handle ) {
3313		if ( elem.removeEventListener ) {
3314			elem.removeEventListener( type, handle, false );
3315		}
3316	} :
3317	function( elem, type, handle ) {
3318		var name = "on" + type;
3319
3320		if ( elem.detachEvent ) {
3321
3322			// #8545, #7054, preventing memory leaks for custom events in IE6-8
3323			// detachEvent needed property on element, by name of that event, to properly expose it to GC
3324			if ( typeof elem[ name ] === core_strundefined ) {
3325				elem[ name ] = null;
3326			}
3327
3328			elem.detachEvent( name, handle );
3329		}
3330	};
3331
3332jQuery.Event = function( src, props ) {
3333	// Allow instantiation without the 'new' keyword
3334	if ( !(this instanceof jQuery.Event) ) {
3335		return new jQuery.Event( src, props );
3336	}
3337
3338	// Event object
3339	if ( src && src.type ) {
3340		this.originalEvent = src;
3341		this.type = src.type;
3342
3343		// Events bubbling up the document may have been marked as prevented
3344		// by a handler lower down the tree; reflect the correct value.
3345		this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false ||
3346			src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse;
3347
3348	// Event type
3349	} else {
3350		this.type = src;
3351	}
3352
3353	// Put explicitly provided properties onto the event object
3354	if ( props ) {
3355		jQuery.extend( this, props );
3356	}
3357
3358	// Create a timestamp if incoming event doesn't have one
3359	this.timeStamp = src && src.timeStamp || jQuery.now();
3360
3361	// Mark it as fixed
3362	this[ jQuery.expando ] = true;
3363};
3364
3365// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
3366// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
3367jQuery.Event.prototype = {
3368	isDefaultPrevented: returnFalse,
3369	isPropagationStopped: returnFalse,
3370	isImmediatePropagationStopped: returnFalse,
3371
3372	preventDefault: function() {
3373		var e = this.originalEvent;
3374
3375		this.isDefaultPrevented = returnTrue;
3376		if ( !e ) {
3377			return;
3378		}
3379
3380		// If preventDefault exists, run it on the original event
3381		if ( e.preventDefault ) {
3382			e.preventDefault();
3383
3384		// Support: IE
3385		// Otherwise set the returnValue property of the original event to false
3386		} else {
3387			e.returnValue = false;
3388		}
3389	},
3390	stopPropagation: function() {
3391		var e = this.originalEvent;
3392
3393		this.isPropagationStopped = returnTrue;
3394		if ( !e ) {
3395			return;
3396		}
3397		// If stopPropagation exists, run it on the original event
3398		if ( e.stopPropagation ) {
3399			e.stopPropagation();
3400		}
3401
3402		// Support: IE
3403		// Set the cancelBubble property of the original event to true
3404		e.cancelBubble = true;
3405	},
3406	stopImmediatePropagation: function() {
3407		this.isImmediatePropagationStopped = returnTrue;
3408		this.stopPropagation();
3409	}
3410};
3411
3412// Create mouseenter/leave events using mouseover/out and event-time checks
3413jQuery.each({
3414	mouseenter: "mouseover",
3415	mouseleave: "mouseout"
3416}, function( orig, fix ) {
3417	jQuery.event.special[ orig ] = {
3418		delegateType: fix,
3419		bindType: fix,
3420
3421		handle: function( event ) {
3422			var ret,
3423				target = this,
3424				related = event.relatedTarget,
3425				handleObj = event.handleObj;
3426
3427			// For mousenter/leave call the handler if related is outside the target.
3428			// NB: No relatedTarget if the mouse left/entered the browser window
3429			if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
3430				event.type = handleObj.origType;
3431				ret = handleObj.handler.apply( this, arguments );
3432				event.type = fix;
3433			}
3434			return ret;
3435		}
3436	};
3437});
3438
3439// IE submit delegation
3440if ( !jQuery.support.submitBubbles ) {
3441
3442	jQuery.event.special.submit = {
3443		setup: function() {
3444			// Only need this for delegated form submit events
3445			if ( jQuery.nodeName( this, "form" ) ) {
3446				return false;
3447			}
3448
3449			// Lazy-add a submit handler when a descendant form may potentially be submitted
3450			jQuery.event.add( this, "click._submit keypress._submit", function( e ) {
3451				// Node name check avoids a VML-related crash in IE (#9807)
3452				var elem = e.target,
3453					form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined;
3454				if ( form && !jQuery._data( form, "submitBubbles" ) ) {
3455					jQuery.event.add( form, "submit._submit", function( event ) {
3456						event._submit_bubble = true;
3457					});
3458					jQuery._data( form, "submitBubbles", true );
3459				}
3460			});
3461			// return undefined since we don't need an event listener
3462		},
3463
3464		postDispatch: function( event ) {
3465			// If form was submitted by the user, bubble the event up the tree
3466			if ( event._submit_bubble ) {
3467				delete event._submit_bubble;
3468				if ( this.parentNode && !event.isTrigger ) {
3469					jQuery.event.simulate( "submit", this.parentNode, event, true );
3470				}
3471			}
3472		},
3473
3474		teardown: function() {
3475			// Only need this for delegated form submit events
3476			if ( jQuery.nodeName( this, "form" ) ) {
3477				return false;
3478			}
3479
3480			// Remove delegated handlers; cleanData eventually reaps submit handlers attached above
3481			jQuery.event.remove( this, "._submit" );
3482		}
3483	};
3484}
3485
3486// IE change delegation and checkbox/radio fix
3487if ( !jQuery.support.changeBubbles ) {
3488
3489	jQuery.event.special.change = {
3490
3491		setup: function() {
3492
3493			if ( rformElems.test( this.nodeName ) ) {
3494				// IE doesn't fire change on a check/radio until blur; trigger it on click
3495				// after a propertychange. Eat the blur-change in special.change.handle.
3496				// This still fires onchange a second time for check/radio after blur.
3497				if ( this.type === "checkbox" || this.type === "radio" ) {
3498					jQuery.event.add( this, "propertychange._change", function( event ) {
3499						if ( event.originalEvent.propertyName === "checked" ) {
3500							this._just_changed = true;
3501						}
3502					});
3503					jQuery.event.add( this, "click._change", function( event ) {
3504						if ( this._just_changed && !event.isTrigger ) {
3505							this._just_changed = false;
3506						}
3507						// Allow triggered, simulated change events (#11500)
3508						jQuery.event.simulate( "change", this, event, true );
3509					});
3510				}
3511				return false;
3512			}
3513			// Delegated event; lazy-add a change handler on descendant inputs
3514			jQuery.event.add( this, "beforeactivate._change", function( e ) {
3515				var elem = e.target;
3516
3517				if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "changeBubbles" ) ) {
3518					jQuery.event.add( elem, "change._change", function( event ) {
3519						if ( this.parentNode && !event.isSimulated && !event.isTrigger ) {
3520							jQuery.event.simulate( "change", this.parentNode, event, true );
3521						}
3522					});
3523					jQuery._data( elem, "changeBubbles", true );
3524				}
3525			});
3526		},
3527
3528		handle: function( event ) {
3529			var elem = event.target;
3530
3531			// Swallow native change events from checkbox/radio, we already triggered them above
3532			if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) {
3533				return event.handleObj.handler.apply( this, arguments );
3534			}
3535		},
3536
3537		teardown: function() {
3538			jQuery.event.remove( this, "._change" );
3539
3540			return !rformElems.test( this.nodeName );
3541		}
3542	};
3543}
3544
3545// Create "bubbling" focus and blur events
3546if ( !jQuery.support.focusinBubbles ) {
3547	jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
3548
3549		// Attach a single capturing handler while someone wants focusin/focusout
3550		var attaches = 0,
3551			handler = function( event ) {
3552				jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
3553			};
3554
3555		jQuery.event.special[ fix ] = {
3556			setup: function() {
3557				if ( attaches++ === 0 ) {
3558					document.addEventListener( orig, handler, true );
3559				}
3560			},
3561			teardown: function() {
3562				if ( --attaches === 0 ) {
3563					document.removeEventListener( orig, handler, true );
3564				}
3565			}
3566		};
3567	});
3568}
3569
3570jQuery.fn.extend({
3571
3572	on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
3573		var type, origFn;
3574
3575		// Types can be a map of types/handlers
3576		if ( typeof types === "object" ) {
3577			// ( types-Object, selector, data )
3578			if ( typeof selector !== "string" ) {
3579				// ( types-Object, data )
3580				data = data || selector;
3581				selector = undefined;
3582			}
3583			for ( type in types ) {
3584				this.on( type, selector, data, types[ type ], one );
3585			}
3586			return this;
3587		}
3588
3589		if ( data == null && fn == null ) {
3590			// ( types, fn )
3591			fn = selector;
3592			data = selector = undefined;
3593		} else if ( fn == null ) {
3594			if ( typeof selector === "string" ) {
3595				// ( types, selector, fn )
3596				fn = data;
3597				data = undefined;
3598			} else {
3599				// ( types, data, fn )
3600				fn = data;
3601				data = selector;
3602				selector = undefined;
3603			}
3604		}
3605		if ( fn === false ) {
3606			fn = returnFalse;
3607		} else if ( !fn ) {
3608			return this;
3609		}
3610
3611		if ( one === 1 ) {
3612			origFn = fn;
3613			fn = function( event ) {
3614				// Can use an empty set, since event contains the info
3615				jQuery().off( event );
3616				return origFn.apply( this, arguments );
3617			};
3618			// Use same guid so caller can remove using origFn
3619			fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
3620		}
3621		return this.each( function() {
3622			jQuery.event.add( this, types, fn, data, selector );
3623		});
3624	},
3625	one: function( types, selector, data, fn ) {
3626		return this.on( types, selector, data, fn, 1 );
3627	},
3628	off: function( types, selector, fn ) {
3629		var handleObj, type;
3630		if ( types && types.preventDefault && types.handleObj ) {
3631			// ( event )  dispatched jQuery.Event
3632			handleObj = types.handleObj;
3633			jQuery( types.delegateTarget ).off(
3634				handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
3635				handleObj.selector,
3636				handleObj.handler
3637			);
3638			return this;
3639		}
3640		if ( typeof types === "object" ) {
3641			// ( types-object [, selector] )
3642			for ( type in types ) {
3643				this.off( type, selector, types[ type ] );
3644			}
3645			return this;
3646		}
3647		if ( selector === false || typeof selector === "function" ) {
3648			// ( types [, fn] )
3649			fn = selector;
3650			selector = undefined;
3651		}
3652		if ( fn === false ) {
3653			fn = returnFalse;
3654		}
3655		return this.each(function() {
3656			jQuery.event.remove( this, types, fn, selector );
3657		});
3658	},
3659
3660	bind: function( types, data, fn ) {
3661		return this.on( types, null, data, fn );
3662	},
3663	unbind: function( types, fn ) {
3664		return this.off( types, null, fn );
3665	},
3666
3667	delegate: function( selector, types, data, fn ) {
3668		return this.on( types, selector, data, fn );
3669	},
3670	undelegate: function( selector, types, fn ) {
3671		// ( namespace ) or ( selector, types [, fn] )
3672		return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
3673	},
3674
3675	trigger: function( type, data ) {
3676		return this.each(function() {
3677			jQuery.event.trigger( type, data, this );
3678		});
3679	},
3680	triggerHandler: function( type, data ) {
3681		var elem = this[0];
3682		if ( elem ) {
3683			return jQuery.event.trigger( type, data, elem, true );
3684		}
3685	}
3686});
3687/*!
3688 * Sizzle CSS Selector Engine
3689 * Copyright 2012 jQuery Foundation and other contributors
3690 * Released under the MIT license
3691 * http://sizzlejs.com/
3692 */
3693(function( window, undefined ) {
3694
3695var i,
3696	cachedruns,
3697	Expr,
3698	getText,
3699	isXML,
3700	compile,
3701	hasDuplicate,
3702	outermostContext,
3703
3704	// Local document vars
3705	setDocument,
3706	document,
3707	docElem,
3708	documentIsXML,
3709	rbuggyQSA,
3710	rbuggyMatches,
3711	matches,
3712	contains,
3713	sortOrder,
3714
3715	// Instance-specific data
3716	expando = "sizzle" + -(new Date()),
3717	preferredDoc = window.document,
3718	support = {},
3719	dirruns = 0,
3720	done = 0,
3721	classCache = createCache(),
3722	tokenCache = createCache(),
3723	compilerCache = createCache(),
3724
3725	// General-purpose constants
3726	strundefined = typeof undefined,
3727	MAX_NEGATIVE = 1 << 31,
3728
3729	// Array methods
3730	arr = [],
3731	pop = arr.pop,
3732	push = arr.push,
3733	slice = arr.slice,
3734	// Use a stripped-down indexOf if we can't use a native one
3735	indexOf = arr.indexOf || function( elem ) {
3736		var i = 0,
3737			len = this.length;
3738		for ( ; i < len; i++ ) {
3739			if ( this[i] === elem ) {
3740				return i;
3741			}
3742		}
3743		return -1;
3744	},
3745
3746
3747	// Regular expressions
3748
3749	// Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
3750	whitespace = "[\\x20\\t\\r\\n\\f]",
3751	// http://www.w3.org/TR/css3-syntax/#characters
3752	characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
3753
3754	// Loosely modeled on CSS identifier characters
3755	// An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors
3756	// Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
3757	identifier = characterEncoding.replace( "w", "w#" ),
3758
3759	// Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors
3760	operators = "([*^$|!~]?=)",
3761	attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace +
3762		"*(?:" + operators + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]",
3763
3764	// Prefer arguments quoted,
3765	//   then not containing pseudos/brackets,
3766	//   then attribute selectors/non-parenthetical expressions,
3767	//   then anything else
3768	// These preferences are here to reduce the number of selectors
3769	//   needing tokenize in the PSEUDO preFilter
3770	pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace( 3, 8 ) + ")*)|.*)\\)|)",
3771
3772	// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
3773	rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
3774
3775	rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
3776	rcombinators = new RegExp( "^" + whitespace + "*([\\x20\\t\\r\\n\\f>+~])" + whitespace + "*" ),
3777	rpseudo = new RegExp( pseudos ),
3778	ridentifier = new RegExp( "^" + identifier + "$" ),
3779
3780	matchExpr = {
3781		"ID": new RegExp( "^#(" + characterEncoding + ")" ),
3782		"CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
3783		"NAME": new RegExp( "^\\[name=['\"]?(" + characterEncoding + ")['\"]?\\]" ),
3784		"TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
3785		"ATTR": new RegExp( "^" + attributes ),
3786		"PSEUDO": new RegExp( "^" + pseudos ),
3787		"CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
3788			"*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
3789			"*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
3790		// For use in libraries implementing .is()
3791		// We use this for POS matching in `select`
3792		"needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
3793			whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
3794	},
3795
3796	rsibling = /[\x20\t\r\n\f]*[+~]/,
3797
3798	rnative = /^[^{]+\{\s*\[native code/,
3799
3800	// Easily-parseable/retrievable ID or TAG or CLASS selectors
3801	rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
3802
3803	rinputs = /^(?:input|select|textarea|button)$/i,
3804	rheader = /^h\d$/i,
3805
3806	rescape = /'|\\/g,
3807	rattributeQuotes = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,
3808
3809	// CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
3810	runescape = /\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g,
3811	funescape = function( _, escaped ) {
3812		var high = "0x" + escaped - 0x10000;
3813		// NaN means non-codepoint
3814		return high !== high ?
3815			escaped :
3816			// BMP codepoint
3817			high < 0 ?
3818				String.fromCharCode( high + 0x10000 ) :
3819				// Supplemental Plane codepoint (surrogate pair)
3820				String.fromCharCode( high >>
3820 10 | 0xD800, high & 0x3FF | 0xDC00 );
3821	};
3822
3823// Use a stripped-down slice if we can't use a native one
3824try {
3825	slice.call( preferredDoc.documentElement.childNodes, 0 )[0].nodeType;
3826} catch ( e ) {
3827	slice = function( i ) {
3828		var elem,
3829			results = [];
3830		while ( (elem = this[i++]) ) {
3831			results.push( elem );
3832		}
3833		return results;
3834	};
3835}
3836
3837/**
3838 * For feature detection
3839 * @param {Function} fn The function to test for native support
3840 */
3841function isNative( fn ) {
3842	return rnative.test( fn + "" );
3843}
3844
3845/**
3846 * Create key-value caches of limited size
3847 * @returns {Function(string, Object)} Returns the Object data after storing it on itself with
3848 *	property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
3849 *	deleting the oldest entry
3850 */
3851function createCache() {
3852	var cache,
3853		keys = [];
3854
3855	return (cache = function( key, value ) {
3856		// Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
3857		if ( keys.push( key += " " ) > Expr.cacheLength ) {
3858			// Only keep the most recent entries
3859			delete cache[ keys.shift() ];
3860		}
3861		return (cache[ key ] = value);
3862	});
3863}
3864
3865/**
3866 * Mark a function for special use by Sizzle
3867 * @param {Function} fn The function to mark
3868 */
3869function markFunction( fn ) {
3870	fn[ expando ] = true;
3871	return fn;
3872}
3873
3874/**
3875 * Support testing using an element
3876 * @param {Function} fn Passed the created div and expects a boolean result
3877 */
3878function assert( fn ) {
3879	var div = document.createElement("div");
3880
3881	try {
3882		return fn( div );
3883	} catch (e) {
3884		return false;
3885	} finally {
3886		// release memory in IE
3887		div = null;
3888	}
3889}
3890
3891function Sizzle( selector, context, results, seed ) {
3892	var match, elem, m, nodeType,
3893		// QSA vars
3894		i, groups, old, nid, newContext, newSelector;
3895
3896	if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
3897		setDocument( context );
3898	}
3899
3900	context = context || document;
3901	results = results || [];
3902
3903	if ( !selector || typeof selector !== "string" ) {
3904		return results;
3905	}
3906
3907	if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
3908		return [];
3909	}
3910
3911	if ( !documentIsXML && !seed ) {
3912
3913		// Shortcuts
3914		if ( (match = rquickExpr.exec( selector )) ) {
3915			// Speed-up: Sizzle("#ID")
3916			if ( (m = match[1]) ) {
3917				if ( nodeType === 9 ) {
3918					elem = context.getElementById( m );
3919					// Check parentNode to catch when Blackberry 4.6 returns
3920					// nodes that are no longer in the document #6963
3921					if ( elem && elem.parentNode ) {
3922						// Handle the case where IE, Opera, and Webkit return items
3923						// by name instead of ID
3924						if ( elem.id === m ) {
3925							results.push( elem );
3926							return results;
3927						}
3928					} else {
3929						return results;
3930					}
3931				} else {
3932					// Context is not a document
3933					if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
3934						contains( context, elem ) && elem.id === m ) {
3935						results.push( elem );
3936						return results;
3937					}
3938				}
3939
3940			// Speed-up: Sizzle("TAG")
3941			} else if ( match[2] ) {
3942				push.apply( results, slice.call(context.getElementsByTagName( selector ), 0) );
3943				return results;
3944
3945			// Speed-up: Sizzle(".CLASS")
3946			} else if ( (m = match[3]) && support.getByClassName && context.getElementsByClassName ) {
3947				push.apply( results, slice.call(context.getElementsByClassName( m ), 0) );
3948				return results;
3949			}
3950		}
3951
3952		// QSA path
3953		if ( support.qsa && !rbuggyQSA.test(selector) ) {
3954			old = true;
3955			nid = expando;
3956			newContext = context;
3957			newSelector = nodeType === 9 && selector;
3958
3959			// qSA works strangely on Element-rooted queries
3960			// We can work around this by specifying an extra ID on the root
3961			// and working up from there (Thanks to Andrew Dupont for the technique)
3962			// IE 8 doesn't work on object elements
3963			if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
3964				groups = tokenize( selector );
3965
3966				if ( (old = context.getAttribute("id")) ) {
3967					nid = old.replace( rescape, "\\$&" );
3968				} else {
3969					context.setAttribute( "id", nid );
3970				}
3971				nid = "[id='" + nid + "'] ";
3972
3973				i = groups.length;
3974				while ( i-- ) {
3975					groups[i] = nid + toSelector( groups[i] );
3976				}
3977				newContext = rsibling.test( selector ) && context.parentNode || context;
3978				newSelector = groups.join(",");
3979			}
3980
3981			if ( newSelector ) {
3982				try {
3983					push.apply( results, slice.call( newContext.querySelectorAll(
3984						newSelector
3985					), 0 ) );
3986					return results;
3987				} catch(qsaError) {
3988				} finally {
3989					if ( !old ) {
3990						context.removeAttribute("id");
3991					}
3992				}
3993			}
3994		}
3995	}
3996
3997	// All others
3998	return select( selector.replace( rtrim, "$1" ), context, results, seed );
3999}
4000
4001/**
4002 * Detect xml
4003 * @param {Element|Object} elem An element or a document
4004 */
4005isXML = Sizzle.isXML = function( elem ) {
4006	// documentElement is verified for cases where it doesn't yet exist
4007	// (such as loading iframes in IE - #4833)
4008	var documentElement = elem && (elem.ownerDocument || elem).documentElement;
4009	return documentElement ? documentElement.nodeName !== "HTML" : false;
4010};
4011
4012/**
4013 * Sets document-related variables once based on the current document
4014 * @param {Element|Object} [doc] An element or document object to use to set the document
4015 * @returns {Object} Returns the current document
4016 */
4017setDocument = Sizzle.setDocument = function( node ) {
4018	var doc = node ? node.ownerDocument || node : preferredDoc;
4019
4020	// If no document and documentElement is available, return
4021	if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
4022		return document;
4023	}
4024
4025	// Set our document
4026	document = doc;
4027	docElem = doc.documentElement;
4028
4029	// Support tests
4030	documentIsXML = isXML( doc );
4031
4032	// Check if getElementsByTagName("*") returns only elements
4033	support.tagNameNoComments = assert(function( div ) {
4034		div.appendChild( doc.createComment("") );
4035		return !div.getElementsByTagName("*").length;
4036	});
4037
4038	// Check if attributes should be retrieved by attribute nodes
4039	support.attributes = assert(function( div ) {
4040		div.innerHTML = "<select></select>";
4041		var type = typeof div.lastChild.getAttribute("multiple");
4042		// IE8 returns a string for some attributes even when not present
4043		return type !== "boolean" && type !== "string";
4044	});
4045
4046	// Check if getElementsByClassName can be trusted
4047	support.getByClassName = assert(function( div ) {
4048		// Opera can't find a second classname (in 9.6)
4049		div.innerHTML = "<div class='hidden e'></div><div class='hidden'></div>";
4050		if ( !div.getElementsByClassName || !div.getElementsByClassName("e").length ) {
4051			return false;
4052		}
4053
4054		// Safari 3.2 caches class attributes and doesn't catch changes
4055		div.lastChild.className = "e";
4056		return div.getElementsByClassName("e").length === 2;
4057	});
4058
4059	// Check if getElementById returns elements by name
4060	// Check if getElementsByName privileges form controls or returns elements by ID
4061	support.getByName = assert(function( div ) {
4062		// Inject content
4063		div.id = expando + 0;
4064		div.innerHTML = "<a name='" + expando + "'></a><div name='" + expando + "'></div>";
4065		docElem.insertBefore( div, docElem.firstChild );
4066
4067		// Test
4068		var pass = doc.getElementsByName &&
4069			// buggy browsers will return fewer than the correct 2
4070			doc.getElementsByName( expando ).length === 2 +
4071			// buggy browsers will return more than the correct 0
4072			doc.getElementsByName( expando + 0 ).length;
4073		support.getIdNotName = !doc.getElementById( expando );
4074
4075		// Cleanup
4076		docElem.removeChild( div );
4077
4078		return pass;
4079	});
4080
4081	// IE6/7 return modified attributes
4082	Expr.attrHandle = assert(function( div ) {
4083		div.innerHTML = "<a href='#'></a>";
4084		return div.firstChild && typeof div.firstChild.getAttribute !== strundefined &&
4085			div.firstChild.getAttribute("href") === "#";
4086	}) ?
4087		{} :
4088		{
4089			"href": function( elem ) {
4090				return elem.getAttribute( "href", 2 );
4091			},
4092			"type": function( elem ) {
4093				return elem.getAttribute("type");
4094			}
4095		};
4096
4097	// ID find and filter
4098	if ( support.getIdNotName ) {
4099		Expr.find["ID"] = function( id, context ) {
4100			if ( typeof context.getElementById !== strundefined && !documentIsXML ) {
4101				var m = context.getElementById( id );
4102				// Check parentNode to catch when Blackberry 4.6 returns
4103				// nodes that are no longer in the document #6963
4104				return m && m.parentNode ? [m] : [];
4105			}
4106		};
4107		Expr.filter["ID"] = function( id ) {
4108			var attrId = id.replace( runescape, funescape );
4109			return function( elem ) {
4110				return elem.getAttribute("id") === attrId;
4111			};
4112		};
4113	} else {
4114		Expr.find["ID"] = function( id, context ) {
4115			if ( typeof context.getElementById !== strundefined && !documentIsXML ) {
4116				var m = context.getElementById( id );
4117
4118				return m ?
4119					m.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode("id").value === id ?
4120						[m] :
4121						undefined :
4122					[];
4123			}
4124		};
4125		Expr.filter["ID"] =  function( id ) {
4126			var attrId = id.replace( runescape, funescape );
4127			return function( elem ) {
4128				var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
4129				return node && node.value === attrId;
4130			};
4131		};
4132	}
4133
4134	// Tag
4135	Expr.find["TAG"] = support.tagNameNoComments ?
4136		function( tag, context ) {
4137			if ( typeof context.getElementsByTagName !== strundefined ) {
4138				return context.getElementsByTagName( tag );
4139			}
4140		} :
4141		function( tag, context ) {
4142			var elem,
4143				tmp = [],
4144				i = 0,
4145				results = context.getElementsByTagName( tag );
4146
4147			// Filter out possible comments
4148			if ( tag === "*" ) {
4149				while ( (elem = results[i++]) ) {
4150					if ( elem.nodeType === 1 ) {
4151						tmp.push( elem );
4152					}
4153				}
4154
4155				return tmp;
4156			}
4157			return results;
4158		};
4159
4160	// Name
4161	Expr.find["NAME"] = support.getByName && function( tag, context ) {
4162		if ( typeof context.getElementsByName !== strundefined ) {
4163			return context.getElementsByName( name );
4164		}
4165	};
4166
4167	// Class
4168	Expr.find["CLASS"] = support.getByClassName && function( className, context ) {
4169		if ( typeof context.getElementsByClassName !== strundefined && !documentIsXML ) {
4170			return context.getElementsByClassName( className );
4171		}
4172	};
4173
4174	// QSA and matchesSelector support
4175
4176	// matchesSelector(:active) reports false when true (IE9/Opera 11.5)
4177	rbuggyMatches = [];
4178
4179	// qSa(:focus) reports false when true (Chrome 21),
4180	// no need to also add to buggyMatches since matches checks buggyQSA
4181	// A support test would require too much code (would include document ready)
4182	rbuggyQSA = [ ":focus" ];
4183
4184	if ( (support.qsa = isNative(doc.querySelectorAll)) ) {
4185		// Build QSA regex
4186		// Regex strategy adopted from Diego Perini
4187		assert(function( div ) {
4188			// Select is set to empty string on purpose
4189			// This is to test IE's treatment of not explictly
4190			// setting a boolean content attribute,
4191			// since its presence should be enough
4192			// http://bugs.jquery.com/ticket/12359
4193			div.innerHTML = "<select><option selected=''></option></select>";
4194
4195			// IE8 - Some boolean attributes are not treated correctly
4196			if ( !div.querySelectorAll("[selected]").length ) {
4197				rbuggyQSA.push( "\\[" + whitespace + "*(?:checked|disabled|ismap|multiple|readonly|selected|value)" );
4198			}
4199
4200			// Webkit/Opera - :checked should return selected option elements
4201			// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
4202			// IE8 throws error here and will not see later tests
4203			if ( !div.querySelectorAll(":checked").length ) {
4204				rbuggyQSA.push(":checked");
4205			}
4206		});
4207
4208		assert(function( div ) {
4209
4210			// Opera 10-12/IE8 - ^= $= *= and empty values
4211			// Should not select anything
4212			div.innerHTML = "<input type='hidden' i=''/>";
4213			if ( div.querySelectorAll("[i^='']").length ) {
4214				rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:\"\"|'')" );
4215			}
4216
4217			// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
4218			// IE8 throws error here and will not see later tests
4219			if ( !div.querySelectorAll(":enabled").length ) {
4220				rbuggyQSA.push( ":enabled", ":disabled" );
4221			}
4222
4223			// Opera 10-11 does not throw on post-comma invalid pseudos
4224			div.querySelectorAll("*,:x");
4225			rbuggyQSA.push(",.*:");
4226		});
4227	}
4228
4229	if ( (support.matchesSelector = isNative( (matches = docElem.matchesSelector ||
4230		docElem.mozMatchesSelector ||
4231		docElem.webkitMatchesSelector ||
4232		docElem.oMatchesSelector ||
4233		docElem.msMatchesSelector) )) ) {
4234
4235		assert(function( div ) {
4236			// Check to see if it's possible to do matchesSelector
4237			// on a disconnected node (IE 9)
4238			support.disconnectedMatch = matches.call( div, "div" );
4239
4240			// This should fail with an exception
4241			// Gecko does not error, returns false instead
4242			matches.call( div, "[s!='']:x" );
4243			rbuggyMatches.push( "!=", pseudos );
4244		});
4245	}
4246
4247	rbuggyQSA = new RegExp( rbuggyQSA.join("|") );
4248	rbuggyMatches = new RegExp( rbuggyMatches.join("|") );
4249
4250	// Element contains another
4251	// Purposefully does not implement inclusive descendent
4252	// As in, an element does not contain itself
4253	contains = isNative(docElem.contains) || docElem.compareDocumentPosition ?
4254		function( a, b ) {
4255			var adown = a.nodeType === 9 ? a.documentElement : a,
4256				bup = b && b.parentNode;
4257			return a === bup || !!( bup && bup.nodeType === 1 && (
4258				adown.contains ?
4259					adown.contains( bup ) :
4260					a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
4261			));
4262		} :
4263		function( a, b ) {
4264			if ( b ) {
4265				while ( (b = b.parentNode) ) {
4266					if ( b === a ) {
4267						return true;
4268					}
4269				}
4270			}
4271			return false;
4272		};
4273
4274	// Document order sorting
4275	sortOrder = docElem.compareDocumentPosition ?
4276	function( a, b ) {
4277		var compare;
4278
4279		if ( a === b ) {
4280			hasDuplicate = true;
4281			return 0;
4282		}
4283
4284		if ( (compare = b.compareDocumentPosition && a.compareDocumentPosition && a.compareDocumentPosition( b )) ) {
4285			if ( compare & 1 || a.parentNode && a.parentNode.nodeType === 11 ) {
4286				if ( a === doc || contains( preferredDoc, a ) ) {
4287					return -1;
4288				}
4289				if ( b === doc || contains( preferredDoc, b ) ) {
4290					return 1;
4291				}
4292				return 0;
4293			}
4294			return compare & 4 ? -1 : 1;
4295		}
4296
4297		return a.compareDocumentPosition ? -1 : 1;
4298	} :
4299	function( a, b ) {
4300		var cur,
4301			i = 0,
4302			aup = a.parentNode,
4303			bup = b.parentNode,
4304			ap = [ a ],
4305			bp = [ b ];
4306
4307		// Exit early if the nodes are identical
4308		if ( a === b ) {
4309			hasDuplicate = true;
4310			return 0;
4311
4312		// Parentless nodes are either documents or disconnected
4313		} else if ( !aup || !bup ) {
4314			return a === doc ? -1 :
4315				b === doc ? 1 :
4316				aup ? -1 :
4317				bup ? 1 :
4318				0;
4319
4320		// If the nodes are siblings, we can do a quick check
4321		} else if ( aup === bup ) {
4322			return siblingCheck( a, b );
4323		}
4324
4325		// Otherwise we need full lists of their ancestors for comparison
4326		cur = a;
4327		while ( (cur = cur.parentNode) ) {
4328			ap.unshift( cur );
4329		}
4330		cur = b;
4331		while ( (cur = cur.parentNode) ) {
4332			bp.unshift( cur );
4333		}
4334
4335		// Walk down the tree looking for a discrepancy
4336		while ( ap[i] === bp[i] ) {
4337			i++;
4338		}
4339
4340		return i ?
4341			// Do a sibling check if the nodes have a common ancestor
4342			siblingCheck( ap[i], bp[i] ) :
4343
4344			// Otherwise nodes in our document sort first
4345			ap[i] === preferredDoc ? -1 :
4346			bp[i] === preferredDoc ? 1 :
4347			0;
4348	};
4349
4350	// Always assume the presence of duplicates if sort doesn't
4351	// pass them to our comparison function (as in Google Chrome).
4352	hasDuplicate = false;
4353	[0, 0].sort( sortOrder );
4354	support.detectDuplicates = hasDuplicate;
4355
4356	return document;
4357};
4358
4359Sizzle.matches = function( expr, elements ) {
4360	return Sizzle( expr, null, null, elements );
4361};
4362
4363Sizzle.matchesSelector = function( elem, expr ) {
4364	// Set document vars if needed
4365	if ( ( elem.ownerDocument || elem ) !== document ) {
4366		setDocument( elem );
4367	}
4368
4369	// Make sure that attribute selectors are quoted
4370	expr = expr.replace( rattributeQuotes, "='$1']" );
4371
4372	// rbuggyQSA always contains :focus, so no need for an existence check
4373	if ( support.matchesSelector && !documentIsXML && (!rbuggyMatches || !rbuggyMatches.test(expr)) && !rbuggyQSA.test(expr) ) {
4374		try {
4375			var ret = matches.call( elem, expr );
4376
4377			// IE 9's matchesSelector returns false on disconnected nodes
4378			if ( ret || support.disconnectedMatch ||
4379					// As well, disconnected nodes are said to be in a document
4380					// fragment in IE 9
4381					elem.document && elem.document.nodeType !== 11 ) {
4382				return ret;
4383			}
4384		} catch(e) {}
4385	}
4386
4387	return Sizzle( expr, document, null, [elem] ).length > 0;
4388};
4389
4390Sizzle.contains = function( context, elem ) {
4391	// Set document vars if needed
4392	if ( ( context.ownerDocument || context ) !== document ) {
4393		setDocument( context );
4394	}
4395	return contains( context, elem );
4396};
4397
4398Sizzle.attr = function( elem, name ) {
4399	var val;
4400
4401	// Set document vars if needed
4402	if ( ( elem.ownerDocument || elem ) !== document ) {
4403		setDocument( elem );
4404	}
4405
4406	if ( !documentIsXML ) {
4407		name = name.toLowerCase();
4408	}
4409	if ( (val = Expr.attrHandle[ name ]) ) {
4410		return val( elem );
4411	}
4412	if ( documentIsXML || support.attributes ) {
4413		return elem.getAttribute( name );
4414	}
4415	return ( (val = elem.getAttributeNode( name )) || elem.getAttribute( name ) ) && elem[ name ] === true ?
4416		name :
4417		val && val.specified ? val.value : null;
4418};
4419
4420Sizzle.error = function( msg ) {
4421	throw new Error( "Syntax error, unrecognized expression: " + msg );
4422};
4423
4424// Document sorting and removing duplicates
4425Sizzle.uniqueSort = function( results ) {
4426	var elem,
4427		duplicates = [],
4428		i = 1,
4429		j = 0;
4430
4431	// Unless we *know* we can detect duplicates, assume their presence
4432	hasDuplicate = !support.detectDuplicates;
4433	results.sort( sortOrder );
4434
4435	if ( hasDuplicate ) {
4436		for ( ; (elem = results[i]); i++ ) {
4437			if ( elem === results[ i - 1 ] ) {
4438				j = duplicates.push( i );
4439			}
4440		}
4441		while ( j-- ) {
4442			results.splice( duplicates[ j ], 1 );
4443		}
4444	}
4445
4446	return results;
4447};
4448
4449function siblingCheck( a, b ) {
4450	var cur = b && a,
4451		diff = cur && ( ~b.sourceIndex || MAX_NEGATIVE ) - ( ~a.sourceIndex || MAX_NEGATIVE );
4452
4453	// Use IE sourceIndex if available on both nodes
4454	if ( diff ) {
4455		return diff;
4456	}
4457
4458	// Check if b follows a
4459	if ( cur ) {
4460		while ( (cur = cur.nextSibling) ) {
4461			if ( cur === b ) {
4462				return -1;
4463			}
4464		}
4465	}
4466
4467	return a ? 1 : -1;
4468}
4469
4470// Returns a function to use in pseudos for input types
4471function createInputPseudo( type ) {
4472	return function( elem ) {
4473		var name = elem.nodeName.toLowerCase();
4474		return name === "input" && elem.type === type;
4475	};
4476}
4477
4478// Returns a function to use in pseudos for buttons
4479function createButtonPseudo( type ) {
4480	return function( elem ) {
4481		var name = elem.nodeName.toLowerCase();
4482		return (name === "input" || name === "button") && elem.type === type;
4483	};
4484}
4485
4486// Returns a function to use in pseudos for positionals
4487function createPositionalPseudo( fn ) {
4488	return markFunction(function( argument ) {
4489		argument = +argument;
4490		return markFunction(function( seed, matches ) {
4491			var j,
4492				matchIndexes = fn( [], seed.length, argument ),
4493				i = matchIndexes.length;
4494
4495			// Match elements found at the specified indexes
4496			while ( i-- ) {
4497				if ( seed[ (j = matchIndexes[i]) ] ) {
4498					seed[j] = !(matches[j] = seed[j]);
4499				}
4500			}
4501		});
4502	});
4503}
4504
4505/**
4506 * Utility function for retrieving the text value of an array of DOM nodes
4507 * @param {Array|Element} elem
4508 */
4509getText = Sizzle.getText = function( elem ) {
4510	var node,
4511		ret = "",
4512		i = 0,
4513		nodeType = elem.nodeType;
4514
4515	if ( !nodeType ) {
4516		// If no nodeType, this is expected to be an array
4517		for ( ; (node = elem[i]); i++ ) {
4518			// Do not traverse comment nodes
4519			ret += getText( node );
4520		}
4521	} else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
4522		// Use textContent for elements
4523		// innerText usage removed for consistency of new lines (see #11153)
4524		if ( typeof elem.textContent === "string" ) {
4525			return elem.textContent;
4526		} else {
4527			// Traverse its children
4528			for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
4529				ret += getText( elem );
4530			}
4531		}
4532	} else if ( nodeType === 3 || nodeType === 4 ) {
4533		return elem.nodeValue;
4534	}
4535	// Do not include comment or processing instruction nodes
4536
4537	return ret;
4538};
4539
4540Expr = Sizzle.selectors = {
4541
vendor: 20,551 bytes, lines 4542-5272
4542	// Can be adjusted by the user
4543	cacheLength: 50,
4544
4545	createPseudo: markFunction,
4546
4547	match: matchExpr,
4548
4549	find: {},
4550
4551	relative: {
4552		">": { dir: "parentNode", first: true },
4553		" ": { dir: "parentNode" },
4554		"+": { dir: "previousSibling", first: true },
4555		"~": { dir: "previousSibling" }
4556	},
4557
4558	preFilter: {
4559		"ATTR": function( match ) {
4560			match[1] = match[1].replace( runescape, funescape );
4561
4562			// Move the given value to match[3] whether quoted or unquoted
4563			match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape );
4564
4565			if ( match[2] === "~=" ) {
4566				match[3] = " " + match[3] + " ";
4567			}
4568
4569			return match.slice( 0, 4 );
4570		},
4571
4572		"CHILD": function( match ) {
4573			/* matches from matchExpr["CHILD"]
4574				1 type (only|nth|...)
4575				2 what (child|of-type)
4576				3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
4577				4 xn-component of xn+y argument ([+-]?\d*n|)
4578				5 sign of xn-component
4579				6 x of xn-component
4580				7 sign of y-component
4581				8 y of y-component
4582			*/
4583			match[1] = match[1].toLowerCase();
4584
4585			if ( match[1].slice( 0, 3 ) === "nth" ) {
4586				// nth-* requires argument
4587				if ( !match[3] ) {
4588					Sizzle.error( match[0] );
4589				}
4590
4591				// numeric x and y parameters for Expr.filter.CHILD
4592				// remember that false/true cast respectively to 0/1
4593				match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
4594				match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
4595
4596			// other types prohibit arguments
4597			} else if ( match[3] ) {
4598				Sizzle.error( match[0] );
4599			}
4600
4601			return match;
4602		},
4603
4604		"PSEUDO": function( match ) {
4605			var excess,
4606				unquoted = !match[5] && match[2];
4607
4608			if ( matchExpr["CHILD"].test( match[0] ) ) {
4609				return null;
4610			}
4611
4612			// Accept quoted arguments as-is
4613			if ( match[4] ) {
4614				match[2] = match[4];
4615
4616			// Strip excess characters from unquoted arguments
4617			} else if ( unquoted && rpseudo.test( unquoted ) &&
4618				// Get excess from tokenize (recursively)
4619				(excess = tokenize( unquoted, true )) &&
4620				// advance to the next closing parenthesis
4621				(excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
4622
4623				// excess is a negative index
4624				match[0] = match[0].slice( 0, excess );
4625				match[2] = unquoted.slice( 0, excess );
4626			}
4627
4628			// Return only captures needed by the pseudo filter method (type and argument)
4629			return match.slice( 0, 3 );
4630		}
4631	},
4632
4633	filter: {
4634
4635		"TAG": function( nodeName ) {
4636			if ( nodeName === "*" ) {
4637				return function() { return true; };
4638			}
4639
4640			nodeName = nodeName.replace( runescape, funescape ).toLowerCase();
4641			return function( elem ) {
4642				return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
4643			};
4644		},
4645
4646		"CLASS": function( className ) {
4647			var pattern = classCache[ className + " " ];
4648
4649			return pattern ||
4650				(pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
4651				classCache( className, function( elem ) {
4652					return pattern.test( elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute("class")) || "" );
4653				});
4654		},
4655
4656		"ATTR": function( name, operator, check ) {
4657			return function( elem ) {
4658				var result = Sizzle.attr( elem, name );
4659
4660				if ( result == null ) {
4661					return operator === "!=";
4662				}
4663				if ( !operator ) {
4664					return true;
4665				}
4666
4667				result += "";
4668
4669				return operator === "=" ? result === check :
4670					operator === "!=" ? result !== check :
4671					operator === "^=" ? check && result.indexOf( check ) === 0 :
4672					operator === "*=" ? check && result.indexOf( check ) > -1 :
4673					operator === "$=" ? check && result.slice( -check.length ) === check :
4674					operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
4675					operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
4676					false;
4677			};
4678		},
4679
4680		"CHILD": function( type, what, argument, first, last ) {
4681			var simple = type.slice( 0, 3 ) !== "nth",
4682				forward = type.slice( -4 ) !== "last",
4683				ofType = what === "of-type";
4684
4685			return first === 1 && last === 0 ?
4686
4687				// Shortcut for :nth-*(n)
4688				function( elem ) {
4689					return !!elem.parentNode;
4690				} :
4691
4692				function( elem, context, xml ) {
4693					var cache, outerCache, node, diff, nodeIndex, start,
4694						dir = simple !== forward ? "nextSibling" : "previousSibling",
4695						parent = elem.parentNode,
4696						name = ofType && elem.nodeName.toLowerCase(),
4697						useCache = !xml && !ofType;
4698
4699					if ( parent ) {
4700
4701						// :(first|last|only)-(child|of-type)
4702						if ( simple ) {
4703							while ( dir ) {
4704								node = elem;
4705								while ( (node = node[ dir ]) ) {
4706									if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
4707										return false;
4708									}
4709								}
4710								// Reverse direction for :only-* (if we haven't yet done so)
4711								start = dir = type === "only" && !start && "nextSibling";
4712							}
4713							return true;
4714						}
4715
4716						start = [ forward ? parent.firstChild : parent.lastChild ];
4717
4718						// non-xml :nth-child(...) stores cache data on `parent`
4719						if ( forward && useCache ) {
4720							// Seek `elem` from a previously-cached index
4721							outerCache = parent[ expando ] || (parent[ expando ] = {});
4722							cache = outerCache[ type ] || [];
4723							nodeIndex = cache[0] === dirruns && cache[1];
4724							diff = cache[0] === dirruns && cache[2];
4725							node = nodeIndex && parent.childNodes[ nodeIndex ];
4726
4727							while ( (node = ++nodeIndex && node && node[ dir ] ||
4728
4729								// Fallback to seeking `elem` from the start
4730								(diff = nodeIndex = 0) || start.pop()) ) {
4731
4732								// When found, cache indexes on `parent` and break
4733								if ( node.nodeType === 1 && ++diff && node === elem ) {
4734									outerCache[ type ] = [ dirruns, nodeIndex, diff ];
4735									break;
4736								}
4737							}
4738
4739						// Use previously-cached element index if available
4740						} else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
4741							diff = cache[1];
4742
4743						// xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)
4744						} else {
4745							// Use the same loop as above to seek `elem` from the start
4746							while ( (node = ++nodeIndex && node && node[ dir ] ||
4747								(diff = nodeIndex = 0) || start.pop()) ) {
4748
4749								if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
4750									// Cache the index of each encountered element
4751									if ( useCache ) {
4752										(node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
4753									}
4754
4755									if ( node === elem ) {
4756										break;
4757									}
4758								}
4759							}
4760						}
4761
4762						// Incorporate the offset, then check against cycle size
4763						diff -= last;
4764						return diff === first || ( diff % first === 0 && diff / first >= 0 );
4765					}
4766				};
4767		},
4768
4769		"PSEUDO": function( pseudo, argument ) {
4770			// pseudo-class names are case-insensitive
4771			// http://www.w3.org/TR/selectors/#pseudo-classes
4772			// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
4773			// Remember that setFilters inherits from pseudos
4774			var args,
4775				fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
4776					Sizzle.error( "unsupported pseudo: " + pseudo );
4777
4778			// The user may use createPseudo to indicate that
4779			// arguments are needed to create the filter function
4780			// just as Sizzle does
4781			if ( fn[ expando ] ) {
4782				return fn( argument );
4783			}
4784
4785			// But maintain support for old signatures
4786			if ( fn.length > 1 ) {
4787				args = [ pseudo, pseudo, "", argument ];
4788				return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
4789					markFunction(function( seed, matches ) {
4790						var idx,
4791							matched = fn( seed, argument ),
4792							i = matched.length;
4793						while ( i-- ) {
4794							idx = indexOf.call( seed, matched[i] );
4795							seed[ idx ] = !( matches[ idx ] = matched[i] );
4796						}
4797					}) :
4798					function( elem ) {
4799						return fn( elem, 0, args );
4800					};
4801			}
4802
4803			return fn;
4804		}
4805	},
4806
4807	pseudos: {
4808		// Potentially complex pseudos
4809		"not": markFunction(function( selector ) {
4810			// Trim the selector passed to compile
4811			// to avoid treating leading and trailing
4812			// spaces as combinators
4813			var input = [],
4814				results = [],
4815				matcher = compile( selector.replace( rtrim, "$1" ) );
4816
4817			return matcher[ expando ] ?
4818				markFunction(function( seed, matches, context, xml ) {
4819					var elem,
4820						unmatched = matcher( seed, null, xml, [] ),
4821						i = seed.length;
4822
4823					// Match elements unmatched by `matcher`
4824					while ( i-- ) {
4825						if ( (elem = unmatched[i]) ) {
4826							seed[i] = !(matches[i] = elem);
4827						}
4828					}
4829				}) :
4830				function( elem, context, xml ) {
4831					input[0] = elem;
4832					matcher( input, null, xml, results );
4833					return !results.pop();
4834				};
4835		}),
4836
4837		"has": markFunction(function( selector ) {
4838			return function( elem ) {
4839				return Sizzle( selector, elem ).length > 0;
4840			};
4841		}),
4842
4843		"contains": markFunction(function( text ) {
4844			return function( elem ) {
4845				return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
4846			};
4847		}),
4848
4849		// "Whether an element is represented by a :lang() selector
4850		// is based solely on the element's language value
4851		// being equal to the identifier C,
4852		// or beginning with the identifier C immediately followed by "-".
4853		// The matching of C against the element's language value is performed case-insensitively.
4854		// The identifier C does not have to be a valid language name."
4855		// http://www.w3.org/TR/selectors/#lang-pseudo
4856		"lang": markFunction( function( lang ) {
4857			// lang value must be a valid identifider
4858			if ( !ridentifier.test(lang || "") ) {
4859				Sizzle.error( "unsupported lang: " + lang );
4860			}
4861			lang = lang.replace( runescape, funescape ).toLowerCase();
4862			return function( elem ) {
4863				var elemLang;
4864				do {
4865					if ( (elemLang = documentIsXML ?
4866						elem.getAttribute("xml:lang") || elem.getAttribute("lang") :
4867						elem.lang) ) {
4868
4869						elemLang = elemLang.toLowerCase();
4870						return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
4871					}
4872				} while ( (elem = elem.parentNode) && elem.nodeType === 1 );
4873				return false;
4874			};
4875		}),
4876
4877		// Miscellaneous
4878		"target": function( elem ) {
4879			var hash = window.location && window.location.hash;
4880			return hash && hash.slice( 1 ) === elem.id;
4881		},
4882
4883		"root": function( elem ) {
4884			return elem === docElem;
4885		},
4886
4887		"focus": function( elem ) {
4888			return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
4889		},
4890
4891		// Boolean properties
4892		"enabled": function( elem ) {
4893			return elem.disabled === false;
4894		},
4895
4896		"disabled": function( elem ) {
4897			return elem.disabled === true;
4898		},
4899
4900		"checked": function( elem ) {
4901			// In CSS3, :checked should return both checked and selected elements
4902			// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
4903			var nodeName = elem.nodeName.toLowerCase();
4904			return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
4905		},
4906
4907		"selected": function( elem ) {
4908			// Accessing this property makes selected-by-default
4909			// options in Safari work properly
4910			if ( elem.parentNode ) {
4911				elem.parentNode.selectedIndex;
4912			}
4913
4914			return elem.selected === true;
4915		},
4916
4917		// Contents
4918		"empty": function( elem ) {
4919			// http://www.w3.org/TR/selectors/#empty-pseudo
4920			// :empty is only affected by element nodes and content nodes(including text(3), cdata(4)),
4921			//   not comment, processing instructions, or others
4922			// Thanks to Diego Perini for the nodeName shortcut
4923			//   Greater than "@" means alpha characters (specifically not starting with "#" or "?")
4924			for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
4925				if ( elem.nodeName > "@" || elem.nodeType === 3 || elem.nodeType === 4 ) {
4926					return false;
4927				}
4928			}
4929			return true;
4930		},
4931
4932		"parent": function( elem ) {
4933			return !Expr.pseudos["empty"]( elem );
4934		},
4935
4936		// Element/input types
4937		"header": function( elem ) {
4938			return rheader.test( elem.nodeName );
4939		},
4940
4941		"input": function( elem ) {
4942			return rinputs.test( elem.nodeName );
4943		},
4944
4945		"button": function( elem ) {
4946			var name = elem.nodeName.toLowerCase();
4947			return name === "input" && elem.type === "button" || name === "button";
4948		},
4949
4950		"text": function( elem ) {
4951			var attr;
4952			// IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
4953			// use getAttribute instead to test this case
4954			return elem.nodeName.toLowerCase() === "input" &&
4955				elem.type === "text" &&
4956				( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === elem.type );
4957		},
4958
4959		// Position-in-collection
4960		"first": createPositionalPseudo(function() {
4961			return [ 0 ];
4962		}),
4963
4964		"last": createPositionalPseudo(function( matchIndexes, length ) {
4965			return [ length - 1 ];
4966		}),
4967
4968		"eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
4969			return [ argument < 0 ? argument + length : argument ];
4970		}),
4971
4972		"even": createPositionalPseudo(function( matchIndexes, length ) {
4973			var i = 0;
4974			for ( ; i < length; i += 2 ) {
4975				matchIndexes.push( i );
4976			}
4977			return matchIndexes;
4978		}),
4979
4980		"odd": createPositionalPseudo(function( matchIndexes, length ) {
4981			var i = 1;
4982			for ( ; i < length; i += 2 ) {
4983				matchIndexes.push( i );
4984			}
4985			return matchIndexes;
4986		}),
4987
4988		"lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
4989			var i = argument < 0 ? argument + length : argument;
4990			for ( ; --i >= 0; ) {
4991				matchIndexes.push( i );
4992			}
4993			return matchIndexes;
4994		}),
4995
4996		"gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
4997			var i = argument < 0 ? argument + length : argument;
4998			for ( ; ++i < length; ) {
4999				matchIndexes.push( i );
5000			}
5001			return matchIndexes;
5002		})
5003	}
5004};
5005
5006// Add button/input type pseudos
5007for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
5008	Expr.pseudos[ i ] = createInputPseudo( i );
5009}
5010for ( i in { submit: true, reset: true } ) {
5011	Expr.pseudos[ i ] = createButtonPseudo( i );
5012}
5013
5014function tokenize( selector, parseOnly ) {
5015	var matched, match, tokens, type,
5016		soFar, groups, preFilters,
5017		cached = tokenCache[ selector + " " ];
5018
5019	if ( cached ) {
5020		return parseOnly ? 0 : cached.slice( 0 );
5021	}
5022
5023	soFar = selector;
5024	groups = [];
5025	preFilters = Expr.preFilter;
5026
5027	while ( soFar ) {
5028
5029		// Comma and first run
5030		if ( !matched || (match = rcomma.exec( soFar )) ) {
5031			if ( match ) {
5032				// Don't consume trailing commas as valid
5033				soFar = soFar.slice( match[0].length ) || soFar;
5034			}
5035			groups.push( tokens = [] );
5036		}
5037
5038		matched = false;
5039
5040		// Combinators
5041		if ( (match = rcombinators.exec( soFar )) ) {
5042			matched = match.shift();
5043			tokens.push( {
5044				value: matched,
5045				// Cast descendant combinators to space
5046				type: match[0].replace( rtrim, " " )
5047			} );
5048			soFar = soFar.slice( matched.length );
5049		}
5050
5051		// Filters
5052		for ( type in Expr.filter ) {
5053			if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
5054				(match = preFilters[ type ]( match ))) ) {
5055				matched = match.shift();
5056				tokens.push( {
5057					value: matched,
5058					type: type,
5059					matches: match
5060				} );
5061				soFar = soFar.slice( matched.length );
5062			}
5063		}
5064
5065		if ( !matched ) {
5066			break;
5067		}
5068	}
5069
5070	// Return the length of the invalid excess
5071	// if we're just parsing
5072	// Otherwise, throw an error or return tokens
5073	return parseOnly ?
5074		soFar.length :
5075		soFar ?
5076			Sizzle.error( selector ) :
5077			// Cache the tokens
5078			tokenCache( selector, groups ).slice( 0 );
5079}
5080
5081function toSelector( tokens ) {
5082	var i = 0,
5083		len = tokens.length,
5084		selector = "";
5085	for ( ; i < len; i++ ) {
5086		selector += tokens[i].value;
5087	}
5088	return selector;
5089}
5090
5091function addCombinator( matcher, combinator, base ) {
5092	var dir = combinator.dir,
5093		checkNonElements = base && dir === "parentNode",
5094		doneName = done++;
5095
5096	return combinator.first ?
5097		// Check against closest ancestor/preceding element
5098		function( elem, context, xml ) {
5099			while ( (elem = elem[ dir ]) ) {
5100				if ( elem.nodeType === 1 || checkNonElements ) {
5101					return matcher( elem, context, xml );
5102				}
5103			}
5104		} :
5105
5106		// Check against all ancestor/preceding elements
5107		function( elem, context, xml ) {
5108			var data, cache, outerCache,
5109				dirkey = dirruns + " " + doneName;
5110
5111			// We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
5112			if ( xml ) {
5113				while ( (elem = elem[ dir ]) ) {
5114					if ( elem.nodeType === 1 || checkNonElements ) {
5115						if ( matcher( elem, context, xml ) ) {
5116							return true;
5117						}
5118					}
5119				}
5120			} else {
5121				while ( (elem = elem[ dir ]) ) {
5122					if ( elem.nodeType === 1 || checkNonElements ) {
5123						outerCache = elem[ expando ] || (elem[ expando ] = {});
5124						if ( (cache = outerCache[ dir ]) && cache[0] === dirkey ) {
5125							if ( (data = cache[1]) === true || data === cachedruns ) {
5126								return data === true;
5127							}
5128						} else {
5129							cache = outerCache[ dir ] = [ dirkey ];
5130							cache[1] = matcher( elem, context, xml ) || cachedruns;
5131							if ( cache[1] === true ) {
5132								return true;
5133							}
5134						}
5135					}
5136				}
5137			}
5138		};
5139}
5140
5141function elementMatcher( matchers ) {
5142	return matchers.length > 1 ?
5143		function( elem, context, xml ) {
5144			var i = matchers.length;
5145			while ( i-- ) {
5146				if ( !matchers[i]( elem, context, xml ) ) {
5147					return false;
5148				}
5149			}
5150			return true;
5151		} :
5152		matchers[0];
5153}
5154
5155function condense( unmatched, map, filter, context, xml ) {
5156	var elem,
5157		newUnmatched = [],
5158		i = 0,
5159		len = unmatched.length,
5160		mapped = map != null;
5161
5162	for ( ; i < len; i++ ) {
5163		if ( (elem = unmatched[i]) ) {
5164			if ( !filter || filter( elem, context, xml ) ) {
5165				newUnmatched.push( elem );
5166				if ( mapped ) {
5167					map.push( i );
5168				}
5169			}
5170		}
5171	}
5172
5173	return newUnmatched;
5174}
5175
5176function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
5177	if ( postFilter && !postFilter[ expando ] ) {
5178		postFilter = setMatcher( postFilter );
5179	}
5180	if ( postFinder && !postFinder[ expando ] ) {
5181		postFinder = setMatcher( postFinder, postSelector );
5182	}
5183	return markFunction(function( seed, results, context, xml ) {
5184		var temp, i, elem,
5185			preMap = [],
5186			postMap = [],
5187			preexisting = results.length,
5188
5189			// Get initial elements from seed or context
5190			elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
5191
5192			// Prefilter to get matcher input, preserving a map for seed-results synchronization
5193			matcherIn = preFilter && ( seed || !selector ) ?
5194				condense( elems, preMap, preFilter, context, xml ) :
5195				elems,
5196
5197			matcherOut = matcher ?
5198				// If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
5199				postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
5200
5201					// ...intermediate processing is necessary
5202					[] :
5203
5204					// ...otherwise use results directly
5205					results :
5206				matcherIn;
5207
5208		// Find primary matches
5209		if ( matcher ) {
5210			matcher( matcherIn, matcherOut, context, xml );
5211		}
5212
5213		// Apply postFilter
5214		if ( postFilter ) {
5215			temp = condense( matcherOut, postMap );
5216			postFilter( temp, [], context, xml );
5217
5218			// Un-match failing elements by moving them back to matcherIn
5219			i = temp.length;
5220			while ( i-- ) {
5221				if ( (elem = temp[i]) ) {
5222					matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
5223				}
5224			}
5225		}
5226
5227		if ( seed ) {
5228			if ( postFinder || preFilter ) {
5229				if ( postFinder ) {
5230					// Get the final matcherOut by condensing this intermediate into postFinder contexts
5231					temp = [];
5232					i = matcherOut.length;
5233					while ( i-- ) {
5234						if ( (elem = matcherOut[i]) ) {
5235							// Restore matcherIn since elem is not yet a final match
5236							temp.push( (matcherIn[i] = elem) );
5237						}
5238					}
5239					postFinder( null, (matcherOut = []), temp, xml );
5240				}
5241
5242				// Move matched elements from seed to results to keep them synchronized
5243				i = matcherOut.length;
5244				while ( i-- ) {
5245					if ( (elem = matcherOut[i]) &&
5246						(temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
5247
5248						seed[temp] = !(results[temp] = elem);
5249					}
5250				}
5251			}
5252
5253		// Add elements to results, through postFinder if defined
5254		} else {
5255			matcherOut = condense(
5256				matcherOut === results ?
5257					matcherOut.splice( preexisting, matcherOut.length ) :
5258					matcherOut
5259			);
5260			if ( postFinder ) {
5261				postFinder( null, results, matcherOut, xml );
5262			} else {
5263				push.apply( results, matcherOut );
5264			}
5265		}
5266	});
5267}
5268
5269function matcherFromTokens( tokens ) {
5270	var checkContext, matcher, j,
5271		len = tokens.length,
5272		leadingRelative = Expr.relative[ tokens[0].type ],
5273		implicitRelative = leadingRelative || Expr.relative[" "],
5274		i = leadingRelative ? 1 : 0,
5275
5276		// The foundational matcher ensures that elements are reachable from top-level context(s)
5277		matchContext = addCombinator( function( elem ) {
5278			return elem === checkContext;
5279		}, implicitRelative, true ),
5280		matchAnyContext = addCombinator( function( elem ) {
5281			return indexOf.call( checkContext, elem ) > -1;
5282		}, implicitRelative, true ),
5283		matchers = [ function( elem, context, xml ) {
5284			return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
5285				(checkContext = context).nodeType ?
5286					matchContext( elem, context, xml ) :
5287					matchAnyContext( elem, context, xml ) );
5288		} ];
5289
5290	for ( ; i < len; i++ ) {
5291		if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
5292			matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
5293		} else {
5294			matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
5295
5296			// Return special upon seeing a positional matcher
5297			if ( matcher[ expando ] ) {
5298				// Find the next relative operator (if any) for proper handling
5299				j = ++i;
5300				for ( ; j < len; j++ ) {
5301					if ( Expr.relative[ tokens[j].type ] ) {
5302						break;
5303					}
5304				}
5305				return setMatcher(
5306					i > 1 && elementMatcher( matchers ),
5307					i > 1 && toSelector( tokens.slice( 0, i - 1 ) ).replace( rtrim, "$1" ),
5308					matcher,
5309					i < j && matcherFromTokens( tokens.slice( i, j ) ),
5310					j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
5311					j < len && toSelector( tokens )
5312				);
5313			}
5314			matchers.push( matcher );
5315		}
5316	}
5317
5318	return elementMatcher( matchers );
5319}
5320
5321function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
5322	// A counter to specify which element is currently being matched
5323	var matcherCachedRuns = 0,
5324		bySet = setMatchers.length > 0,
5325		byElement = elementMatchers.length > 0,
5326		superMatcher = function( seed, context, xml, results, expandContext ) {
5327			var elem, j, matcher,
5328				setMatched = [],
5329				matchedCount = 0,
5330				i = "0",
5331				unmatched = seed && [],
5332				outermost = expandContext != null,
5333				contextBackup = outermostContext,
5334				// We must always have either seed elements or context
5335				elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ),
5336				// Use integer dirruns iff this is the outermost matcher
5337				dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1);
5338
5339			if ( outermost ) {
5340				outermostContext = context !== document && context;
5341				cachedruns = matcherCachedRuns;
5342			}
5343
5344			// Add elements passing elementMatchers directly to results
5345			// Keep `i` a string if there are no elements so `matchedCount` will be "00" below
5346			for ( ; (elem = elems[i]) != null; i++ ) {
5347				if ( byElement && elem ) {
5348					j = 0;
5349					while ( (matcher = elementMatchers[j++]) ) {
5350						if ( matcher( elem, context, xml ) ) {
5351							results.push( elem );
5352							break;
5353						}
5354					}
5355					if ( outermost ) {
5356						dirruns = dirrunsUnique;
5357						cachedruns = ++matcherCachedRuns;
5358					}
5359				}
5360
5361				// Track unmatched elements for set filters
5362				if ( bySet ) {
5363					// They will have gone through all possible matchers
5364					if ( (elem = !matcher && elem) ) {
5365						matchedCount--;
5366					}
5367
5368					// Lengthen the array for every element, matched or not
5369					if ( seed ) {
5370						unmatched.push( elem );
5371					}
5372				}
5373			}
5374
5375			// Apply set filters to unmatched elements
5376			matchedCount += i;
5377			if ( bySet && i !== matchedCount ) {
5378				j = 0;
5379				while ( (matcher = setMatchers[j++]) ) {
5380					matcher( unmatched, setMatched, context, xml );
5381				}
5382
5383				if ( seed ) {
5384					// Reintegrate element matches to eliminate the need for sorting
5385					if ( matchedCount > 0 ) {
5386						while ( i-- ) {
5387							if ( !(unmatched[i] || setMatched[i]) ) {
5388								setMatched[i] = pop.call( results );
5389							}
5390						}
5391					}
5392
5393					// Discard index placeholder values to get only actual matches
5394					setMatched = condense( setMatched );
5395				}
5396
5397				// Add matches to results
5398				push.apply( results, setMatched );
5399
5400				// Seedless set matches succeeding multiple successful matchers stipulate sorting
5401				if ( outermost && !seed && setMatched.length > 0 &&
5402					( matchedCount + setMatchers.length ) > 1 ) {
5403
5404					Sizzle.uniqueSort( results );
5405				}
5406			}
5407
5408			// Override manipulation of globals by nested matchers
5409			if ( outermost ) {
5410				dirruns = dirrunsUnique;
5411				outermostContext = contextBackup;
5412			}
5413
5414			return unmatched;
5415		};
5416
5417	return bySet ?
5418		markFunction( superMatcher ) :
5419		superMatcher;
5420}
5421
5422compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) {
5423	var i,
5424		setMatchers = [],
5425		elementMatchers = [],
5426		cached = compilerCache[ selector + " " ];
5427
5428	if ( !cached ) {
5429		// Generate a function of recursive functions that can be used to check each element
5430		if ( !group ) {
5431			group = tokenize( selector );
5432		}
5433		i = group.length;
5434		while ( i-- ) {
5435			cached = matcherFromTokens( group[i] );
5436			if ( cached[ expando ] ) {
5437				setMatchers.push( cached );
5438			} else {
5439				elementMatchers.push( cached );
5440			}
5441		}
5442
5443		// Cache the compiled function
5444		cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
5445	}
5446	return cached;
5447};
5448
5449function multipleContexts( selector, contexts, results ) {
5450	var i = 0,
5451		len = contexts.length;
5452	for ( ; i < len; i++ ) {
5453		Sizzle( selector, contexts[i], results );
5454	}
5455	return results;
5456}
5457
5458function select( selector, context, results, seed ) {
5459	var i, tokens, token, type, find,
5460		match = tokenize( selector );
5461
5462	if ( !seed ) {
5463		// Try to minimize operations if there is only one group
5464		if ( match.length === 1 ) {
5465
5466			// Take a shortcut and set the context if the root selector is an ID
5467			tokens = match[0] = match[0].slice( 0 );
5468			if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
5469					context.nodeType === 9 && !documentIsXML &&
5470					Expr.relative[ tokens[1].type ] ) {
5471
5472				context = Expr.find["ID"]( token.matches[0].replace( runescape, funescape ), context )[0];
5473				if ( !context ) {
5474					return results;
5475				}
5476
5477				selector = selector.slice( tokens.shift().value.length );
5478			}
5479
5480			// Fetch a seed set for right-to-left matching
5481			i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
5482			while ( i-- ) {
5483				token = tokens[i];
5484
5485				// Abort if we hit a combinator
5486				if ( Expr.relative[ (type = token.type) ] ) {
5487					break;
5488				}
5489				if ( (find = Expr.find[ type ]) ) {
5490					// Search, expanding context for leading sibling combinators
5491					if ( (seed = find(
5492						token.matches[0].replace( runescape, funescape ),
5493						rsibling.test( tokens[0].type ) && context.parentNode || context
5494					)) ) {
5495
5496						// If seed is empty or no tokens remain, we can return early
5497						tokens.splice( i, 1 );
5498						selector = seed.length && toSelector( tokens );
5499						if ( !selector ) {
5500							push.apply( results, slice.call( seed, 0 ) );
5501							return results;
5502						}
5503
5504						break;
5505					}
5506				}
5507			}
5508		}
5509	}
5510
5511	// Compile and execute a filtering function
5512	// Provide `match` to avoid retokenization if we modified the selector above
5513	compile( selector, match )(
5514		seed,
5515		context,
5516		documentIsXML,
5517		results,
5518		rsibling.test( selector )
5519	);
5520	return results;
5521}
5522
5523// Deprecated
5524Expr.pseudos["nth"] = Expr.pseudos["eq"];
5525
5526// Easy API for creating new setFilters
5527function setFilters() {}
5528Expr.filters = setFilters.prototype = Expr.pseudos;
5529Expr.setFilters = new setFilters();
5530
5531// Initialize with the default document
5532setDocument();
5533
5534// Override sizzle attribute retrieval
5535Sizzle.attr = jQuery.attr;
5536jQuery.find = Sizzle;
5537jQuery.expr = Sizzle.selectors;
5538jQuery.expr[":"] = jQuery.expr.pseudos;
5539jQuery.unique = Sizzle.uniqueSort;
5540jQuery.text = Sizzle.getText;
5541jQuery.isXMLDoc = Sizzle.isXML;
5542jQuery.contains = Sizzle.contains;
5543
5544
5545})( window );
5546var runtil = /Until$/,
5547	rparentsprev = /^(?:parents|prev(?:Until|All))/,
5548	isSimple = /^.[^:#\[\.,]*$/,
5549	rneedsContext = jQuery.expr.match.needsContext,
5550	// methods guaranteed to produce a unique set when starting from a unique set
5551	guaranteedUnique = {
5552		children: true,
5553		contents: true,
5554		next: true,
5555		prev: true
5556	};
5557
5558jQuery.fn.extend({
5559	find: function( selector ) {
5560		var i, ret, self,
5561			len = this.length;
5562
5563		if ( typeof selector !== "string" ) {
5564			self = this;
5565			return this.pushStack( jQuery( selector ).filter(function() {
5566				for ( i = 0; i < len; i++ ) {
5567					if ( jQuery.contains( self[ i ], this ) ) {
5568						return true;
5569					}
5570				}
5571			}) );
5572		}
5573
5574		ret = [];
5575		for ( i = 0; i < len; i++ ) {
5576			jQuery.find( selector, this[ i ], ret );
5577		}
5578
5579		// Needed because $( selector, context ) becomes $( context ).find( selector )
5580		ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
5581		ret.selector = ( this.selector ? this.selector + " " : "" ) + selector;
5582		return ret;
5583	},
5584
5585	has: function( target ) {
5586		var i,
5587			targets = jQuery( target, this ),
5588			len = targets.length;
5589
5590		return this.filter(function() {
5591			for ( i = 0; i < len; i++ ) {
5592				if ( jQuery.contains( this, targets[i] ) ) {
5593					return true;
5594				}
5595			}
5596		});
5597	},
5598
5599	not: function( selector ) {
5600		return this.pushStack( winnow(this, selector, false) );
5601	},
5602
5603	filter: function( selector ) {
5604		return this.pushStack( winnow(this, selector, true) );
5605	},
5606
5607	is: function( selector ) {
5608		return !!selector && (
5609			typeof selector === "string" ?
5610				// If this is a positional/relative selector, check membership in the returned set
5611				// so $("p:first").is("p:last") won't return true for a doc with two "p".
5612				rneedsContext.test( selector ) ?
5613					jQuery( selector, this.context ).index( this[0] ) >= 0 :
5614					jQuery.filter( selector, this ).length > 0 :
5615				this.filter( selector ).length > 0 );
5616	},
5617
5618	closest: function( selectors, context ) {
5619		var cur,
5620			i = 0,
5621			l = this.length,
5622			ret = [],
5623			pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
5624				jQuery( selectors, context || this.context ) :
5625				0;
5626
5627		for ( ; i < l; i++ ) {
5628			cur = this[i];
5629
5630			while ( cur && cur.ownerDocument && cur !== context && cur.nodeType !== 11 ) {
5631				if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {
5632					ret.push( cur );
5633					break;
5634				}
5635				cur = cur.parentNode;
5636			}
5637		}
5638
5639		return this.pushStack( ret.length > 1 ? jQuery.unique( ret ) : ret );
5640	},
5641
5642	// Determine the position of an element within
5643	// the matched set of elements
5644	index: function( elem ) {
5645
5646		// No argument, return index in parent
5647		if ( !elem ) {
5648			return ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1;
5649		}
5650
5651		// index in selector
5652		if ( typeof elem === "string" ) {
5653			return jQuery.inArray( this[0], jQuery( elem ) );
5654		}
5655
5656		// Locate the position of the desired element
5657		return jQuery.inArray(
5658			// If it receives a jQuery object, the first element is used
5659			elem.jquery ? elem[0] : elem, this );
5660	},
5661
5662	add: function( selector, context ) {
5663		var set = typeof selector === "string" ?
5664				jQuery( selector, context ) :
5665				jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
5666			all = jQuery.merge( this.get(), set );
5667
5668		return this.pushStack( jQuery.unique(all) );
5669	},
5670
5671	addBack: function( selector ) {
5672		return this.add( selector == null ?
5673			this.prevObject : this.prevObject.filter(selector)
5674		);
5675	}
5676});
5677
5678jQuery.fn.andSelf = jQuery.fn.addBack;
5679
5680function sibling( cur, dir ) {
5681	do {
5682		cur = cur[ dir ];
5683	} while ( cur && cur.nodeType !== 1 );
5684
5685	return cur;
5686}
5687
5688jQuery.each({
5689	parent: function( elem ) {
5690		var parent = elem.parentNode;
5691		return parent && parent.nodeType !== 11 ? parent : null;
5692	},
5693	parents: function( elem ) {
5694		return jQuery.dir( elem, "parentNode" );
5695	},
5696	parentsUntil: function( elem, i, until ) {
5697		return jQuery.dir( elem, "parentNode", until );
5698	},
5699	next: function( elem ) {
5700		return sibling( elem, "nextSibling" );
5701	},
5702	prev: function( elem ) {
5703		return sibling( elem, "previousSibling" );
5704	},
5705	nextAll: function( elem ) {
5706		return jQuery.dir( elem, "nextSibling" );
5707	},
5708	prevAll: function( elem ) {
5709		return jQuery.dir( elem, "previousSibling" );
5710	},
5711	nextUntil: function( elem, i, until ) {
5712		return jQuery.dir( elem, "nextSibling", until );
5713	},
5714	prevUntil: function( elem, i, until ) {
5715		return jQuery.dir( elem, "previousSibling", until );
5716	},
5717	siblings: function( elem ) {
5718		return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
5719	},
5720	children: function( elem ) {
5721		return jQuery.sibling( elem.firstChild );
5722	},
5723	contents: function( elem ) {
5724		return jQuery.nodeName( elem, "iframe" ) ?
5725			elem.contentDocument || elem.contentWindow.document :
5726			jQuery.merge( [], elem.childNodes );
5727	}
5728}, function( name, fn ) {
5729	jQuery.fn[ name ] = function( until, selector ) {
5730		var ret = jQuery.map( this, fn, until );
5731
5732		if ( !runtil.test( name ) ) {
5733			selector = until;
5734		}
5735
5736		if ( selector && typeof selector === "string" ) {
5737			ret = jQuery.filter( selector, ret );
5738		}
5739
5740		ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
5741
5742		if ( this.length > 1 && rparentsprev.test( name ) ) {
5743			ret = ret.reverse();
5744		}
5745
5746		return this.pushStack( ret );
5747	};
5748});
5749
5750jQuery.extend({
5751	filter: function( expr, elems, not ) {
5752		if ( not ) {
5753			expr = ":not(" + expr + ")";
5754		}
5755
5756		return elems.length === 1 ?
5757			jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :
5758			jQuery.find.matches(expr, elems);
5759	},
5760
5761	dir: function( elem, dir, until ) {
5762		var matched = [],
5763			cur = elem[ dir ];
5764
5765		while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
5766			if ( cur.nodeType === 1 ) {
5767				matched.push( cur );
5768			}
5769			cur = cur[dir];
5770		}
5771		return matched;
5772	},
5773
5774	sibling: function( n, elem ) {
5775		var r = [];
5776
5777		for ( ; n; n = n.nextSibling ) {
5778			if ( n.nodeType === 1 && n !== elem ) {
5779				r.push( n );
5780			}
5781		}
5782
5783		return r;
5784	}
5785});
5786
5787// Implement the identical functionality for filter and not
5788function winnow( elements, qualifier, keep ) {
5789
5790	// Can't pass null or undefined to indexOf in Firefox 4
5791	// Set to 0 to skip string check
5792	qualifier = qualifier || 0;
5793
5794	if ( jQuery.isFunction( qualifier ) ) {
5795		return jQuery.grep(elements, function( elem, i ) {
5796			var retVal = !!qualifier.call( elem, i, elem );
5797			return retVal === keep;
5798		});
5799
5800	} else if ( qualifier.nodeType ) {
5801		return jQuery.grep(elements, function( elem ) {
5802			return ( elem === qualifier ) === keep;
5803		});
5804
5805	} else if ( typeof qualifier === "string" ) {
5806		var filtered = jQuery.grep(elements, function( elem ) {
5807			return elem.nodeType === 1;
5808		});
5809
5810		if ( isSimple.test( qualifier ) ) {
5811			return jQuery.filter(qualifier, filtered, !keep);
5812		} else {
5813			qualifier = jQuery.filter( qualifier, filtered );
5814		}
5815	}
5816
5817	return jQuery.grep(elements, function( elem ) {
5818		return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep;
5819	});
5820}
5821function createSafeFragment( document ) {
5822	var list = nodeNames.split( "|" ),
5823		safeFrag = document.createDocumentFragment();
5824
5825	if ( safeFrag.createElement ) {
5826		while ( list.length ) {
5827			safeFrag.createElement(
5828				list.pop()
5829			);
5830		}
5831	}
5832	return safeFrag;
5833}
5834
5835var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" +
5836		"header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
5837	rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g,
5838	rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"),
5839	rleadingWhitespace = /^\s+/,
5840	rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
5841	rtagName = /<([\w:]+)/,
5842	rtbody = /<tbody/i,
5843	rhtml = /<|&#?\w+;/,
5844	rnoInnerhtml = /<(?:script|style|link)/i,
5845	manipulation_rcheckableType = /^(?:checkbox|radio)$/i,
5846	// checked="checked" or checked
5847	rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
5848	rscriptType = /^$|\/(?:java|ecma)script/i,
5849	rscriptTypeMasked = /^true\/(.*)/,
5850	rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,
5851
5852	// We have to close these tags to support XHTML (#13200)
5853	wrapMap = {
5854		option: [ 1, "<select multiple='multiple'>", "</select>" ],
5855		legend: [ 1, "<fieldset>", "</fieldset>" ],
5856		area: [ 1, "<map>", "</map>" ],
5857		param: [ 1, "<object>", "</object>" ],
5858		thead: [ 1, "<table>", "</table>" ],
5859		tr: [ 2, "<table><tbody>", "</tbody></table>" ],
5860		col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
5861		td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
5862
5863		// IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags,
5864		// unless wrapped in a div with non-breaking characters in front of it.
5865		_default: jQuery.support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X<div>", "</div>"  ]
5866	},
5867	safeFragment = createSafeFragment( document ),
5868	fragmentDiv = safeFragment.appendChild( document.createElement("div") );
5869
5870wrapMap.optgroup = wrapMap.option;
5871wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
5872wrapMap.th = wrapMap.td;
5873
5874jQuery.fn.extend({
5875	text: function( value ) {
5876		return jQuery.access( this, function( value ) {
5877			return value === undefined ?
5878				jQuery.text( this ) :
5879				this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );
5880		}, null, value, arguments.length );
5881	},
5882
5883	wrapAll: function( html ) {
5884		if ( jQuery.isFunction( html ) ) {
5885			return this.each(function(i) {
5886				jQuery(this).wrapAll( html.call(this, i) );
5887			});
5888		}
5889
5890		if ( this[0] ) {
5891			// The elements to wrap the target around
5892			var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
5893
5894			if ( this[0].parentNode ) {
5895				wrap.insertBefore( this[0] );
5896			}
5897
5898			wrap.map(function() {
5899				var elem = this;
5900
5901				while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
5902					elem = elem.firstChild;
5903				}
5904
5905				return elem;
5906			}).append( this );
5907		}
5908
5909		return this;
5910	},
5911
5912	wrapInner: function( html ) {
5913		if ( jQuery.isFunction( html ) ) {
5914			return this.each(function(i) {
5915				jQuery(this).wrapInner( html.call(this, i) );
5916			});
5917		}
5918
5919		return this.each(function() {
5920			var self = jQuery( this ),
5921				contents = self.contents();
5922
5923			if ( contents.length ) {
5924				contents.wrapAll( html );
5925
5926			} else {
5927				self.append( html );
5928			}
5929		});
5930	},
5931
5932	wrap: function( html ) {
5933		var isFunction = jQuery.isFunction( html );
5934
5935		return this.each(function(i) {
5936			jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
5937		});
5938	},
5939
5940	unwrap: function() {
5941		return this.parent().each(function() {
5942			if ( !jQuery.nodeName( this, "body" ) ) {
5943				jQuery( this ).replaceWith( this.childNodes );
5944			}
5945		}).end();
5946	},
5947
5948	append: function() {
5949		return this.domManip(arguments, true, function( elem ) {
5950			if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
5951				this.appendChild( elem );
5952			}
5953		});
5954	},
5955
5956	prepend: function() {
5957		return this.domManip(arguments, true, function( elem ) {
5958			if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
5959				this.insertBefore( elem, this.firstChild );
5960			}
5961		});
5962	},
5963
5964	before: function() {
5965		return this.domManip( arguments, false, function( elem ) {
5966			if ( this.parentNode ) {
5967				this.parentNode.insertBefore( elem, this );
5968			}
5969		});
5970	},
5971
5972	after: function() {
5973		return this.domManip( arguments, false, function( elem ) {
5974			if ( this.parentNode ) {
5975				this.parentNode.insertBefore( elem, this.nextSibling );
5976			}
5977		});
5978	},
5979
5980	// keepData is for internal use only--do not document
5981	remove: function( selector, keepData ) {
5982		var elem,
5983			i = 0;
5984
5985		for ( ; (elem = this[i]) != null; i++ ) {
5986			if ( !selector || jQuery.filter( selector, [ elem ] ).length > 0 ) {
5987				if ( !keepData && elem.nodeType === 1 ) {
5988					jQuery.cleanData( getAll( elem ) );
5989				}
5990
5991				if ( elem.parentNode ) {
5992					if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) {
5993						setGlobalEval( getAll( elem, "script" ) );
5994					}
5995					elem.parentNode.removeChild( elem );
5996				}
5997			}
5998		}
5999
6000		return this;
6001	},
6002
6003	empty: function() {
6004		var elem,
6005			i = 0;
6006
6007		for ( ; (elem = this[i]) != null; i++ ) {
6008			// Remove element nodes and prevent memory leaks
6009			if ( elem.nodeType === 1 ) {
6010				jQuery.cleanData( getAll( elem, false ) );
6011			}
6012
6013			// Remove any remaining nodes
6014			while ( elem.firstChild ) {
6015				elem.removeChild( elem.firstChild );
6016			}
6017
6018			// If this is a select, ensure that it displays empty (#12336)
6019			// Support: IE<9
6020			if ( elem.options && jQuery.nodeName( elem, "select" ) ) {
6021				elem.options.length = 0;
6022			}
6023		}
6024
6025		return this;
6026	},
6027
6028	clone: function( dataAndEvents, deepDataAndEvents ) {
6029		dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
6030		deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
6031
6032		return this.map( function () {
6033			return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
6034		});
6035	},
6036
6037	html: function( value ) {
6038		return jQuery.access( this, function( value ) {
6039			var elem = this[0] || {},
6040				i = 0,
6041				l = this.length;
6042
6043			if ( value === undefined ) {
6044				return elem.nodeType === 1 ?
6045					elem.innerHTML.replace( rinlinejQuery, "" ) :
6046					undefined;
6047			}
6048
6049			// See if we can take a shortcut and just use innerHTML
6050			if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
6051				( jQuery.support.htmlSerialize || !rnoshimcache.test( value )  ) &&
6052				( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
6053				!wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) {
6054
6055				value = value.replace( rxhtmlTag, "<$1></$2>" );
6056
6057				try {
6058					for (; i < l; i++ ) {
6059						// Remove element nodes and prevent memory leaks
6060						elem = this[i] || {};
6061						if ( elem.nodeType === 1 ) {
6062							jQuery.cleanData( getAll( elem, false ) );
6063							elem.innerHTML = value;
6064						}
6065					}
6066
6067					elem = 0;
6068
6069				// If using innerHTML throws an exception, use the fallback method
6070				} catch(e) {}
6071			}
6072
6073			if ( elem ) {
6074				this.empty().append( value );
6075			}
6076		}, null, value, arguments.length );
6077	},
6078
6079	replaceWith: function( value ) {
6080		var isFunc = jQuery.isFunction( value );
6081
6082		// Make sure that the elements are removed from the DOM before they are inserted
6083		// this can help fix replacing a parent with child elements
6084		if ( !isFunc && typeof value !== "string" ) {
6085			value = jQuery( value ).not( this ).detach();
6086		}
6087
6088		return this.domManip( [ value ], true, function( elem ) {
6089			var next = this.nextSibling,
6090				parent = this.parentNode;
6091
6092			if ( parent ) {
6093				jQuery( this ).remove();
6094				parent.insertBefore( elem, next );
6095			}
6096		});
6097	},
6098
6099	detach: function( selector ) {
6100		return this.remove( selector, true );
6101	},
6102
6103	domManip: function( args, table, callback ) {
6104
6105		// Flatten any nested arrays
6106		args = core_concat.apply( [], args );
6107
6108		var first, node, hasScripts,
6109			scripts, doc, fragment,
6110			i = 0,
6111			l = this.length,
6112			set = this,
6113			iNoClone = l - 1,
6114			value = args[0],
6115			isFunction = jQuery.isFunction( value );
6116
6117		// We can't cloneNode fragments that contain checked, in WebKit
6118		if ( isFunction || !( l <= 1 || typeof value !== "string" || jQuery.support.checkClone || !rchecked.test( value ) ) ) {
6119			return this.each(function( index ) {
6120				var self = set.eq( index );
6121				if ( isFunction ) {
6122					args[0] = value.call( this, index, table ? self.html() : undefined );
6123				}
6124				self.domManip( args, table, callback );
6125			});
6126		}
6127
6128		if ( l ) {
6129			fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this );
6130			first = fragment.firstChild;
6131
6132			if ( fragment.childNodes.length === 1 ) {
6133				fragment = first;
6134			}
6135
6136			if ( first ) {
6137				table = table && jQuery.nodeName( first, "tr" );
6138				scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
6139				hasScripts = scripts.length;
6140
6141				// Use the original fragment for the last item instead of the first because it can end up
6142				// being emptied incorrectly in certain situations (#8070).
6143				for ( ; i < l; i++ ) {
6144					node = fragment;
6145
6146					if ( i !== iNoClone ) {
6147						node = jQuery.clone( node, true, true );
6148
6149						// Keep references to cloned scripts for later restoration
6150						if ( hasScripts ) {
6151							jQuery.merge( scripts, getAll( node, "script" ) );
6152						}
6153					}
6154
6155					callback.call(
6156						table && jQuery.nodeName( this[i], "table" ) ?
6157							findOrAppend( this[i], "tbody" ) :
6158							this[i],
6159						node,
6160						i
6161					);
6162				}
6163
6164				if ( hasScripts ) {
6165					doc = scripts[ scripts.length - 1 ].ownerDocument;
6166
6167					// Reenable scripts
6168					jQuery.map( scripts, restoreScript );
6169
6170					// Evaluate executable scripts on first document insertion
6171					for ( i = 0; i < hasScripts; i++ ) {
6172						node = scripts[ i ];
6173						if ( rscriptType.test( node.type || "" ) &&
6174							!jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) {
6175
6176							if ( node.src ) {
6177								// Hope ajax is available...
6178								jQuery.ajax({
6179									url: node.src,
6180									type: "GET",
6181									dataType: "script",
6182									async: false,
6183									global: false,
6184									"throws": true
6185								});
6186							} else {
6187								jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) );
6188							}
6189						}
6190					}
6191				}
6192
6193				// Fix #11809: Avoid leaking memory
6194				fragment = first = null;
6195			}
6196		}
6197
6198		return this;
6199	}
6200});
6201
6202function findOrAppend( elem, tag ) {
6203	return elem.getElementsByTagName( tag )[0] || elem.appendChild( elem.ownerDocument.createElement( tag ) );
6204}
6205
6206// Replace/restore the type attribute of script elements for safe DOM manipulation
6207function disableScript( elem ) {
6208	var attr = elem.getAttributeNode("type");
6209	elem.type = ( attr && attr.specified ) + "/" + elem.type;
6210	return elem;
6211}
6212function restoreScript( elem ) {
6213	var match = rscriptTypeMasked.exec( elem.type );
6214	if ( match ) {
6215		elem.type = match[1];
6216	} else {
6217		elem.removeAttribute("type");
6218	}
6219	return elem;
6220}
6221
6222// Mark scripts as having already been evaluated
6223function setGlobalEval( elems, refElements ) {
6224	var elem,
6225		i = 0;
6226	for ( ; (elem = elems[i]) != null; i++ ) {
6227		jQuery._data( elem, "globalEval", !refElements || jQuery._data( refElements[i], "globalEval" ) );
6228	}
6229}
6230
6231function cloneCopyEvent( src, dest ) {
6232
6233	if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
6234		return;
6235	}
6236
6237	var type, i, l,
6238		oldData = jQuery._data( src ),
6239		curData = jQuery._data( dest, oldData ),
6240		events = oldData.events;
6241
6242	if ( events ) {
6243		delete curData.handle;
6244		curData.events = {};
6245
6246		for ( type in events ) {
6247			for ( i = 0, l = events[ type ].length; i < l; i++ ) {
6248				jQuery.event.add( dest, type, events[ type ][ i ] );
6249			}
6250		}
6251	}
6252
6253	// make the cloned public data object a copy from the original
6254	if ( curData.data ) {
6255		curData.data = jQuery.extend( {}, curData.data );
6256	}
6257}
6258
6259function fixCloneNodeIssues( src, dest ) {
6260	var nodeName, e, data;
6261
6262	// We do not need to do anything for non-Elements
6263	if ( dest.nodeType !== 1 ) {
6264		return;
6265	}
6266
6267	nodeName = dest.nodeName.toLowerCase();
6268
6269	// IE6-8 copies events bound via attachEvent when using cloneNode.
6270	if ( !jQuery.support.noCloneEvent && dest[ jQuery.expando ] ) {
6271		data = jQuery._data( dest );
6272
6273		for ( e in data.events ) {
6274			jQuery.removeEvent( dest, e, data.handle );
6275		}
6276
6277		// Event data gets referenced instead of copied if the expando gets copied too
6278		dest.removeAttribute( jQuery.expando );
6279	}
6280
6281	// IE blanks contents when cloning scripts, and tries to evaluate newly-set text
6282	if ( nodeName === "script" && dest.text !== src.text ) {
6283		disableScript( dest ).text = src.text;
6284		restoreScript( dest );
6285
6286	// IE6-10 improperly clones children of object elements using classid.
6287	// IE10 throws NoModificationAllowedError if parent is null, #12132.
6288	} else if ( nodeName === "object" ) {
6289		if ( dest.parentNode ) {
6290			dest.outerHTML = src.outerHTML;
6291		}
6292
6293		// This path appears unavoidable for IE9. When cloning an object
6294		// element in IE9, the outerHTML strategy above is not sufficient.
6295		// If the src has innerHTML and the destination does not,
6296		// copy the src.innerHTML into the dest.innerHTML. #10324
6297		if ( jQuery.support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) {
6298			dest.innerHTML = src.innerHTML;
6299		}
6300
6301	} else if ( nodeName === "input" && manipulation_rcheckableType.test( src.type ) ) {
6302		// IE6-8 fails to persist the checked state of a cloned checkbox
6303		// or radio button. Worse, IE6-7 fail to give the cloned element
6304		// a checked appearance if the defaultChecked value isn't also set
6305
6306		dest.defaultChecked = dest.checked = src.checked;
6307
6308		// IE6-7 get confused and end up setting the value of a cloned
6309		// checkbox/radio button to an empty string instead of "on"
6310		if ( dest.value !== src.value ) {
6311			dest.value = src.value;
6312		}
6313
6314	// IE6-8 fails to return the selected option to the default selected
6315	// state when cloning options
6316	} else if ( nodeName === "option" ) {
6317		dest.defaultSelected = dest.selected = src.defaultSelected;
6318
6319	// IE6-8 fails to set the defaultValue to the correct value when
6320	// cloning other types of input fields
6321	} else if ( nodeName === "input" || nodeName === "textarea" ) {
6322		dest.defaultValue = src.defaultValue;
6323	}
6324}
6325
6326jQuery.each({
6327	appendTo: "append",
6328	prependTo: "prepend",
6329	insertBefore: "before",
6330	insertAfter: "after",
6331	replaceAll: "replaceWith"
6332}, function( name, original ) {
6333	jQuery.fn[ name ] = function( selector ) {
6334		var elems,
6335			i = 0,
6336			ret = [],
6337			insert = jQuery( selector ),
6338			last = insert.length - 1;
6339
6340		for ( ; i <= last; i++ ) {
6341			elems = i === last ? this : this.clone(true);
6342			jQuery( insert[i] )[ original ]( elems );
6343
6344			// Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get()
6345			core_push.apply( ret, elems.get() );
6346		}
6347
6348		return this.pushStack( ret );
6349	};
6350});
6351
6352function getAll( context, tag ) {
6353	var elems, elem,
6354		i = 0,
6355		found = typeof context.getElementsByTagName !== core_strundefined ? context.getElementsByTagName( tag || "*" ) :
6356			typeof context.querySelectorAll !== core_strundefined ? context.querySelectorAll( tag || "*" ) :
6357			undefined;
6358
6359	if ( !found ) {
6360		for ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) {
6361			if ( !tag || jQuery.nodeName( elem, tag ) ) {
6362				found.push( elem );
6363			} else {
6364				jQuery.merge( found, getAll( elem, tag ) );
6365			}
6366		}
6367	}
6368
6369	return tag === undefined || tag && jQuery.nodeName( context, tag ) ?
6370		jQuery.merge( [ context ], found ) :
6371		found;
6372}
6373
6374// Used in buildFragment, fixes the defaultChecked property
6375function fixDefaultChecked( elem ) {
6376	if ( manipulation_rcheckableType.test( elem.type ) ) {
6377		elem.defaultChecked = elem.checked;
6378	}
6379}
6380
6381jQuery.extend({
6382	clone: function( elem, dataAndEvents, deepDataAndEvents ) {
6383		var destElements, node, clone, i, srcElements,
6384			inPage = jQuery.contains( elem.ownerDocument, elem );
6385
6386		if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) {
6387			clone = elem.cloneNode( true );
6388
6389		// IE<=8 does not properly clone detached, unknown element nodes
6390		} else {
6391			fragmentDiv.innerHTML = elem.outerHTML;
6392			fragmentDiv.removeChild( clone = fragmentDiv.firstChild );
6393		}
6394
6395		if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&
6396				(elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
6397
6398			// We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2
6399			destElements = getAll( clone );
6400			srcElements = getAll( elem );
6401
6402			// Fix all IE cloning issues
6403			for ( i = 0; (node = srcElements[i]) != null; ++i ) {
6404				// Ensure that the destination node is not null; Fixes #9587
6405				if ( destElements[i] ) {
6406					fixCloneNodeIssues( node, destElements[i] );
6407				}
6408			}
6409		}
6410
6411		// Copy the events from the original to the clone
6412		if ( dataAndEvents ) {
6413			if ( deepDataAndEvents ) {
6414				srcElements = srcElements || getAll( elem );
6415				destElements = destElements || getAll( clone );
6416
6417				for ( i = 0; (node = srcElements[i]) != null; i++ ) {
6418					cloneCopyEvent( node, destElements[i] );
6419				}
6420			} else {
6421				cloneCopyEvent( elem, clone );
6422			}
6423		}
6424
6425		// Preserve script evaluation history
6426		destElements = getAll( clone, "script" );
6427		if ( destElements.length > 0 ) {
6428			setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
6429		}
6430
6431		destElements = srcElements = node = null;
6432
6433		// Return the cloned set
6434		return clone;
6435	},
6436
6437	buildFragment: function( elems, context, scripts, selection ) {
6438		var j, elem, contains,
6439			tmp, tag, tbody, wrap,
6440			l = elems.length,
6441
6442			// Ensure a safe fragment
6443			safe = createSafeFragment( context ),
6444
6445			nodes = [],
6446			i = 0;
6447
6448		for ( ; i < l; i++ ) {
6449			elem = elems[ i ];
6450
6451			if ( elem || elem === 0 ) {
6452
6453				// Add nodes directly
6454				if ( jQuery.type( elem ) === "object" ) {
6455					jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
6456
6457				// Convert non-html into a text node
6458				} else if ( !rhtml.test( elem ) ) {
6459					nodes.push( context.createTextNode( elem ) );
6460
6461				// Convert html into DOM nodes
6462				} else {
6463					tmp = tmp || safe.appendChild( context.createElement("div") );
6464
6465					// Deserialize a standard representation
6466					tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase();
6467					wrap = wrapMap[ tag ] || wrapMap._default;
6468
6469					tmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, "<$1></$2>" ) + wrap[2];
6470
6471					// Descend through wrappers to the right content
6472					j = wrap[0];
6473					while ( j-- ) {
6474						tmp = tmp.lastChild;
6475					}
6476
6477					// Manually add leading whitespace removed by IE
6478					if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
6479						nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) );
6480					}
6481
6482					// Remove IE's autoinserted <tbody> from table fragments
6483					if ( !jQuery.support.tbody ) {
6484
6485						// String was a <table>, *may* have spurious <tbody>
6486						elem = tag === "table" && !rtbody.test( elem ) ?
6487							tmp.firstChild :
6488
6489							// String was a bare <thead> or <tfoot>
6490							wrap[1] === "<table>" && !rtbody.test( elem ) ?
6491								tmp :
6492								0;
6493
6494						j = elem && elem.childNodes.length;
6495						while ( j-- ) {
6496							if ( jQuery.nodeName( (tbody = elem.childNodes[j]), "tbody" ) && !tbody.childNodes.length ) {
6497								elem.removeChild( tbody );
6498							}
6499						}
6500					}
6501
6502					jQuery.merge( nodes, tmp.childNodes );
6503
6504					// Fix #12392 for WebKit and IE > 9
6505					tmp.textContent = "";
6506
6507					// Fix #12392 for oldIE
6508					while ( tmp.firstChild ) {
6509						tmp.removeChild( tmp.firstChild );
6510					}
6511
6512					// Remember the top-level container for proper cleanup
6513					tmp = safe.lastChild;
6514				}
6515			}
6516		}
6517
6518		// Fix #11356: Clear elements from fragment
6519		if ( tmp ) {
6520			safe.removeChild( tmp );
6521		}
6522
6523		// Reset defaultChecked for any radios and checkboxes
6524		// about to be appended to the DOM in IE 6/7 (#8060)
6525		if ( !jQuery.support.appendChecked ) {
6526			jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked );
6527		}
6528
6529		i = 0;
6530		while ( (elem = nodes[ i++ ]) ) {
6531
6532			// #4087 - If origin and destination elements are the same, and this is
6533			// that element, do not do anything
6534			if ( selection && jQuery.inArray( elem, selection ) !== -1 ) {
6535				continue;
6536			}
6537
6538			contains = jQuery.contains( elem.ownerDocument, elem );
6539
6540			// Append to fragment
6541			tmp = getAll( safe.appendChild( elem ), "script" );
6542
6543			// Preserve script evaluation history
6544			if ( contains ) {
6545				setGlobalEval( tmp );
6546			}
6547
6548			// Capture executables
6549			if ( scripts ) {
6550				j = 0;
6551				while ( (elem = tmp[ j++ ]) ) {
6552					if ( rscriptType.test( elem.type || "" ) ) {
6553						scripts.push( elem );
6554					}
6555				}
6556			}
6557		}
6558
6559		tmp = null;
6560
6561		return safe;
6562	},
6563
6564	cleanData: function( elems, /* internal */ acceptData ) {
6565		var elem, type, id, data,
6566			i = 0,
6567			internalKey = jQuery.expando,
6568			cache = jQuery.cache,
6569			deleteExpando = jQuery.support.deleteExpando,
6570			special = jQuery.event.special;
6571
6572		for ( ; (elem = elems[i]) != null; i++ ) {
6573
6574			if ( acceptData || jQuery.acceptData( elem ) ) {
6575
6576				id = elem[ internalKey ];
6577				data = id && cache[ id ];
6578
6579				if ( data ) {
6580					if ( data.events ) {
6581						for ( type in data.events ) {
6582							if ( special[ type ] ) {
6583								jQuery.event.remove( elem, type );
6584
6585							// This is a shortcut to avoid jQuery.event.remove's overhead
6586							} else {
6587								jQuery.removeEvent( elem, type, data.handle );
6588							}
6589						}
6590					}
6591
6592					// Remove cache only if it was not already removed by jQuery.event.remove
6593					if ( cache[ id ] ) {
6594
6595						delete cache[ id ];
6596
6597						// IE does not allow us to delete expando properties from nodes,
6598						// nor does it have a removeAttribute function on Document nodes;
6599						// we must handle all of these cases
6600						if ( deleteExpando ) {
6601							delete elem[ internalKey ];
6602
6603						} else if ( typeof elem.removeAttribute !== core_strundefined ) {
6604							elem.removeAttribute( internalKey );
6605
6606						} else {
6607							elem[ internalKey ] = null;
6608						}
6609
6610						core_deletedIds.push( id );
6611					}
6612				}
6613			}
6614		}
6615	}
6616});
6617var iframe, getStyles, curCSS,
6618	ralpha = /alpha\([^)]*\)/i,
6619	ropacity = /opacity\s*=\s*([^)]*)/,
6620	rposition = /^(top|right|bottom|left)$/,
6621	// swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
6622	// see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
6623	rdisplayswap = /^(none|table(?!-c[ea]).+)/,
6624	rmargin = /^margin/,
6625	rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ),
6626	rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ),
6627	rrelNum = new RegExp( "^([+-])=(" + core_pnum + ")", "i" ),
6628	elemdisplay = { BODY: "block" },
6629
6630	cssShow = { position: "absolute", visibility: "hidden", display: "block" },
6631	cssNormalTransform = {
6632		letterSpacing: 0,
6633		fontWeight: 400
6634	},
6635
6636	cssExpand = [ "Top", "Right", "Bottom", "Left" ],
6637	cssPrefixes = [ "Webkit", "O", "Moz", "ms" ];
6638
6639// return a css property mapped to a potentially vendor prefixed property
6640function vendorPropName( style, name ) {
6641
6642	// shortcut for names that are not vendor prefixed
6643	if ( name in style ) {
6644		return name;
6645	}
6646
6647	// check for vendor prefixed names
6648	var capName = name.charAt(0).toUpperCase() + name.slice(1),
6649		origName = name,
6650		i = cssPrefixes.length;
6651
6652	while ( i-- ) {
6653		name = cssPrefixes[ i ] + capName;
6654		if ( name in style ) {
6655			return name;
6656		}
6657	}
6658
6659	return origName;
6660}
6661
6662function isHidden( elem, el ) {
6663	// isHidden might be called from jQuery#filter function;
6664	// in that case, element will be second argument
6665	elem = el || elem;
6666	return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );
6667}
6668
6669function showHide( elements, show ) {
6670	var display, elem, hidden,
6671		values = [],
6672		index = 0,
6673		length = elements.length;
6674
6675	for ( ; index < length; index++ ) {
6676		elem = elements[ index ];
6677		if ( !elem.style ) {
6678			continue;
6679		}
6680
6681		values[ index ] = jQuery._data( elem, "olddisplay" );
6682		display = elem.style.display;
6683		if ( show ) {
6684			// Reset the inline display of this element to learn if it is
6685			// being hidden by cascaded rules or not
6686			if ( !values[ index ] && display === "none" ) {
6687				elem.style.display = "";
6688			}
6689
6690			// Set elements which have been overridden with display: none
6691			// in a stylesheet to whatever the default browser style is
6692			// for such an element
6693			if ( elem.style.display === "" && isHidden( elem ) ) {
6694				values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) );
6695			}
6696		} else {
6697
6698			if ( !values[ index ] ) {
6699				hidden = isHidden( elem );
6700
6701				if ( display && display !== "none" || !hidden ) {
6702					jQuery._data( elem, "olddisplay", hidden ? display : jQuery.css( elem, "display" ) );
6703				}
6704			}
6705		}
6706	}
6707
6708	// Set the display of most of the elements in a second loop
6709	// to avoid the constant reflow
6710	for ( index = 0; index < length; index++ ) {
6711		elem = elements[ index ];
6712		if ( !elem.style ) {
6713			continue;
6714		}
6715		if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
6716			elem.style.display = show ? values[ index ] || "" : "none";
6717		}
6718	}
6719
6720	return elements;
6721}
6722
6723jQuery.fn.extend({
6724	css: function( name, value ) {
6725		return jQuery.access( this, function( elem, name, value ) {
6726			var len, styles,
6727				map = {},
6728				i = 0;
6729
6730			if ( jQuery.isArray( name ) ) {
6731				styles = getStyles( elem );
6732				len = name.length;
6733
6734				for ( ; i < len; i++ ) {
6735					map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
6736				}
6737
6738				return map;
6739			}
6740
6741			return value !== undefined ?
6742				jQuery.style( elem, name, value ) :
6743				jQuery.css( elem, name );
6744		}, name, value, arguments.length > 1 );
6745	},
6746	show: function() {
6747		return showHide( this, true );
6748	},
6749	hide: function() {
6750		return showHide( this );
6751	},
6752	toggle: function( state ) {
6753		var bool = typeof state === "boolean";
6754
6755		return this.each(function() {
6756			if ( bool ? state : isHidden( this ) ) {
6757				jQuery( this ).show();
6758			} else {
6759				jQuery( this ).hide();
6760			}
6761		});
6762	}
6763});
6764
6765jQuery.extend({
6766	// Add in style property hooks for overriding the default
6767	// behavior of getting and setting a style property
6768	cssHooks: {
6769		opacity: {
6770			get: function( elem, computed ) {
6771				if ( computed ) {
6772					// We should always get a number back from opacity
6773					var ret = curCSS( elem, "opacity" );
6774					return ret === "" ? "1" : ret;
6775				}
6776			}
6777		}
6778	},
6779
6780	// Exclude the following css properties to add px
6781	cssNumber: {
6782		"columnCount": true,
6783		"fillOpacity": true,
6784		"fontWeight": true,
6785		"lineHeight": true,
6786		"opacity": true,
6787		"orphans": true,
6788		"widows": true,
6789		"zIndex": true,
6790		"zoom": true
6791	},
6792
6793	// Add in properties whose names you wish to fix before
6794	// setting or getting the value
6795	cssProps: {
6796		// normalize float css property
6797		"float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat"
6798	},
6799
6800	// Get and set the style property on a DOM Node
6801	style: function( elem, name, value, extra ) {
6802		// Don't set styles on text and comment nodes
6803		if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
6804			return;
6805		}
6806
6807		// Make sure that we're working with the right name
6808		var ret, type, hooks,
6809			origName = jQuery.camelCase( name ),
6810			style = elem.style;
6811
6812		name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
6813
6814		// gets hook for the prefixed version
6815		// followed by the unprefixed version
6816		hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
6817
6818		// Check if we're setting a value
6819		if ( value !== undefined ) {
6820			type = typeof value;
6821
6822			// convert relative number strings (+= or -=) to relative numbers. #7345
6823			if ( type === "string" && (ret = rrelNum.exec( value )) ) {
6824				value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
6825				// Fixes bug #9237
6826				type = "number";
6827			}
6828
6829			// Make sure that NaN and null values aren't set. See: #7116
6830			if ( value == null || type === "number" && isNaN( value ) ) {
6831				return;
6832			}
6833
6834			// If a number was passed in, add 'px' to the (except for certain CSS properties)
6835			if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
6836				value += "px";
6837			}
6838
6839			// Fixes #8908, it can be done more correctly by specifing setters in cssHooks,
6840			// but it would mean to define eight (for every problematic property) identical functions
6841			if ( !jQuery.support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) {
6842				style[ name ] = "inherit";
6843			}
6844
6845			// If a hook was provided, use that value, otherwise just set the specified value
6846			if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
6847
6848				// Wrapped to prevent IE from throwing errors when 'invalid' values are provided
6849				// Fixes bug #5509
6850				try {
6851					style[ name ] = value;
6852				} catch(e) {}
6853			}
6854
6855		} else {
6856			// If a hook was provided get the non-computed value from there
6857			if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
6858				return ret;
6859			}
6860
6861			// Otherwise just get the value from the style object
6862			return style[ name ];
6863		}
6864	},
6865
6866	css: function( elem, name, extra, styles ) {
6867		var num, val, hooks,
6868			origName = jQuery.camelCase( name );
6869
6870		// Make sure that we're working with the right name
6871		name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
6872
6873		// gets hook for the prefixed version
6874		// followed by the unprefixed version
6875		hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
6876
6877		// If a hook was provided get the computed value from there
6878		if ( hooks && "get" in hooks ) {
6879			val = hooks.get( elem, true, extra );
6880		}
6881
6882		// Otherwise, if a way to get the computed value exists, use that
6883		if ( val === undefined ) {
6884			val = curCSS( elem, name, styles );
6885		}
6886
6887		//convert "normal" to computed value
6888		if ( val === "normal" && name in cssNormalTransform ) {
6889			val = cssNormalTransform[ name ];
6890		}
6891
6892		// Return, converting to number if forced or a qualifier was provided and val looks numeric
6893		if ( extra === "" || extra ) {
6894			num = parseFloat( val );
6895			return extra === true || jQuery.isNumeric( num ) ? num || 0 : val;
6896		}
6897		return val;
6898	},
6899
6900	// A method for quickly swapping in/out CSS properties to get correct calculations
6901	swap: function( elem, options, callback, args ) {
6902		var ret, name,
6903			old = {};
6904
6905		// Remember the old values, and insert the new ones
6906		for ( name in options ) {
6907			old[ name ] = elem.style[ name ];
6908			elem.style[ name ] = options[ name ];
6909		}
6910
6911		ret = callback.apply( elem, args || [] );
6912
6913		// Revert the old values
6914		for ( name in options ) {
6915			elem.style[ name ] = old[ name ];
6916		}
6917
6918		return ret;
6919	}
6920});
6921
6922// NOTE: we've included the "window" in window.getComputedStyle
6923// because jsdom on node.js will break without it.
6924if ( window.getComputedStyle ) {
6925	getStyles = function( elem ) {
6926		return window.getComputedStyle( elem, null );
6927	};
6928
6929	curCSS = function( elem, name, _computed ) {
6930		var width, minWidth, maxWidth,
6931			computed = _computed || getStyles( elem ),
6932
6933			// getPropertyValue is only needed for .css('filter') in IE9, see #12537
6934			ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined,
6935			style = elem.style;
6936
6937		if ( computed ) {
6938
6939			if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
6940				ret = jQuery.style( elem, name );
6941			}
6942
6943			// A tribute to the "awesome hack by Dean Edwards"
6944			// Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right
6945			// Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels
6946			// this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
6947			if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
6948
6949				// Remember the original values
6950				width = style.width;
6951				minWidth = style.minWidth;
6952				maxWidth = style.maxWidth;
6953
6954				// Put in the new values to get a computed value out
6955				style.minWidth = style.maxWidth = style.width = ret;
6956				ret = computed.width;
6957
6958				// Revert the changed values
6959				style.width = width;
6960				style.minWidth = minWidth;
6961				style.maxWidth = maxWidth;
6962			}
6963		}
6964
6965		return ret;
6966	};
6967} else if ( document.documentElement.currentStyle ) {
6968	getStyles = function( elem ) {
6969		return elem.currentStyle;
6970	};
6971
6972	curCSS = function( elem, name, _computed ) {
6973		var left, rs, rsLeft,
6974			computed = _computed || getStyles( elem ),
6975			ret = computed ? computed[ name ] : undefined,
6976			style = elem.style;
6977
6978		// Avoid setting ret to empty string here
6979		// so we don't default to auto
6980		if ( ret == null && style && style[ name ] ) {
6981			ret = style[ name ];
6982		}
6983
6984		// From the awesome hack by Dean Edwards
6985		// http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
6986
6987		// If we're not dealing with a regular pixel number
6988		// but a number that has a weird ending, we need to convert it to pixels
6989		// but not position css attributes, as those are proportional to the parent element instead
6990		// and we can't measure the parent instead because it might trigger a "stacking dolls" problem
6991		if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) {
6992
6993			// Remember the original values
6994			left = style.left;
6995			rs = elem.runtimeStyle;
6996			rsLeft = rs && rs.left;
6997
6998			// Put in the new values to get a computed value out
6999			if ( rsLeft ) {
7000				rs.left = elem.currentStyle.left;
7001			}
7002			style.left = name === "fontSize" ? "1em" : ret;
7003			ret = style.pixelLeft + "px";
7004
7005			// Revert the changed values
7006			style.left = left;
7007			if ( rsLeft ) {
7008				rs.left = rsLeft;
7009			}
7010		}
7011
7012		return ret === "" ? "auto" : ret;
7013	};
7014}
7015
7016function setPositiveNumber( elem, value, subtract ) {
7017	var matches = rnumsplit.exec( value );
7018	return matches ?
7019		// Guard against undefined "subtract", e.g., when used as in cssHooks
7020		Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
7021		value;
7022}
7023
7024function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
7025	var i = extra === ( isBorderBox ? "border" : "content" ) ?
7026		// If we already have the right measurement, avoid augmentation
7027		4 :
7028		// Otherwise initialize for horizontal or vertical properties
7029		name === "width" ? 1 : 0,
7030
7031		val = 0;
7032
7033	for ( ; i < 4; i += 2 ) {
7034		// both box models exclude margin, so add it if we want it
7035		if ( extra === "margin" ) {
7036			val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
7037		}
7038
7039		if ( isBorderBox ) {
7040			// border-box includes padding, so remove it if we want content
7041			if ( extra === "content" ) {
7042				val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
7043			}
7044
7045			// at this point, extra isn't border nor margin, so remove border
7046			if ( extra !== "margin" ) {
7047				val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
7048			}
7049		} else {
7050			// at this point, extra isn't content, so add padding
7051			val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
7052
7053			// at this point, extra isn't content nor padding, so add border
7054			if ( extra !== "padding" ) {
7055				val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
7056			}
7057		}
7058	}
7059
7060	return val;
7061}
7062
7063function getWidthOrHeight( elem, name, extra ) {
7064
7065	// Start with offset property, which is equivalent to the border-box value
7066	var valueIsBorderBox = true,
7067		val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
7068		styles = getStyles( elem ),
7069		isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
7070
7071	// some non-html elements return undefined for offsetWidth, so check for null/undefined
7072	// svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
7073	// MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
7074	if ( val <= 0 || val == null ) {
7075		// Fall back to computed then uncomputed css if necessary
7076		val = curCSS( elem, name, styles );
7077		if ( val < 0 || val == null ) {
7078			val = elem.style[ name ];
7079		}
7080
7081		// Computed unit is not pixels. Stop here and return.
7082		if ( rnumnonpx.test(val) ) {
7083			return val;
7084		}
7085
7086		// we need the check for style in case a browser which returns unreliable values
7087		// for getComputedStyle silently falls back to the reliable elem.style
7088		valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] );
7089
7090		// Normalize "", auto, and prepare for extra
7091		val = parseFloat( val ) || 0;
7092	}
7093
7094	// use the active box-sizing model to add/subtract irrelevant styles
7095	return ( val +
7096		augmentWidthOrHeight(
7097			elem,
7098			name,
7099			extra || ( isBorderBox ? "border" : "content" ),
7100			valueIsBorderBox,
7101			styles
7102		)
7103	) + "px";
7104}
7105
7106// Try to determine the default display value of an element
7107function css_defaultDisplay( nodeName ) {
7108	var doc = document,
7109		display = elemdisplay[ nodeName ];
7110
7111	if ( !display ) {
7112		display = actualDisplay( nodeName, doc );
7113
7114		// If the simple way fails, read from inside an iframe
7115		if ( display === "none" || !display ) {
7116			// Use the already-created iframe if possible
7117			iframe = ( iframe ||
7118				jQuery("<iframe frameborder='0' width='0' height='0'/>")
7119				.css( "cssText", "display:block !important" )
7120			).appendTo( doc.documentElement );
7121
7122			// Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse
7123			doc = ( iframe[0].contentWindow || iframe[0].contentDocument ).document;
7124			doc.write("<!doctype html><html><body>");
7125			doc.close();
7126
7127			display = actualDisplay( nodeName, doc );
7128			iframe.detach();
7129		}
7130
7131		// Store the correct default display
7132		elemdisplay[ nodeName ] = display;
7133	}
7134
7135	return display;
7136}
7137
7138// Called ONLY from within css_defaultDisplay
7139function actualDisplay( name, doc ) {
7140	var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),
7141		display = jQuery.css( elem[0], "display" );
7142	elem.remove();
7143	return display;
7144}
7145
7146jQuery.each([ "height", "width" ], function( i, name ) {
7147	jQuery.cssHooks[ name ] = {
7148		get: function( elem, computed, extra ) {
7149			if ( computed ) {
7150				// certain elements can have dimension info if we invisibly show them
7151				// however, it must have a current display style that would benefit from this
7152				return elem.offsetWidth === 0 && rdisplayswap.test( jQuery.css( elem, "display" ) ) ?
7153					jQuery.swap( elem, cssShow, function() {
7154						return getWidthOrHeight( elem, name, extra );
7155					}) :
7156					getWidthOrHeight( elem, name, extra );
7157			}
7158		},
7159
7160		set: function( elem, value, extra ) {
7161			var styles = extra && getStyles( elem );
7162			return setPositiveNumber( elem, value, extra ?
7163				augmentWidthOrHeight(
7164					elem,
7165					name,
7166					extra,
7167					jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
7168					styles
7169				) : 0
7170			);
7171		}
7172	};
7173});
7174
7175if ( !jQuery.support.opacity ) {
7176	jQuery.cssHooks.opacity = {
7177		get: function( elem, computed ) {
7178			// IE uses filters for opacity
7179			return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
7180				( 0.01 * parseFloat( RegExp.$1 ) ) + "" :
7181				computed ? "1" : "";
7182		},
7183
7184		set: function( elem, value ) {
7185			var style = elem.style,
7186				currentStyle = elem.currentStyle,
7187				opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "",
7188				filter = currentStyle && currentStyle.filter || style.filter || "";
7189
7190			// IE has trouble with opacity if it does not have layout
7191			// Force it by setting the zoom level
7192			style.zoom = 1;
7193
7194			// if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652
7195			// if value === "", then remove inline opacity #12685
7196			if ( ( value >= 1 || value === "" ) &&
7197					jQuery.trim( filter.replace( ralpha, "" ) ) === "" &&
7198					style.removeAttribute ) {
7199
7200				// Setting style.filter to null, "" & " " still leave "filter:" in the cssText
7201				// if "filter:" is present at all, clearType is disabled, we want to avoid this
7202				// style.removeAttribute is IE Only, but so apparently is this code path...
7203				style.removeAttribute( "filter" );
7204
7205				// if there is no filter style applied in a css rule or unset inline opacity, we are done
7206				if ( value === "" || currentStyle && !currentStyle.filter ) {
7207					return;
7208				}
7209			}
7210
7211			// otherwise, set new filter values
7212			style.filter = ralpha.test( filter ) ?
7213				filter.replace( ralpha, opacity ) :
7214				filter + " " + opacity;
7215		}
7216	};
7217}
7218
7219// These hooks cannot be added until DOM ready because the support test
7220// for it is not run until after DOM ready
7221jQuery(function() {
7222	if ( !jQuery.support.reliableMarginRight ) {
7223		jQuery.cssHooks.marginRight = {
7224			get: function( elem, computed ) {
7225				if ( computed ) {
7226					// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
7227					// Work around by temporarily setting element display to inline-block
7228					return jQuery.swap( elem, { "display": "inline-block" },
7229						curCSS, [ elem, "marginRight" ] );
7230				}
7231			}
7232		};
7233	}
7234
7235	// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
7236	// getComputedStyle returns percent when specified for top/left/bottom/right
7237	// rather than make the css module depend on the offset module, we just check for it here
7238	if ( !jQuery.support.pixelPosition && jQuery.fn.position ) {
7239		jQuery.each( [ "top", "left" ], function( i, prop ) {
7240			jQuery.cssHooks[ prop ] = {
7241				get: function( elem, computed ) {
7242					if ( computed ) {
7243						computed = curCSS( elem, prop );
7244						// if curCSS returns percentage, fallback to offset
7245						return rnumnonpx.test( computed ) ?
7246							jQuery( elem ).position()[ prop ] + "px" :
7247							computed;
7248					}
7249				}
7250			};
7251		});
7252	}
7253
7254});
7255
7256if ( jQuery.expr && jQuery.expr.filters ) {
7257	jQuery.expr.filters.hidden = function( elem ) {
7258		// Support: Opera <= 12.12
7259		// Opera reports offsetWidths and offsetHeights less than zero on some elements
7260		return elem.offsetWidth <= 0 && elem.offsetHeight <= 0 ||
7261			(!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none");
7262	};
7263
7264	jQuery.expr.filters.visible = function( elem ) {
7265		return !jQuery.expr.filters.hidden( elem );
7266	};
7267}
7268
7269// These hooks are used by animate to expand properties
7270jQuery.each({
7271	margin: "",
7272	padding: "",
7273	border: "Width"
7274}, function( prefix, suffix ) {
7275	jQuery.cssHooks[ prefix + suffix ] = {
7276		expand: function( value ) {
7277			var i = 0,
7278				expanded = {},
7279
7280				// assumes a single number if not a string
7281				parts = typeof value === "string" ? value.split(" ") : [ value ];
7282
7283			for ( ; i < 4; i++ ) {
7284				expanded[ prefix + cssExpand[ i ] + suffix ] =
7285					parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
7286			}
7287
7288			return expanded;
7289		}
7290	};
7291
7292	if ( !rmargin.test( prefix ) ) {
7293		jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
7294	}
7295});
7296var r20 = /%20/g,
7297	rbracket = /\[\]$/,
7298	rCRLF = /\r?\n/g,
7299	rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
7300	rsubmittable = /^(?:input|select|textarea|keygen)/i;
7301
7302jQuery.fn.extend({
7303	serialize: function() {
7304		return jQuery.param( this.serializeArray() );
7305	},
7306	serializeArray: function() {
7307		return this.map(function(){
7308			// Can add propHook for "elements" to filter or add form elements
7309			var elements = jQuery.prop( this, "elements" );
7310			return elements ? jQuery.makeArray( elements ) : this;
7311		})
7312		.filter(function(){
7313			var type = this.type;
7314			// Use .is(":disabled") so that fieldset[disabled] works
7315			return this.name && !jQuery( this ).is( ":disabled" ) &&
7316				rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
7317				( this.checked || !manipulation_rcheckableType.test( type ) );
7318		})
7319		.map(function( i, elem ){
7320			var val = jQuery( this ).val();
7321
7322			return val == null ?
7323				null :
7324				jQuery.isArray( val ) ?
7325					jQuery.map( val, function( val ){
7326						return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
7327					}) :
7328					{ name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
7329		}).get();
7330	}
7331});
7332
7333//Serialize an array of form elements or a set of
7334//key/values into a query string
7335jQuery.param = function( a, traditional ) {
7336	var prefix,
7337		s = [],
7338		add = function( key, value ) {
7339			// If value is a function, invoke it and return its value
7340			value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
7341			s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
7342		};
7343
7344	// Set traditional to true for jQuery <= 1.3.2 behavior.
7345	if ( traditional === undefined ) {
7346		traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
7347	}
7348
7349	// If an array was passed in, assume that it is an array of form elements.
7350	if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
7351		// Serialize the form elements
7352		jQuery.each( a, function() {
7353			add( this.name, this.value );
7354		});
7355
7356	} else {
7357		// If traditional, encode the "old" way (the way 1.3.2 or older
7358		// did it), otherwise encode params recursively.
7359		for ( prefix in a ) {
7360			buildParams( prefix, a[ prefix ], traditional, add );
7361		}
7362	}
7363
7364	// Return the resulting serialization
7365	return s.join( "&" ).replace( r20, "+" );
7366};
7367
7368function buildParams( prefix, obj, traditional, add ) {
7369	var name;
7370
7371	if ( jQuery.isArray( obj ) ) {
7372		// Serialize array item.
7373		jQuery.each( obj, function( i, v ) {
7374			if ( traditional || rbracket.test( prefix ) ) {
7375				// Treat each array item as a scalar.
7376				add( prefix, v );
7377
7378			} else {
7379				// Item is non-scalar (array or object), encode its numeric index.
7380				buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
7381			}
7382		});
7383
7384	} else if ( !traditional && jQuery.type( obj ) === "object" ) {
7385		// Serialize object item.
7386		for ( name in obj ) {
7387			buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
7388		}
7389
7390	} else {
7391		// Serialize scalar item.
7392		add( prefix, obj );
7393	}
7394}
7395jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
7396	"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
7397	"change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
7398
7399	// Handle event binding
7400	jQuery.fn[ name ] = function( data, fn ) {
7401		return arguments.length > 0 ?
7402			this.on( name, null, data, fn ) :
7403			this.trigger( name );
7404	};
7405});
7406
7407jQuery.fn.hover = function( fnOver, fnOut ) {
7408	return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
7409};
7410var
7411	// Document location
7412	ajaxLocParts,
7413	ajaxLocation,
7414	ajax_nonce = jQuery.now(),
7415
7416	ajax_rquery = /\?/,
7417	rhash = /#.*$/,
7418	rts = /([?&])_=[^&]*/,
7419	rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
7420	// #7653, #8125, #8152: local protocol detection
7421	rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
7422	rnoContent = /^(?:GET|HEAD)$/,
7423	rprotocol = /^\/\//,
7424	rurl = /^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,
7425
7426	// Keep a copy of the old load method
7427	_load = jQuery.fn.load,
7428
7429	/* Prefilters
7430	 * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
7431	 * 2) These are called:
7432	 *    - BEFORE asking for a transport
7433	 *    - AFTER param serialization (s.data is a string if s.processData is true)
7434	 * 3) key is the dataType
7435	 * 4) the catchall symbol "*" can be used
7436	 * 5) execution will start with transport dataType and THEN continue down to "*" if needed
7437	 */
7438	prefilters = {},
7439
7440	/* Transports bindings
7441	 * 1) key is the dataType
7442	 * 2) the catchall symbol "*" can be used
7443	 * 3) selection will start with transport dataType and THEN go to "*" if needed
7444	 */
7445	transports = {},
7446
7447	// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
7448	allTypes = "*/".concat("*");
7449
7450// #8138, IE may throw an exception when accessing
7451// a field from window.location if document.domain has been set
7452try {
7453	ajaxLocation = location.href;
7454} catch( e ) {
7455	// Use the href attribute of an A element
7456	// since IE will modify it given document.location
7457	ajaxLocation = document.createElement( "a" );
7458	ajaxLocation.href = "";
7459	ajaxLocation = ajaxLocation.href;
7460}
7461
7462// Segment location into parts
7463ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
7464
7465// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
7466function addToPrefiltersOrTransports( structure ) {
7467
7468	// dataTypeExpression is optional and defaults to "*"
7469	return function( dataTypeExpression, func ) {
7470
7471		if ( typeof dataTypeExpression !== "string" ) {
7472			func = dataTypeExpression;
7473			dataTypeExpression = "*";
7474		}
7475
7476		var dataType,
7477			i = 0,
7478			dataTypes = dataTypeExpression.toLowerCase().match( core_rnotwhite ) || [];
7479
7480		if ( jQuery.isFunction( func ) ) {
7481			// For each dataType in the dataTypeExpression
7482			while ( (dataType = dataTypes[i++]) ) {
7483				// Prepend if requested
7484				if ( dataType[0] === "+" ) {
7485					dataType = dataType.slice( 1 ) || "*";
7486					(structure[ dataType ] = structure[ dataType ] || []).unshift( func );
7487
7488				// Otherwise append
7489				} else {
7490					(structure[ dataType ] = structure[ dataType ] || []).push( func );
7491				}
7492			}
7493		}
7494	};
7495}
7496
7497// Base inspection function for prefilters and transports
7498function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
7499
7500	var inspected = {},
7501		seekingTransport = ( structure === transports );
7502
7503	function inspect( dataType ) {
7504		var selected;
7505		inspected[ dataType ] = true;
7506		jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
7507			var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
7508			if( typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {
7509				options.dataTypes.unshift( dataTypeOrTransport );
7510				inspect( dataTypeOrTransport );
7511				return false;
7512			} else if ( seekingTransport ) {
7513				return !( selected = dataTypeOrTransport );
7514			}
7515		});
7516		return selected;
7517	}
7518
7519	return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
7520}
7521
7522// A special extend for ajax options
7523// that takes "flat" options (not to be deep extended)
7524// Fixes #9887
7525function ajaxExtend( target, src ) {
7526	var deep, key,
7527		flatOptions = jQuery.ajaxSettings.flatOptions || {};
7528
7529	for ( key in src ) {
7530		if ( src[ key ] !== undefined ) {
7531			( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ];
7532		}
7533	}
7534	if ( deep ) {
7535		jQuery.extend( true, target, deep );
7536	}
7537
7538	return target;
7539}
7540
7541jQuery.fn.load = function( url, params, callback ) {
7542	if ( typeof url !== "string" && _load ) {
7543		return _load.apply( this, arguments );
7544	}
7545
7546	var selector, response, type,
7547		self = this,
7548		off = url.indexOf(" ");
7549
7550	if ( off >= 0 ) {
7551		selector = url.slice( off, url.length );
7552		url = url.slice( 0, off );
7553	}
7554
7555	// If it's a function
7556	if ( jQuery.isFunction( params ) ) {
7557
7558		// We assume that it's the callback
7559		callback = params;
7560		params = undefined;
7561
7562	// Otherwise, build a param string
7563	} else if ( params && typeof params === "object" ) {
7564		type = "POST";
7565	}
7566
7567	// If we have elements to modify, make the request
7568	if ( self.length > 0 ) {
7569		jQuery.ajax({
7570			url: url,
7571
7572			// if "type" variable is undefined, then "GET" method will be used
7573			type: type,
7574			dataType: "html",
7575			data: params
7576		}).done(function( responseText ) {
7577
7578			// Save response for use in complete callback
7579			response = arguments;
7580
7581			self.html( selector ?
7582
7583				// If a selector was specified, locate the right elements in a dummy div
7584				// Exclude scripts to avoid IE 'Permission Denied' errors
7585				jQuery("<div>").append( jQuery.parseHTML( responseText ) ).find( selector ) :
7586
7587				// Otherwise use the full result
7588				responseText );
7589
7590		}).complete( callback && function( jqXHR, status ) {
7591			self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );
7592		});
7593	}
7594
7595	return this;
7596};
7597
7598// Attach a bunch of functions for handling common AJAX events
7599jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ){
7600	jQuery.fn[ type ] = function( fn ){
7601		return this.on( type, fn );
7602	};
7603});
7604
7605jQuery.each( [ "get", "post" ], function( i, method ) {
7606	jQuery[ method ] = function( url, data, callback, type ) {
7607		// shift arguments if data argument was omitted
7608		if ( jQuery.isFunction( data ) ) {
7609			type = type || callback;
7610			callback = data;
7611			data = undefined;
7612		}
7613
7614		return jQuery.ajax({
7615			url: url,
7616			type: method,
7617			dataType: type,
7618			data: data,
7619			success: callback
7620		});
7621	};
7622});
7623
7624jQuery.extend({
7625
7626	// Counter for holding the number of active queries
7627	active: 0,
7628
7629	// Last-Modified header cache for next request
7630	lastModified: {},
7631	etag: {},
7632
7633	ajaxSettings: {
7634		url: ajaxLocation,
7635		type: "GET",
7636		isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
7637		global: true,
7638		processData: true,
7639		async: true,
7640		contentType: "application/x-www-form-urlencoded; charset=UTF-8",
7641		/*
7642		timeout: 0,
7643		data: null,
7644		dataType: null,
7645		username: null,
7646		password: null,
7647		cache: null,
7648		throws: false,
7649		traditional: false,
7650		headers: {},
7651		*/
7652
7653		accepts: {
7654			"*": allTypes,
7655			text: "text/plain",
7656			html: "text/html",
7657			xml: "application/xml, text/xml",
7658			json: "application/json, text/javascript"
7659		},
7660
7661		contents: {
7662			xml: /xml/,
7663			html: /html/,
7664			json: /json/
7665		},
7666
7667		responseFields: {
7668			xml: "responseXML",
7669			text: "responseText"
7670		},
7671
7672		// Data converters
7673		// Keys separate source (or catchall "*") and destination types with a single space
7674		converters: {
7675
7676			// Convert anything to text
7677			"* text": window.String,
7678
7679			// Text to html (true = no transformation)
7680			"text html": true,
7681
7682			// Evaluate text as a json expression
7683			"text json": jQuery.parseJSON,
7684
7685			// Parse text as xml
7686			"text xml": jQuery.parseXML
7687		},
7688
7689		// For options that shouldn't be deep extended:
7690		// you can add your own custom options here if
7691		// and when you create one that shouldn't be
7692		// deep extended (see ajaxExtend)
7693		flatOptions: {
7694			url: true,
7695			context: true
7696		}
7697	},
7698
7699	// Creates a full fledged settings object into target
7700	// with both ajaxSettings and settings fields.
7701	// If target is omitted, writes into ajaxSettings.
7702	ajaxSetup: function( target, settings ) {
7703		return settings ?
7704
7705			// Building a settings object
7706			ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
7707
7708			// Extending ajaxSettings
7709			ajaxExtend( jQuery.ajaxSettings, target );
7710	},
7711
7712	ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
7713	ajaxTransport: addToPrefiltersOrTransports( transports ),
7714
7715	// Main method
7716	ajax: function( url, options ) {
7717
7718		// If url is an object, simulate pre-1.5 signature
7719		if ( typeof url === "object" ) {
7720			options = url;
7721			url = undefined;
7722		}
7723
7724		// Force options to be an object
7725		options = options || {};
7726
7727		var // Cross-domain detection vars
7728			parts,
7729			// Loop variable
7730			i,
7731			// URL without anti-cache param
7732			cacheURL,
7733			// Response headers as string
7734			responseHeadersString,
7735			// timeout handle
7736			timeoutTimer,
7737
7738			// To know if global events are to be dispatched
7739			fireGlobals,
7740
7741			transport,
7742			// Response headers
7743			responseHeaders,
7744			// Create the final options object
7745			s = jQuery.ajaxSetup( {}, options ),
7746			// Callbacks context
7747			callbackContext = s.context || s,
7748			// Context for global events is callbackContext if it is a DOM node or jQuery collection
7749			globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?
7750				jQuery( callbackContext ) :
7751				jQuery.event,
7752			// Deferreds
7753			deferred = jQuery.Deferred(),
7754			completeDeferred = jQuery.Callbacks("once memory"),
7755			// Status-dependent callbacks
7756			statusCode = s.statusCode || {},
7757			// Headers (they are sent all at once)
7758			requestHeaders = {},
7759			requestHeadersNames = {},
7760			// The jqXHR state
7761			state = 0,
7762			// Default abort message
7763			strAbort = "canceled",
7764			// Fake xhr
7765			jqXHR = {
7766				readyState: 0,
7767
7768				// Builds headers hashtable if needed
7769				getResponseHeader: function( key ) {
7770					var match;
7771					if ( state === 2 ) {
7772						if ( !responseHeaders ) {
7773							responseHeaders = {};
7774							while ( (match = rheaders.exec( responseHeadersString )) ) {
7775								responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
7776							}
7777						}
7778						match = responseHeaders[ key.toLowerCase() ];
7779					}
7780					return match == null ? null : match;
7781				},
7782
7783				// Raw string
7784				getAllResponseHeaders: function() {
7785					return state === 2 ? responseHeadersString : null;
7786				},
7787
7788				// Caches the header
7789				setRequestHeader: function( name, value ) {
7790					var lname = name.toLowerCase();
7791					if ( !state ) {
7792						name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
7793						requestHeaders[ name ] = value;
7794					}
7795					return this;
7796				},
7797
7798				// Overrides response content-type header
7799				overrideMimeType: function( type ) {
7800					if ( !state ) {
7801						s.mimeType = type;
7802					}
7803					return this;
7804				},
7805
7806				// Status-dependent callbacks
7807				statusCode: function( map ) {
7808					var code;
7809					if ( map ) {
7810						if ( state < 2 ) {
7811							for ( code in map ) {
7812								// Lazy-add the new callback in a way that preserves old ones
7813								statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
7814							}
7815						} else {
7816							// Execute the appropriate callbacks
7817							jqXHR.always( map[ jqXHR.status ] );
7818						}
7819					}
7820					return this;
7821				},
7822
7823				// Cancel the request
7824				abort: function( statusText ) {
7825					var finalText = statusText || strAbort;
7826					if ( transport ) {
7827						transport.abort( finalText );
7828					}
7829					done( 0, finalText );
7830					return this;
7831				}
7832			};
7833
7834		// Attach deferreds
7835		deferred.promise( jqXHR ).complete = completeDeferred.add;
7836		jqXHR.success = jqXHR.done;
7837		jqXHR.error = jqXHR.fail;
7838
7839		// Remove hash character (#7531: and string promotion)
7840		// Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
7841		// Handle falsy url in the settings object (#10093: consistency with old signature)
7842		// We also use the url parameter if available
7843		s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
7844
7845		// Alias method option to type as per ticket #12004
7846		s.type = options.method || options.type || s.method || s.type;
7847
7848		// Extract dataTypes list
7849		s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( core_rnotwhite ) || [""];
7850
7851		// A cross-domain request is in order when we have a protocol:host:port mismatch
7852		if ( s.crossDomain == null ) {
7853			parts = rurl.exec( s.url.toLowerCase() );
7854			s.crossDomain = !!( parts &&
7855				( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
7856					( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) !=
7857						( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) )
7858			);
7859		}
7860
7861		// Convert data if not already a string
7862		if ( s.data && s.processData && typeof s.data !== "string" ) {
7863			s.data = jQuery.param( s.data, s.traditional );
7864		}
7865
7866		// Apply prefilters
7867		inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
7868
7869		// If request was aborted inside a prefilter, stop there
7870		if ( state === 2 ) {
7871			return jqXHR;
7872		}
7873
7874		// We can fire global events as of now if asked to
7875		fireGlobals = s.global;
7876
7877		// Watch for a new set of requests
7878		if ( fireGlobals && jQuery.active++ === 0 ) {
7879			jQuery.event.trigger("ajaxStart");
7880		}
7881
7882		// Uppercase the type
7883		s.type = s.type.toUpperCase();
7884
7885		// Determine if request has content
7886		s.hasContent = !rnoContent.test( s.type );
7887
7888		// Save the URL in case we're toying with the If-Modified-Since
7889		// and/or If-None-Match header later on
7890		cacheURL = s.url;
7891
7892		// More options handling for requests with no content
7893		if ( !s.hasContent ) {
7894
7895			// If data is available, append data to url
7896			if ( s.data ) {
7897				cacheURL = ( s.url += ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + s.data );
7898				// #9682: remove data so that it's not used in an eventual retry
7899				delete s.data;
7900			}
7901
7902			// Add anti-cache in url if needed
7903			if ( s.cache === false ) {
7904				s.url = rts.test( cacheURL ) ?
7905
7906					// If there is already a '_' parameter, set its value
7907					cacheURL.replace( rts, "$1_=" + ajax_nonce++ ) :
7908
7909					// Otherwise add one to the end
7910					cacheURL + ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ajax_nonce++;
7911			}
7912		}
7913
7914		// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
7915		if ( s.ifModified ) {
7916			if ( jQuery.lastModified[ cacheURL ] ) {
7917				jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
7918			}
7919			if ( jQuery.etag[ cacheURL ] ) {
7920				jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
7921			}
7922		}
7923
7924		// Set the correct header, if data is being sent
7925		if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
7926			jqXHR.setRequestHeader( "Content-Type", s.contentType );
7927		}
7928
7929		// Set the Accepts header for the server, depending on the dataType
7930		jqXHR.setRequestHeader(
7931			"Accept",
7932			s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
7933				s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
7934				s.accepts[ "*" ]
7935		);
7936
7937		// Check for headers option
7938		for ( i in s.headers ) {
7939			jqXHR.setRequestHeader( i, s.headers[ i ] );
7940		}
7941
7942		// Allow custom headers/mimetypes and early abort
7943		if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
7944			// Abort if not done already and return
7945			return jqXHR.abort();
7946		}
7947
7948		// aborting is no longer a cancellation
7949		strAbort = "abort";
7950
7951		// Install callbacks on deferreds
7952		for ( i in { success: 1, error: 1, complete: 1 } ) {
7953			jqXHR[ i ]( s[ i ] );
7954		}
7955
7956		// Get transport
7957		transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
7958
7959		// If no transport, we auto-abort
7960		if ( !transport ) {
7961			done( -1, "No Transport" );
7962		} else {
7963			jqXHR.readyState = 1;
7964
7965			// Send global event
7966			if ( fireGlobals ) {
7967				globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
7968			}
7969			// Timeout
7970			if ( s.async && s.timeout > 0 ) {
7971				timeoutTimer = setTimeout(function() {
7972					jqXHR.abort("timeout");
7973				}, s.timeout );
7974			}
7975
7976			try {
7977				state = 1;
7978				transport.send( requestHeaders, done );
7979			} catch ( e ) {
7980				// Propagate exception as error if not done
7981				if ( state < 2 ) {
7982					done( -1, e );
7983				// Simply rethrow otherwise
7984				} else {
7985					throw e;
7986				}
7987			}
7988		}
7989
7990		// Callback for when everything is done
7991		function done( status, nativeStatusText, responses, headers ) {
7992			var isSuccess, success, error, response, modified,
7993				statusText = nativeStatusText;
7994
7995			// Called once
7996			if ( state === 2 ) {
7997				return;
7998			}
7999
8000			// State is "done" now
8001			state = 2;
8002
8003			// Clear timeout if it exists
8004			if ( timeoutTimer ) {
8005				clearTimeout( timeoutTimer );
8006			}
8007
8008			// Dereference transport for early garbage collection
8009			// (no matter how long the jqXHR object will be used)
8010			transport = undefined;
8011
8012			// Cache response headers
8013			responseHeadersString = headers || "";
8014
8015			// Set readyState
8016			jqXHR.readyState = status > 0 ? 4 : 0;
8017
8018			// Get response data
8019			if ( responses ) {
8020				response = ajaxHandleResponses( s, jqXHR, responses );
8021			}
8022
8023			// If successful, handle type chaining
8024			if ( status >= 200 && status < 300 || status === 304 ) {
8025
8026				// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
8027				if ( s.ifModified ) {
8028					modified = jqXHR.getResponseHeader("Last-Modified");
8029					if ( modified ) {
8030						jQuery.lastModified[ cacheURL ] = modified;
8031					}
8032					modified = jqXHR.getResponseHeader("etag");
8033					if ( modified ) {
8034						jQuery.etag[ cacheURL ] = modified;
8035					}
8036				}
8037
8038				// if no content
8039				if ( status === 204 ) {
8040					isSuccess = true;
8041					statusText = "nocontent";
8042
8043				// if not modified
8044				} else if ( status === 304 ) {
8045					isSuccess = true;
8046					statusText = "notmodified";
8047
8048				// If we have data, let's convert it
8049				} else {
8050					isSuccess = ajaxConvert( s, response );
8051					statusText = isSuccess.state;
8052					success = isSuccess.data;
8053					error = isSuccess.error;
8054					isSuccess = !error;
8055				}
8056			} else {
8057				// We extract error from statusText
8058				// then normalize statusText and status for non-aborts
8059				error = statusText;
8060				if ( status || !statusText ) {
8061					statusText = "error";
8062					if ( status < 0 ) {
8063						status = 0;
8064					}
8065				}
8066			}
8067
8068			// Set data for the fake xhr object
8069			jqXHR.status = status;
8070			jqXHR.statusText = ( nativeStatusText || statusText ) + "";
8071
8072			// Success/Error
8073			if ( isSuccess ) {
8074				deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
8075			} else {
8076				deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
8077			}
8078
8079			// Status-dependent callbacks
8080			jqXHR.statusCode( statusCode );
8081			statusCode = undefined;
8082
8083			if ( fireGlobals ) {
8084				globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
8085					[ jqXHR, s, isSuccess ? success : error ] );
8086			}
8087
8088			// Complete
8089			completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
8090
8091			if ( fireGlobals ) {
8092				globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
8093				// Handle the global AJAX counter
8094				if ( !( --jQuery.active ) ) {
8095					jQuery.event.trigger("ajaxStop");
8096				}
8097			}
8098		}
8099
8100		return jqXHR;
8101	},
8102
8103	getScript: function( url, callback ) {
8104		return jQuery.get( url, undefined, callback, "script" );
8105	},
8106
8107	getJSON: function( url, data, callback ) {
8108		return jQuery.get( url, data, callback, "json" );
8109	}
8110});
8111
8112/* Handles responses to an ajax request:
8113 * - sets all responseXXX fields accordingly
8114 * - finds the right dataType (mediates between content-type and expected dataType)
8115 * - returns the corresponding response
8116 */
8117function ajaxHandleResponses( s, jqXHR, responses ) {
8118	var firstDataType, ct, finalDataType, type,
8119		contents = s.contents,
8120		dataTypes = s.dataTypes,
8121		responseFields = s.responseFields;
8122
8123	// Fill responseXXX fields
8124	for ( type in responseFields ) {
8125		if ( type in responses ) {
8126			jqXHR[ responseFields[type] ] = responses[ type ];
8127		}
8128	}
8129
8130	// Remove auto dataType and get content-type in the process
8131	while( dataTypes[ 0 ] === "*" ) {
8132		dataTypes.shift();
8133		if ( ct === undefined ) {
8134			ct = s.mimeType || jqXHR.getResponseHeader("Content-Type");
8135		}
8136	}
8137
8138	// Check if we're dealing with a known content-type
8139	if ( ct ) {
8140		for ( type in contents ) {
8141			if ( contents[ type ] && contents[ type ].test( ct ) ) {
8142				dataTypes.unshift( type );
8143				break;
8144			}
8145		}
8146	}
8147
8148	// Check to see if we have a response for the expected dataType
8149	if ( dataTypes[ 0 ] in responses ) {
8150		finalDataType = dataTypes[ 0 ];
8151	} else {
8152		// Try convertible dataTypes
8153		for ( type in responses ) {
8154			if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
8155				finalDataType = type;
8156				break;
8157			}
8158			if ( !firstDataType ) {
8159				firstDataType = type;
8160			}
8161		}
8162		// Or just use first one
8163		finalDataType = finalDataType || firstDataType;
8164	}
8165
8166	// If we found a dataType
8167	// We add the dataType to the list if needed
8168	// and return the corresponding response
8169	if ( finalDataType ) {
8170		if ( finalDataType !== dataTypes[ 0 ] ) {
8171			dataTypes.unshift( finalDataType );
8172		}
8173		return responses[ finalDataType ];
8174	}
8175}
8176
8177// Chain conversions given the request and the original response
8178function ajaxConvert( s, response ) {
8179	var conv2, current, conv, tmp,
8180		converters = {},
8181		i = 0,
8182		// Work with a copy of dataTypes in case we need to modify it for conversion
8183		dataTypes = s.dataTypes.slice(),
8184		prev = dataTypes[ 0 ];
8185
8186	// Apply the dataFilter if provided
8187	if ( s.dataFilter ) {
8188		response = s.dataFilter( response, s.dataType );
8189	}
8190
8191	// Create converters map with lowercased keys
8192	if ( dataTypes[ 1 ] ) {
8193		for ( conv in s.converters ) {
8194			converters[ conv.toLowerCase() ] = s.converters[ conv ];
8195		}
8196	}
8197
8198	// Convert to each sequential dataType, tolerating list modification
8199	for ( ; (current = dataTypes[++i]); ) {
8200
8201		// There's only work to do if current dataType is non-auto
8202		if ( current !== "*" ) {
8203
8204			// Convert response if prev dataType is non-auto and differs from current
8205			if ( prev !== "*" && prev !== current ) {
8206
8207				// Seek a direct converter
8208				conv = converters[ prev + " " + current ] || converters[ "* " + current ];
8209
8210				// If none found, seek a pair
8211				if ( !conv ) {
8212					for ( conv2 in converters ) {
8213
8214						// If conv2 outputs current
8215						tmp = conv2.split(" ");
8216						if ( tmp[ 1 ] === current ) {
8217
8218							// If prev can be converted to accepted input
8219							conv = converters[ prev + " " + tmp[ 0 ] ] ||
8220								converters[ "* " + tmp[ 0 ] ];
8221							if ( conv ) {
8222								// Condense equivalence converters
8223								if ( conv === true ) {
8224									conv = converters[ conv2 ];
8225
8226								// Otherwise, insert the intermediate dataType
8227								} else if ( converters[ conv2 ] !== true ) {
8228									current = tmp[ 0 ];
8229									dataTypes.splice( i--, 0, current );
8230								}
8231
8232								break;
8233							}
8234						}
8235					}
8236				}
8237
8238				// Apply converter (if not an equivalence)
8239				if ( conv !== true ) {
8240
8241					// Unless errors are allowed to bubble, catch and return them
8242					if ( conv && s["throws"] ) {
8243						response = conv( response );
8244					} else {
8245						try {
8246							response = conv( response );
8247						} catch ( e ) {
8248							return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current };
8249						}
8250					}
8251				}
8252			}
8253
8254			// Update prev for next iteration
8255			prev = current;
8256		}
8257	}
8258
8259	return { state: "success", data: response };
8260}
8261// Install script dataType
8262jQuery.ajaxSetup({
8263	accepts: {
8264		script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
8265	},
8266	contents: {
8267		script: /(?:java|ecma)script/
8268	},
8269	converters: {
8270		"text script": function( text ) {
8271			jQuery.globalEval( text );
8272			return text;
8273		}
8274	}
8275});
8276
8277// Handle cache's special case and global
8278jQuery.ajaxPrefilter( "script", function( s ) {
8279	if ( s.cache === undefined ) {
8280		s.cache = false;
8281	}
8282	if ( s.crossDomain ) {
8283		s.type = "GET";
8284		s.global = false;
8285	}
8286});
8287
8288// Bind script tag hack transport
8289jQuery.ajaxTransport( "script", function(s) {
8290
8291	// This transport only deals with cross domain requests
8292	if ( s.crossDomain ) {
8293
8294		var script,
8295			head = document.head || jQuery("head")[0] || document.documentElement;
8296
8297		return {
8298
8299			send: function( _, callback ) {
8300
8301				script = document.createElement("script");
8302
8303				script.async = true;
8304
8305				if ( s.scriptCharset ) {
8306					script.charset = s.scriptCharset;
8307				}
8308
8309				script.src = s.url;
8310
8311				// Attach handlers for all browsers
8312				script.onload = script.onreadystatechange = function( _, isAbort ) {
8313
8314					if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {
8315
8316						// Handle memory leak in IE
8317						script.onload = script.onreadystatechange = null;
8318
8319						// Remove the script
8320						if ( script.parentNode ) {
8321							script.parentNode.removeChild( script );
8322						}
8323
8324						// Dereference the script
8325						script = null;
8326
8327						// Callback if not abort
8328						if ( !isAbort ) {
8329							callback( 200, "success" );
8330						}
8331					}
8332				};
8333
8334				// Circumvent IE6 bugs with base elements (#2709 and #4378) by prepending
8335				// Use native DOM manipulation to avoid our domManip AJAX trickery
8336				head.insertBefore( script, head.firstChild );
8337			},
8338
8339			abort: function() {
8340				if ( script ) {
8341					script.onload( undefined, true );
8342				}
8343			}
8344		};
8345	}
8346});
8347var oldCallbacks = [],
8348	rjsonp = /(=)\?(?=&|$)|\?\?/;
8349
8350// Default jsonp settings
8351jQuery.ajaxSetup({
8352	jsonp: "callback",
8353	jsonpCallback: function() {
8354		var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( ajax_nonce++ ) );
8355		this[ callback ] = true;
8356		return callback;
8357	}
8358});
8359
8360// Detect, normalize options and install callbacks for jsonp requests
8361jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
8362
8363	var callbackName, overwritten, responseContainer,
8364		jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
8365			"url" :
8366			typeof s.data === "string" && !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && rjsonp.test( s.data ) && "data"
8367		);
8368
8369	// Handle iff the expected data type is "jsonp" or we have a parameter to set
8370	if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
8371
8372		// Get callback name, remembering preexisting value associated with it
8373		callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
8374			s.jsonpCallback() :
8375			s.jsonpCallback;
8376
8377		// Insert callback into url or form data
8378		if ( jsonProp ) {
8379			s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
8380		} else if ( s.jsonp !== false ) {
8381			s.url += ( ajax_rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
8382		}
8383
8384		// Use data converter to retrieve json after script execution
8385		s.converters["script json"] = function() {
8386			if ( !responseContainer ) {
8387				jQuery.error( callbackName + " was not called" );
8388			}
8389			return responseContainer[ 0 ];
8390		};
8391
8392		// force json dataType
8393		s.dataTypes[ 0 ] = "json";
8394
8395		// Install callback
8396		overwritten = window[ callbackName ];
8397		window[ callbackName ] = function() {
8398			responseContainer = arguments;
8399		};
8400
8401		// Clean-up function (fires after converters)
8402		jqXHR.always(function() {
8403			// Restore preexisting value
8404			window[ callbackName ] = overwritten;
8405
8406			// Save back as free
8407			if ( s[ callbackName ] ) {
8408				// make sure that re-using the options doesn't screw things around
8409				s.jsonpCallback = originalSettings.jsonpCallback;
8410
8411				// save the callback name for future use
8412				oldCallbacks.push( callbackName );
8413			}
8414
8415			// Call if it was a function and we have a response
8416			if ( responseContainer && jQuery.isFunction( overwritten ) ) {
8417				overwritten( responseContainer[ 0 ] );
8418			}
8419
8420			responseContainer = overwritten = undefined;
8421		});
8422
8423		// Delegate to script
8424		return "script";
8425	}
8426});
8427var xhrCallbacks, xhrSupported,
8428	xhrId = 0,
8429	// #5280: Internet Explorer will keep connections alive if we don't abort on unload
8430	xhrOnUnloadAbort = window.ActiveXObject && function() {
8431		// Abort all pending requests
8432		var key;
8433		for ( key in xhrCallbacks ) {
8434			xhrCallbacks[ key ]( undefined, true );
8435		}
8436	};
8437
8438// Functions to create xhrs
8439function createStandardXHR() {
8440	try {
8441		return new window.XMLHttpRequest();
8442	} catch( e ) {}
8443}
8444
8445function createActiveXHR() {
8446	try {
8447		return new window.ActiveXObject("Microsoft.XMLHTTP");
8448	} catch( e ) {}
8449}
8450
8451// Create the request object
8452// (This is still attached to ajaxSettings for backward compatibility)
8453jQuery.ajaxSettings.xhr = window.ActiveXObject ?
8454	/* Microsoft failed to properly
8455	 * implement the XMLHttpRequest in IE7 (can't request local files),
8456	 * so we use the ActiveXObject when it is available
8457	 * Additionally XMLHttpRequest can be disabled in IE7/IE8 so
8458	 * we need a fallback.
8459	 */
8460	function() {
8461		return !this.isLocal && createStandardXHR() || createActiveXHR();
8462	} :
8463	// For all other browsers, use the standard XMLHttpRequest object
8464	createStandardXHR;
8465
8466// Determine support properties
8467xhrSupported = jQuery.ajaxSettings.xhr();
8468jQuery.support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
8469xhrSupported = jQuery.support.ajax = !!xhrSupported;
8470
8471// Create transport if the browser can provide an xhr
8472if ( xhrSupported ) {
8473
8474	jQuery.ajaxTransport(function( s ) {
8475		// Cross domain only allowed if supported through XMLHttpRequest
8476		if ( !s.crossDomain || jQuery.support.cors ) {
8477
8478			var callback;
8479
8480			return {
8481				send: function( headers, complete ) {
8482
8483					// Get a new xhr
8484					var handle, i,
8485						xhr = s.xhr();
8486
8487					// Open the socket
8488					// Passing null username, generates a login popup on Opera (#2865)
8489					if ( s.username ) {
8490						xhr.open( s.type, s.url, s.async, s.username, s.password );
8491					} else {
8492						xhr.open( s.type, s.url, s.async );
8493					}
8494
8495					// Apply custom fields if provided
8496					if ( s.xhrFields ) {
8497						for ( i in s.xhrFields ) {
8498							xhr[ i ] = s.xhrFields[ i ];
8499						}
8500					}
8501
8502					// Override mime type if needed
8503					if ( s.mimeType && xhr.overrideMimeType ) {
8504						xhr.overrideMimeType( s.mimeType );
8505					}
8506
8507					// X-Requested-With header
8508					// For cross-domain requests, seeing as conditions for a preflight are
8509					// akin to a jigsaw puzzle, we simply never set it to be sure.
8510					// (it can always be set on a per-request basis or even using ajaxSetup)
8511					// For same-domain requests, won't change header if already provided.
8512					if ( !s.crossDomain && !headers["X-Requested-With"] ) {
8513						headers["X-Requested-With"] = "XMLHttpRequest";
8514					}
8515
8516					// Need an extra try/catch for cross domain requests in Firefox 3
8517					try {
8518						for ( i in headers ) {
8519							xhr.setRequestHeader( i, headers[ i ] );
8520						}
8521					} catch( err ) {}
8522
8523					// Do send the request
8524					// This may raise an exception which is actually
8525					// handled in jQuery.ajax (so no try/catch here)
8526					xhr.send( ( s.hasContent && s.data ) || null );
8527
8528					// Listener
8529					callback = function( _, isAbort ) {
8530						var status, responseHeaders, statusText, responses;
8531
8532						// Firefox throws exceptions when accessing properties
8533						// of an xhr when a network error occurred
8534						// http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
8535						try {
8536
8537							// Was never called and is aborted or complete
8538							if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
8539
8540								// Only called once
8541								callback = undefined;
8542
8543								// Do not keep as active anymore
8544								if ( handle ) {
8545									xhr.onreadystatechange = jQuery.noop;
8546									if ( xhrOnUnloadAbort ) {
8547										delete xhrCallbacks[ handle ];
8548									}
8549								}
8550
8551								// If it's an abort
8552								if ( isAbort ) {
8553									// Abort it manually if needed
8554									if ( xhr.readyState !== 4 ) {
8555										xhr.abort();
8556									}
8557								} else {
8558									responses = {};
8559									status = xhr.status;
8560									responseHeaders = xhr.getAllResponseHeaders();
8561
8562									// When requesting binary data, IE6-9 will throw an exception
8563									// on any attempt to access responseText (#11426)
8564									if ( typeof xhr.responseText === "string" ) {
8565										responses.text = xhr.responseText;
8566									}
8567
8568									// Firefox throws an exception when accessing
8569									// statusText for faulty cross-domain requests
8570									try {
8571										statusText = xhr.statusText;
8572									} catch( e ) {
8573										// We normalize with Webkit giving an empty statusText
8574										statusText = "";
8575									}
8576
8577									// Filter status for non standard behaviors
8578
8579									// If the request is local and we have data: assume a success
8580									// (success with no data won't get notified, that's the best we
8581									// can do given current implementations)
8582									if ( !status && s.isLocal && !s.crossDomain ) {
8583										status = responses.text ? 200 : 404;
8584									// IE - #1450: sometimes returns 1223 when it should be 204
8585									} else if ( status === 1223 ) {
8586										status = 204;
8587									}
8588								}
8589							}
8590						} catch( firefoxAccessException ) {
8591							if ( !isAbort ) {
8592								complete( -1, firefoxAccessException );
8593							}
8594						}
8595
8596						// Call complete if needed
8597						if ( responses ) {
8598							complete( status, statusText, responses, responseHeaders );
8599						}
8600					};
8601
8602					if ( !s.async ) {
8603						// if we're in sync mode we fire the callback
8604						callback();
8605					} else if ( xhr.readyState === 4 ) {
8606						// (IE6 & IE7) if it's in cache and has been
8607						// retrieved directly we need to fire the callback
8608						setTimeout( callback );
8609					} else {
8610						handle = ++xhrId;
8611						if ( xhrOnUnloadAbort ) {
8612							// Create the active xhrs callbacks list if needed
8613							// and attach the unload handler
8614							if ( !xhrCallbacks ) {
8615								xhrCallbacks = {};
8616								jQuery( window ).unload( xhrOnUnloadAbort );
8617							}
8618							// Add to list of active xhrs callbacks
8619							xhrCallbacks[ handle ] = callback;
8620						}
8621						xhr.onreadystatechange = callback;
8622					}
8623				},
8624
8625				abort: function() {
8626					if ( callback ) {
8627						callback( undefined, true );
8628					}
8629				}
8630			};
8631		}
8632	});
8633}
8634var fxNow, timerId,
8635	rfxtypes = /^(?:toggle|show|hide)$/,
8636	rfxnum = new RegExp( "^(?:([+-])=|)(" + core_pnum + ")([a-z%]*)$", "i" ),
8637	rrun = /queueHooks$/,
8638	animationPrefilters = [ defaultPrefilter ],
8639	tweeners = {
8640		"*": [function( prop, value ) {
8641			var end, unit,
8642				tween = this.createTween( prop, value ),
8643				parts = rfxnum.exec( value ),
8644				target = tween.cur(),
8645				start = +target || 0,
8646				scale = 1,
8647				maxIterations = 20;
8648
8649			if ( parts ) {
8650				end = +parts[2];
8651				unit = parts[3] || ( jQuery.cssNumber[ prop ] ? "" : "px" );
8652
8653				// We need to compute starting value
8654				if ( unit !== "px" && start ) {
8655					// Iteratively approximate from a nonzero starting point
8656					// Prefer the current property, because this process will be trivial if it uses the same units
8657					// Fallback to end or a simple constant
8658					start = jQuery.css( tween.elem, prop, true ) || end || 1;
8659
8660					do {
8661						// If previous iteration zeroed out, double until we get *something*
8662						// Use a string for doubling factor so we don't accidentally see scale as unchanged below
8663						scale = scale || ".5";
8664
8665						// Adjust and apply
8666						start = start / scale;
8667						jQuery.style( tween.elem, prop, start + unit );
8668
8669					// Update scale, tolerating zero or NaN from tween.cur()
8670					// And breaking the loop if scale is unchanged or perfect, or if we've just had enough
8671					} while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
8672				}
8673
8674				tween.unit = unit;
8675				tween.start = start;
8676				// If a +=/-= token was provided, we're doing a relative animation
8677				tween.end = parts[1] ? start + ( parts[1] + 1 ) * end : end;
8678			}
8679			return tween;
8680		}]
8681	};
8682
8683// Animations created synchronously will run synchronously
8684function createFxNow() {
8685	setTimeout(function() {
8686		fxNow = undefined;
8687	});
8688	return ( fxNow = jQuery.now() );
8689}
8690
8691function createTweens( animation, props ) {
8692	jQuery.each( props, function( prop, value ) {
8693		var collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
8694			index = 0,
8695			length = collection.length;
8696		for ( ; index < length; index++ ) {
8697			if ( collection[ index ].call( animation, prop, value ) ) {
8698
8699				// we're done with this property
8700				return;
8701			}
8702		}
8703	});
8704}
8705
8706function Animation( elem, properties, options ) {
8707	var result,
8708		stopped,
8709		index = 0,
8710		length = animationPrefilters.length,
8711		deferred = jQuery.Deferred().always( function() {
8712			// don't match elem in the :animated selector
8713			delete tick.elem;
8714		}),
8715		tick = function() {
8716			if ( stopped ) {
8717				return false;
8718			}
8719			var currentTime = fxNow || createFxNow(),
8720				remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
8721				// archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)
8722				temp = remaining / animation.duration || 0,
8723				percent = 1 - temp,
8724				index = 0,
8725				length = animation.tweens.length;
8726
8727			for ( ; index < length ; index++ ) {
8728				animation.tweens[ index ].run( percent );
8729			}
8730
8731			deferred.notifyWith( elem, [ animation, percent, remaining ]);
8732
8733			if ( percent < 1 && length ) {
8734				return remaining;
8735			} else {
8736				deferred.resolveWith( elem, [ animation ] );
8737				return false;
8738			}
8739		},
8740		animation = deferred.promise({
8741			elem: elem,
8742			props: jQuery.extend( {}, properties ),
8743			opts: jQuery.extend( true, { specialEasing: {} }, options ),
8744			originalProperties: properties,
8745			originalOptions: options,
8746			startTime: fxNow || createFxNow(),
8747			duration: options.duration,
8748			tweens: [],
8749			createTween: function( prop, end ) {
8750				var tween = jQuery.Tween( elem, animation.opts, prop, end,
8751						animation.opts.specialEasing[ prop ] || animation.opts.easing );
8752				animation.tweens.push( tween );
8753				return tween;
8754			},
8755			stop: function( gotoEnd ) {
8756				var index = 0,
8757					// if we are going to the end, we want to run all the tweens
8758					// otherwise we skip this part
8759					length = gotoEnd ? animation.tweens.length : 0;
8760				if ( stopped ) {
8761					return this;
8762				}
8763				stopped = true;
8764				for ( ; index < length ; index++ ) {
8765					animation.tweens[ index ].run( 1 );
8766				}
8767
8768				// resolve when we played the last frame
8769				// otherwise, reject
8770				if ( gotoEnd ) {
8771					deferred.resolveWith( elem, [ animation, gotoEnd ] );
8772				} else {
8773					deferred.rejectWith( elem, [ animation, gotoEnd ] );
8774				}
8775				return this;
8776			}
8777		}),
8778		props = animation.props;
8779
8780	propFilter( props, animation.opts.specialEasing );
8781
8782	for ( ; index < length ; index++ ) {
8783		result = animationPrefilters[ index ].call( animation, elem, props, animation.opts );
8784		if ( result ) {
8785			return result;
8786		}
8787	}
8788
8789	createTweens( animation, props );
8790
8791	if ( jQuery.isFunction( animation.opts.start ) ) {
8792		animation.opts.start.call( elem, animation );
8793	}
8794
8795	jQuery.fx.timer(
8796		jQuery.extend( tick, {
8797			elem: elem,
8798			anim: animation,
8799			queue: animation.opts.queue
8800		})
8801	);
8802
8803	// attach callbacks from options
8804	return animation.progress( animation.opts.progress )
8805		.done( animation.opts.done, animation.opts.complete )
8806		.fail( animation.opts.fail )
8807		.always( animation.opts.always );
8808}
8809
8810function propFilter( props, specialEasing ) {
8811	var value, name, index, easing, hooks;
8812
8813	// camelCase, specialEasing and expand cssHook pass
8814	for ( index in props ) {
8815		name = jQuery.camelCase( index );
8816		easing = specialEasing[ name ];
8817		value = props[ index ];
8818		if ( jQuery.isArray( value ) ) {
8819			easing = value[ 1 ];
8820			value = props[ index ] = value[ 0 ];
8821		}
8822
8823		if ( index !== name ) {
8824			props[ name ] = value;
8825			delete props[ index ];
8826		}
8827
8828		hooks = jQuery.cssHooks[ name ];
8829		if ( hooks && "expand" in hooks ) {
8830			value = hooks.expand( value );
8831			delete props[ name ];
8832
8833			// not quite $.extend, this wont overwrite keys already present.
8834			// also - reusing 'index' from above because we have the correct "name"
8835			for ( index in value ) {
8836				if ( !( index in props ) ) {
8837					props[ index ] = value[ index ];
8838					specialEasing[ index ] = easing;
8839				}
8840			}
8841		} else {
8842			specialEasing[ name ] = easing;
8843		}
8844	}
8845}
8846
8847jQuery.Animation = jQuery.extend( Animation, {
8848
8849	tweener: function( props, callback ) {
8850		if ( jQuery.isFunction( props ) ) {
8851			callback = props;
8852			props = [ "*" ];
8853		} else {
8854			props = props.split(" ");
8855		}
8856
8857		var prop,
8858			index = 0,
8859			length = props.length;
8860
8861		for ( ; index < length ; index++ ) {
8862			prop = props[ index ];
8863			tweeners[ prop ] = tweeners[ prop ] || [];
8864			tweeners[ prop ].unshift( callback );
8865		}
8866	},
8867
8868	prefilter: function( callback, prepend ) {
8869		if ( prepend ) {
8870			animationPrefilters.unshift( callback );
8871		} else {
8872			animationPrefilters.push( callback );
8873		}
8874	}
8875});
8876
8877function defaultPrefilter( elem, props, opts ) {
8878	/*jshint validthis:true */
8879	var prop, index, length,
8880		value, dataShow, toggle,
8881		tween, hooks, oldfire,
8882		anim = this,
8883		style = elem.style,
8884		orig = {},
8885		handled = [],
8886		hidden = elem.nodeType && isHidden( elem );
8887
8888	// handle queue: false promises
8889	if ( !opts.queue ) {
8890		hooks = jQuery._queueHooks( elem, "fx" );
8891		if ( hooks.unqueued == null ) {
8892			hooks.unqueued = 0;
8893			oldfire = hooks.empty.fire;
8894			hooks.empty.fire = function() {
8895				if ( !hooks.unqueued ) {
8896					oldfire();
8897				}
8898			};
8899		}
8900		hooks.unqueued++;
8901
8902		anim.always(function() {
8903			// doing this makes sure that the complete handler will be called
8904			// before this completes
8905			anim.always(function() {
8906				hooks.unqueued--;
8907				if ( !jQuery.queue( elem, "fx" ).length ) {
8908					hooks.empty.fire();
8909				}
8910			});
8911		});
8912	}
8913
8914	// height/width overflow pass
8915	if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
8916		// Make sure that nothing sneaks out
8917		// Record all 3 overflow attributes because IE does not
8918		// change the overflow attribute when overflowX and
8919		// overflowY are set to the same value
8920		opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
8921
8922		// Set display property to inline-block for height/width
8923		// animations on inline elements that are having width/height animated
8924		if ( jQuery.css( elem, "display" ) === "inline" &&
8925				jQuery.css( elem, "float" ) === "none" ) {
8926
8927			// inline-level elements accept inline-block;
8928			// block-level elements need to be inline with layout
8929			if ( !jQuery.support.inlineBlockNeedsLayout || css_defaultDisplay( elem.nodeName ) === "inline" ) {
8930				style.display = "inline-block";
8931
8932			} else {
8933				style.zoom = 1;
8934			}
8935		}
8936	}
8937
8938	if ( opts.overflow ) {
8939		style.overflow = "hidden";
8940		if ( !jQuery.support.shrinkWrapBlocks ) {
8941			anim.always(function() {
8942				style.overflow = opts.overflow[ 0 ];
8943				style.overflowX = opts.overflow[ 1 ];
8944				style.overflowY = opts.overflow[ 2 ];
8945			});
8946		}
8947	}
8948
8949
8950	// show/hide pass
8951	for ( index in props ) {
8952		value = props[ index ];
8953		if ( rfxtypes.exec( value ) ) {
8954			delete props[ index ];
8955			toggle = toggle || value === "toggle";
8956			if ( value === ( hidden ? "hide" : "show" ) ) {
8957				continue;
8958			}
8959			handled.push( index );
8960		}
8961	}
8962
8963	length = handled.length;
8964	if ( length ) {
8965		dataShow = jQuery._data( elem, "fxshow" ) || jQuery._data( elem, "fxshow", {} );
8966		if ( "hidden" in dataShow ) {
8967			hidden = dataShow.hidden;
8968		}
8969
8970		// store state if its toggle - enables .stop().toggle() to "reverse"
8971		if ( toggle ) {
8972			dataShow.hidden = !hidden;
8973		}
8974		if ( hidden ) {
8975			jQuery( elem ).show();
8976		} else {
8977			anim.done(function() {
8978				jQuery( elem ).hide();
8979			});
8980		}
8981		anim.done(function() {
8982			var prop;
8983			jQuery._removeData( elem, "fxshow" );
8984			for ( prop in orig ) {
8985				jQuery.style( elem, prop, orig[ prop ] );
8986			}
8987		});
8988		for ( index = 0 ; index < length ; index++ ) {
8989			prop = handled[ index ];
8990			tween = anim.createTween( prop, hidden ? dataShow[ prop ] : 0 );
8991			orig[ prop ] = dataShow[ prop ] || jQuery.style( elem, prop );
8992
8993			if ( !( prop in dataShow ) ) {
8994				dataShow[ prop ] = tween.start;
8995				if ( hidden ) {
8996					tween.end = tween.start;
8997					tween.start = prop === "width" || prop === "height" ? 1 : 0;
8998				}
8999			}
9000		}
9001	}
9002}
9003
9004function Tween( elem, options, prop, end, easing ) {
9005	return new Tween.prototype.init( elem, options, prop, end, easing );
9006}
9007jQuery.Tween = Tween;
9008
9009Tween.prototype = {
9010	constructor: Tween,
9011	init: function( elem, options, prop, end, easing, unit ) {
9012		this.elem = elem;
9013		this.prop = prop;
9014		this.easing = easing || "swing";
9015		this.options = options;
9016		this.start = this.now = this.cur();
9017		this.end = end;
9018		this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
9019	},
9020	cur: function() {
9021		var hooks = Tween.propHooks[ this.prop ];
9022
9023		return hooks && hooks.get ?
9024			hooks.get( this ) :
9025			Tween.propHooks._default.get( this );
9026	},
9027	run: function( percent ) {
9028		var eased,
9029			hooks = Tween.propHooks[ this.prop ];
9030
9031		if ( this.options.duration ) {
9032			this.pos = eased = jQuery.easing[ this.easing ](
9033				percent, this.options.duration * percent, 0, 1, this.options.duration
9034			);
9035		} else {
9036			this.pos = eased = percent;
9037		}
9038		this.now = ( this.end - this.start ) * eased + this.start;
9039
9040		if ( this.options.step ) {
9041			this.options.step.call( this.elem, this.now, this );
9042		}
9043
9044		if ( hooks && hooks.set ) {
9045			hooks.set( this );
9046		} else {
9047			Tween.propHooks._default.set( this );
9048		}
9049		return this;
9050	}
9051};
9052
9053Tween.prototype.init.prototype = Tween.prototype;
9054
9055Tween.propHooks = {
9056	_default: {
9057		get: function( tween ) {
9058			var result;
9059
9060			if ( tween.elem[ tween.prop ] != null &&
9061				(!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {
9062				return tween.elem[ tween.prop ];
9063			}
9064
9065			// passing an empty string as a 3rd parameter to .css will automatically
9066			// attempt a parseFloat and fallback to a string if the parse fails
9067			// so, simple values such as "10px" are parsed to Float.
9068			// complex values such as "rotate(1rad)" are returned as is.
9069			result = jQuery.css( tween.elem, tween.prop, "" );
9070			// Empty strings, null, undefined and "auto" are converted to 0.
9071			return !result || result === "auto" ? 0 : result;
9072		},
9073		set: function( tween ) {
9074			// use step hook for back compat - use cssHook if its there - use .style if its
9075			// available and use plain properties where available
9076			if ( jQuery.fx.step[ tween.prop ] ) {
9077				jQuery.fx.step[ tween.prop ]( tween );
9078			} else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {
9079				jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
9080			} else {
9081				tween.elem[ tween.prop ] = tween.now;
9082			}
9083		}
9084	}
9085};
9086
9087// Remove in 2.0 - this supports IE8's panic based approach
9088// to setting things on disconnected nodes
9089
9090Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
9091	set: function( tween ) {
9092		if ( tween.elem.nodeType && tween.elem.parentNode ) {
9093			tween.elem[ tween.prop ] = tween.now;
9094		}
9095	}
9096};
9097
9098jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
9099	var cssFn = jQuery.fn[ name ];
9100	jQuery.fn[ name ] = function( speed, easing, callback ) {
9101		return speed == null || typeof speed === "boolean" ?
9102			cssFn.apply( this, arguments ) :
9103			this.animate( genFx( name, true ), speed, easing, callback );
9104	};
9105});
9106
9107jQuery.fn.extend({
9108	fadeTo: function( speed, to, easing, callback ) {
9109
9110		// show any hidden elements after setting opacity to 0
9111		return this.filter( isHidden ).css( "opacity", 0 ).show()
9112
9113			// animate to the value specified
9114			.end().animate({ opacity: to }, speed, easing, callback );
9115	},
9116	animate: function( prop, speed, easing, callback ) {
9117		var empty = jQuery.isEmptyObject( prop ),
9118			optall = jQuery.speed( speed, easing, callback ),
9119			doAnimation = function() {
9120				// Operate on a copy of prop so per-property easing won't be lost
9121				var anim = Animation( this, jQuery.extend( {}, prop ), optall );
9122				doAnimation.finish = function() {
9123					anim.stop( true );
9124				};
9125				// Empty animations, or finishing resolves immediately
9126				if ( empty || jQuery._data( this, "finish" ) ) {
9127					anim.stop( true );
9128				}
9129			};
9130			doAnimation.finish = doAnimation;
9131
9132		return empty || optall.queue === false ?
9133			this.each( doAnimation ) :
9134			this.queue( optall.queue, doAnimation );
9135	},
9136	stop: function( type, clearQueue, gotoEnd ) {
9137		var stopQueue = function( hooks ) {
9138			var stop = hooks.stop;
9139			delete hooks.stop;
9140			stop( gotoEnd );
9141		};
9142
9143		if ( typeof type !== "string" ) {
9144			gotoEnd = clearQueue;
9145			clearQueue = type;
9146			type = undefined;
9147		}
9148		if ( clearQueue && type !== false ) {
9149			this.queue( type || "fx", [] );
9150		}
9151
9152		return this.each(function() {
9153			var dequeue = true,
9154				index = type != null && type + "queueHooks",
9155				timers = jQuery.timers,
9156				data = jQuery._data( this );
9157
9158			if ( index ) {
9159				if ( data[ index ] && data[ index ].stop ) {
9160					stopQueue( data[ index ] );
9161				}
9162			} else {
9163				for ( index in data ) {
9164					if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
9165						stopQueue( data[ index ] );
9166					}
9167				}
9168			}
9169
9170			for ( index = timers.length; index--; ) {
9171				if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
9172					timers[ index ].anim.stop( gotoEnd );
9173					dequeue = false;
9174					timers.splice( index, 1 );
9175				}
9176			}
9177
9178			// start the next in the queue if the last step wasn't forced
9179			// timers currently will call their complete callbacks, which will dequeue
9180			// but only if they were gotoEnd
9181			if ( dequeue || !gotoEnd ) {
9182				jQuery.dequeue( this, type );
9183			}
9184		});
9185	},
9186	finish: function( type ) {
9187		if ( type !== false ) {
9188			type = type || "fx";
9189		}
9190		return this.each(function() {
9191			var index,
9192				data = jQuery._data( this ),
9193				queue = data[ type + "queue" ],
9194				hooks = data[ type + "queueHooks" ],
9195				timers = jQuery.timers,
9196				length = queue ? queue.length : 0;
9197
9198			// enable finishing flag on private data
9199			data.finish = true;
9200
9201			// empty the queue first
9202			jQuery.queue( this, type, [] );
9203
9204			if ( hooks && hooks.cur && hooks.cur.finish ) {
9205				hooks.cur.finish.call( this );
9206			}
9207
9208			// look for any active animations, and finish them
9209			for ( index = timers.length; index--; ) {
9210				if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
9211					timers[ index ].anim.stop( true );
9212					timers.splice( index, 1 );
9213				}
9214			}
9215
9216			// look for any animations in the old queue and finish them
9217			for ( index = 0; index < length; index++ ) {
9218				if ( queue[ index ] && queue[ index ].finish ) {
9219					queue[ index ].finish.call( this );
9220				}
9221			}
9222
9223			// turn off finishing flag
9224			delete data.finish;
9225		});
9226	}
9227});
9228
9229// Generate parameters to create a standard animation
9230function genFx( type, includeWidth ) {
9231	var which,
9232		attrs = { height: type },
9233		i = 0;
9234
9235	// if we include width, step value is 1 to do all cssExpand values,
9236	// if we don't include width, step value is 2 to skip over Left and Right
9237	includeWidth = includeWidth? 1 : 0;
9238	for( ; i < 4 ; i += 2 - includeWidth ) {
9239		which = cssExpand[ i ];
9240		attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
9241	}
9242
9243	if ( includeWidth ) {
9244		attrs.opacity = attrs.width = type;
9245	}
9246
9247	return attrs;
9248}
9249
9250// Generate shortcuts for custom animations
9251jQuery.each({
9252	slideDown: genFx("show"),
9253	slideUp: genFx("hide"),
9254	slideToggle: genFx("toggle"),
9255	fadeIn: { opacity: "show" },
9256	fadeOut: { opacity: "hide" },
9257	fadeToggle: { opacity: "toggle" }
9258}, function( name, props ) {
9259	jQuery.fn[ name ] = function( speed, easing, callback ) {
9260		return this.animate( props, speed, easing, callback );
9261	};
9262});
9263
9264jQuery.speed = function( speed, easing, fn ) {
9265	var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
9266		complete: fn || !fn && easing ||
9267			jQuery.isFunction( speed ) && speed,
9268		duration: speed,
9269		easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
9270	};
9271
9272	opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
9273		opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
9274
9275	// normalize opt.queue - true/undefined/null -> "fx"
9276	if ( opt.queue == null || opt.queue === true ) {
9277		opt.queue = "fx";
9278	}
9279
9280	// Queueing
9281	opt.old = opt.complete;
9282
9283	opt.complete = function() {
9284		if ( jQuery.isFunction( opt.old ) ) {
9285			opt.old.call( this );
9286		}
9287
9288		if ( opt.queue ) {
9289			jQuery.dequeue( this, opt.queue );
9290		}
9291	};
9292
9293	return opt;
9294};
9295
9296jQuery.easing = {
9297	linear: function( p ) {
9298		return p;
9299	},
9300	swing: function( p ) {
9301		return 0.5 - Math.cos( p*Math.PI ) / 2;
9302	}
9303};
9304
9305jQuery.timers = [];
9306jQuery.fx = Tween.prototype.init;
9307jQuery.fx.tick = function() {
9308	var timer,
9309		timers = jQuery.timers,
9310		i = 0;
9311
9312	fxNow = jQuery.now();
9313
9314	for ( ; i < timers.length; i++ ) {
9315		timer = timers[ i ];
9316		// Checks the timer has not already been removed
9317		if ( !timer() && timers[ i ] === timer ) {
9318			timers.splice( i--, 1 );
9319		}
9320	}
9321
9322	if ( !timers.length ) {
9323		jQuery.fx.stop();
9324	}
9325	fxNow = undefined;
9326};
9327
9328jQuery.fx.timer = function( timer ) {
9329	if ( timer() && jQuery.timers.push( timer ) ) {
9330		jQuery.fx.start();
9331	}
9332};
9333
9334jQuery.fx.interval = 13;
9335
9336jQuery.fx.start = function() {
9337	if ( !timerId ) {
9338		timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );
9339	}
9340};
9341
9342jQuery.fx.stop = function() {
9343	clearInterval( timerId );
9344	timerId = null;
9345};
9346
9347jQuery.fx.speeds = {
9348	slow: 600,
9349	fast: 200,
9350	// Default speed
9351	_default: 400
9352};
9353
9354// Back Compat <1.8 extension point
9355jQuery.fx.step = {};
9356
9357if ( jQuery.expr && jQuery.expr.filters ) {
9358	jQuery.expr.filters.animated = function( elem ) {
9359		return jQuery.grep(jQuery.timers, function( fn ) {
9360			return elem === fn.elem;
9361		}).length;
9362	};
9363}
9364jQuery.fn.offset = function( options ) {
9365	if ( arguments.length ) {
9366		return options === undefined ?
9367			this :
9368			this.each(function( i ) {
9369				jQuery.offset.setOffset( this, options, i );
9370			});
9371	}
9372
9373	var docElem, win,
9374		box = { top: 0, left: 0 },
9375		elem = this[ 0 ],
9376		doc = elem && elem.ownerDocument;
9377
9378	if ( !doc ) {
9379		return;
9380	}
9381
9382	docElem = doc.documentElement;
9383
9384	// Make sure it's not a disconnected DOM node
9385	if ( !jQuery.contains( docElem, elem ) ) {
9386		return box;
9387	}
9388
9389	// If we don't have gBCR, just use 0,0 rather than error
9390	// BlackBerry 5, iOS 3 (original iPhone)
9391	if ( typeof elem.getBoundingClientRect !== core_strundefined ) {
9392		box = elem.getBoundingClientRect();
9393	}
9394	win = getWindow( doc );
9395	return {
9396		top: box.top  + ( win.pageYOffset || docElem.scrollTop )  - ( docElem.clientTop  || 0 ),
9397		left: box.left + ( win.pageXOffset || docElem.scrollLeft ) - ( docElem.clientLeft || 0 )
9398	};
9399};
9400
9401jQuery.offset = {
9402
9403	setOffset: function( elem, options, i ) {
9404		var position = jQuery.css( elem, "position" );
9405
9406		// set position first, in-case top/left are set even on static elem
9407		if ( position === "static" ) {
9408			elem.style.position = "relative";
9409		}
9410
9411		var curElem = jQuery( elem ),
9412			curOffset = curElem.offset(),
9413			curCSSTop = jQuery.css( elem, "top" ),
9414			curCSSLeft = jQuery.css( elem, "left" ),
9415			calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1,
9416			props = {}, curPosition = {}, curTop, curLeft;
9417
9418		// need to be able to calculate position if either top or left is auto and position is either absolute or fixed
9419		if ( calculatePosition ) {
9420			curPosition = curElem.position();
9421			curTop = curPosition.top;
9422			curLeft = curPosition.left;
9423		} else {
9424			curTop = parseFloat( curCSSTop ) || 0;
9425			curLeft = parseFloat( curCSSLeft ) || 0;
9426		}
9427
9428		if ( jQuery.isFunction( options ) ) {
9429			options = options.call( elem, i, curOffset );
9430		}
9431
9432		if ( options.top != null ) {
9433			props.top = ( options.top - curOffset.top ) + curTop;
9434		}
9435		if ( options.left != null ) {
9436			props.left = ( options.left - curOffset.left ) + curLeft;
9437		}
9438
9439		if ( "using" in options ) {
9440			options.using.call( elem, props );
9441		} else {
9442			curElem.css( props );
9443		}
9444	}
9445};
9446
9447
9448jQuery.fn.extend({
9449
9450	position: function() {
9451		if ( !this[ 0 ] ) {
9452			return;
9453		}
9454
9455		var offsetParent, offset,
9456			parentOffset = { top: 0, left: 0 },
9457			elem = this[ 0 ];
9458
9459		// fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is it's only offset parent
9460		if ( jQuery.css( elem, "position" ) === "fixed" ) {
9461			// we assume that getBoundingClientRect is available when computed position is fixed
9462			offset = elem.getBoundingClientRect();
9463		} else {
9464			// Get *real* offsetParent
9465			offsetParent = this.offsetParent();
9466
9467			// Get correct offsets
9468			offset = this.offset();
9469			if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) {
9470				parentOffset = offsetParent.offset();
9471			}
9472
9473			// Add offsetParent borders
9474			parentOffset.top  += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true );
9475			parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true );
9476		}
9477
9478		// Subtract parent offsets and element margins
9479		// note: when an element has margin: auto the offsetLeft and marginLeft
9480		// are the same in Safari causing offset.left to incorrectly be 0
9481		return {
9482			top:  offset.top  - parentOffset.top - jQuery.css( elem, "marginTop", true ),
9483			left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true)
9484		};
9485	},
9486
9487	offsetParent: function() {
9488		return this.map(function() {
9489			var offsetParent = this.offsetParent || document.documentElement;
9490			while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) && jQuery.css( offsetParent, "position") === "static" ) ) {
9491				offsetParent = offsetParent.offsetParent;
9492			}
9493			return offsetParent || document.documentElement;
9494		});
9495	}
9496});
9497
9498
9499// Create scrollLeft and scrollTop methods
9500jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) {
9501	var top = /Y/.test( prop );
9502
9503	jQuery.fn[ method ] = function( val ) {
9504		return jQuery.access( this, function( elem, method, val ) {
9505			var win = getWindow( elem );
9506
9507			if ( val === undefined ) {
9508				return win ? (prop in win) ? win[ prop ] :
9509					win.document.documentElement[ method ] :
9510					elem[ method ];
9511			}
9512
9513			if ( win ) {
9514				win.scrollTo(
9515					!top ? val : jQuery( win ).scrollLeft(),
9516					top ? val : jQuery( win ).scrollTop()
9517				);
9518
9519			} else {
9520				elem[ method ] = val;
9521			}
9522		}, method, val, arguments.length, null );
9523	};
9524});
9525
9526function getWindow( elem ) {
9527	return jQuery.isWindow( elem ) ?
9528		elem :
9529		elem.nodeType === 9 ?
9530			elem.defaultView || elem.parentWindow :
9531			false;
9532}
9533// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
9534jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
9535	jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) {
9536		// margin is only for outerHeight, outerWidth
9537		jQuery.fn[ funcName ] = function( margin, value ) {
9538			var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
9539				extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
9540
9541			return jQuery.access( this, function( elem, type, value ) {
9542				var doc;
9543
9544				if ( jQuery.isWindow( elem ) ) {
9545					// As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
9546					// isn't a whole lot we can do. See pull request at this URL for discussion:
9547					// https://github.com/jquery/jquery/pull/764
9548					return elem.document.documentElement[ "client" + name ];
9549				}
9550
9551				// Get document width or height
9552				if ( elem.nodeType === 9 ) {
9553					doc = elem.documentElement;
9554
9555					// Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest
9556					// unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it.
9557					return Math.max(
9558						elem.body[ "scroll" + name ], doc[ "scroll" + name ],
9559						elem.body[ "offset" + name ], doc[ "offset" + name ],
9560						doc[ "client" + name ]
9561					);
9562				}
9563
9564				return value === undefined ?
9565					// Get width or height on the element, requesting but not forcing parseFloat
9566					jQuery.css( elem, type, extra ) :
9567
9568					// Set width or height on the element
9569					jQuery.style( elem, type, value, extra );
9570			}, type, chainable ? margin : undefined, chainable, null );
9571		};
9572	});
9573});
9574// Limit scope pollution from any deprecated API
9575// (function() {
9576
9577// })();
9578// Expose jQuery to the global object
9579window.jQuery = window.$ = jQuery;
9580
9581// Expose jQuery as an AMD module, but only for AMD loaders that
9582// understand the issues with loading multiple versions of jQuery
9583// in a page that all might call define(). The loader will indicate
9584// they have special allowances for multiple jQuery versions by
9585// specifying define.amd.jQuery = true. Register as a named module,
9586// since jQuery can be concatenated with other files that may use define,
9587// but not use a proper concatenation script that understands anonymous
9588// AMD modules. A named AMD is safest and most robust way to register.
9589// Lowercase jquery is used because AMD module names are derived from
9590// file names, and jQuery is normally delivered in a lowercase file name.
9591// Do this after creating the global so that if an AMD module wants to call
9592// noConflict to hide this version of jQuery, it will work.
9593if ( typeof define === "function" && define.amd && define.amd.jQuery ) {
9594	define( "jquery", [], function () { return jQuery; } );
9595}
9596
9597})( window );
9598/*!
9599 * Modernizr v2.8.0
9600 * www.modernizr.com
9601 *
9602 * Copyright (c) Faruk Ates, Paul Irish, Alex Sexton
9603 * Available under the BSD and MIT licenses: www.modernizr.com/license/
9604 */
9605
9606/*
9607 * Modernizr tests which native CSS3 and HTML5 features are available in
9608 * the current UA and makes the results available to you in two ways:
9609 * as properties on a global Modernizr object, and as classes on the
9610 * <html> element. This information allows you to progressively enhance
9611 * your pages with a granular level of control over the experience.
9612 *
9613 * Modernizr has an optional (not included) conditional resource loader
9614 * called Modernizr.load(), based on Yepnope.js (yepnopejs.com).
9615 * To get a build that includes Modernizr.load(), as well as choosing
9616 * which tests to include, go to www.modernizr.com/download/
9617 *
9618 * Authors        Faruk Ates, Paul Irish, Alex Sexton
9619 * Contributors   Ryan Seddon, Ben Alman
9620 */
9621
9622window.Modernizr = (function( window, document, undefined ) {
9623
9624    var version = '2.8.0',
9625
9626    Modernizr = {},
9627
9628    /*>>cssclasses*/
9629    // option for enabling the HTML classes to be added
9630    enableClasses = true,
9631    /*>>cssclasses*/
9632
9633    docElement = document.documentElement,
9634
9635    /**
9636     * Create our "modernizr" element that we do most feature tests on.
9637     */
9638    mod = 'modernizr',
9639    modElem = document.createElement(mod),
9640    mStyle = modElem.style,
9641
9642    /**
9643     * Create the input element for various Web Forms feature tests.
9644     */
9645    inputElem /*>>inputelem*/ = document.createElement('input') /*>>inputelem*/ ,
9646
9647    /*>>smile*/
9648    smile = ':)',
9649    /*>>smile*/
9650
9651    toString = {}.toString,
9652
9653    // TODO :: make the prefixes more granular
9654    /*>>prefixes*/
9655    // List of property values to set for css tests. See ticket #21
9656    prefixes = ' -webkit- -moz- -o- -ms- '.split(' '),
9657    /*>>prefixes*/
9658
9659    /*>>domprefixes*/
9660    // Following spec is to expose vendor-specific style properties as:
9661    //   elem.style.WebkitBorderRadius
9662    // and the following would be incorrect:
9663    //   elem.style.webkitBorderRadius
9664
9665    // Webkit ghosts their properties in lowercase but Opera & Moz do not.
9666    // Microsoft uses a lowercase `ms` instead of the correct `Ms` in IE8+
9667    //   erik.eae.net/archives/2008/03/10/21.48.10/
9668
9669    // More here: github.com/Modernizr/Modernizr/issues/issue/21
9670    omPrefixes = 'Webkit Moz O ms',
9671
9672    cssomPrefixes = omPrefixes.split(' '),
9673
9674    domPrefixes = omPrefixes.toLowerCase().split(' '),
9675    /*>>domprefixes*/
9676
9677    /*>>ns*/
9678    ns = {'svg': 'http://www.w3.org/2000/svg'},
9679    /*>>ns*/
9680
9681    tests = {},
9682    inputs = {},
9683    attrs = {},
9684
9685    classes = [],
9686
9687    slice = classes.slice,
9688
9689    featureName, // used in testing loop
9690
9691
9692    /*>>
9692teststyles*/
9693    // Inject element with style element and some CSS rules
9694    injectElementWithStyles = function( rule, callback, nodes, testnames ) {
9695
9696      var style, ret, node, docOverflow,
9697          div = document.createElement('div'),
9698          // After page load injecting a fake body doesn't work so check if body exists
9699          body = document.body,
9700          // IE6 and 7 won't return offsetWidth or offsetHeight unless it's in the body element, so we fake it.
9701          fakeBody = body || document.createElement('body');
9702
9703      if ( parseInt(nodes, 10) ) {
9704          // In order not to give false positives we create a node for each test
9705          // This also allows the method to scale for unspecified uses
9706          while ( nodes-- ) {
9707              node = document.createElement('div');
9708              node.id = testnames ? testnames[nodes] : mod + (nodes + 1);
9709              div.appendChild(node);
9710          }
9711      }
9712
9713      // <style> elements in IE6-9 are considered 'NoScope' elements and therefore will be removed
9714      // when injected with innerHTML. To get around this you need to prepend the 'NoScope' element
9715      // with a 'scoped' element, in our case the soft-hyphen entity as it won't mess with our measurements.
9716      // msdn.microsoft.com/en-us/library/ms533897%28VS.85%29.aspx
9717      // Documents served as xml will throw if using &shy; so use xml friendly encoded version. See issue #277
9718      style = ['&#173;','<style id="s', mod, '">', rule, '</style>'].join('');
9719      div.id = mod;
9720      // IE6 will false positive on some tests due to the style element inside the test div somehow interfering offsetHeight, so insert it into body or fakebody.
9721      // Opera will act all quirky when injecting elements in documentElement when page is served as xml, needs fakebody too. #270
9722      (body ? div : fakeBody).innerHTML += style;
9723      fakeBody.appendChild(div);
9724      if ( !body ) {
9725          //avoid crashing IE8, if background image is used
9726          fakeBody.style.background = '';
9727          //Safari 5.13/5.1.4 OSX stops loading if ::-webkit-scrollbar is used and scrollbars are visible
9728          fakeBody.style.overflow = 'hidden';
9729          docOverflow = docElement.style.overflow;
9730          docElement.style.overflow = 'hidden';
9731          docElement.appendChild(fakeBody);
9732      }
9733
9734      ret = callback(div, rule);
9735      // If this is done after page load we don't want to remove the body so check if body exists
9736      if ( !body ) {
9737          fakeBody.parentNode.removeChild(fakeBody);
9738          docElement.style.overflow = docOverflow;
9739      } else {
9740          div.parentNode.removeChild(div);
9741      }
9742
9743      return !!ret;
9744
9745    },
9746    /*>>teststyles*/
9747
9748    /*>>mq*/
9749    // adapted from matchMedia polyfill
9750    // by Scott Jehl and Paul Irish
9751    // gist.github.com/786768
9752    testMediaQuery = function( mq ) {
9753
9754      var matchMedia = window.matchMedia || window.msMatchMedia;
9755      if ( matchMedia ) {
9756        return matchMedia(mq) && matchMedia(mq).matches || false;
9757      }
9758
9759      var bool;
9760
9761      injectElementWithStyles('@media ' + mq + ' { #' + mod + ' { position: absolute; } }', function( node ) {
9762        bool = (window.getComputedStyle ?
9763                  getComputedStyle(node, null) :
9764                  node.currentStyle)['position'] == 'absolute';
9765      });
9766
9767      return bool;
9768
9769     },
9770     /*>>mq*/
9771
9772
9773    /*>>hasevent*/
9774    //
9775    // isEventSupported determines if a given element supports the given event
9776    // kangax.github.com/iseventsupported/
9777    //
9778    // The following results are known incorrects:
9779    //   Modernizr.hasEvent("webkitTransitionEnd", elem) // false negative
9780    //   Modernizr.hasEvent("textInput") // in Webkit. github.com/Modernizr/Modernizr/issues/333
9781    //   ...
9782    isEventSupported = (function() {
9783
9784      var TAGNAMES = {
9785        'select': 'input', 'change': 'input',
9786        'submit': 'form', 'reset': 'form',
9787        'error': 'img', 'load': 'img', 'abort': 'img'
9788      };
9789
9790      function isEventSupported( eventName, element ) {
9791
9792        element = element || document.createElement(TAGNAMES[eventName] || 'div');
9793        eventName = 'on' + eventName;
9794
9795        // When using `setAttribute`, IE skips "unload", WebKit skips "unload" and "resize", whereas `in` "catches" those
9796        var isSupported = eventName in element;
9797
9798        if ( !isSupported ) {
9799          // If it has no `setAttribute` (i.e. doesn't implement Node interface), try generic element
9800          if ( !element.setAttribute ) {
9801            element = document.createElement('div');
9802          }
9803          if ( element.setAttribute && element.removeAttribute ) {
9804            element.setAttribute(eventName, '');
9805            isSupported = is(element[eventName], 'function');
9806
9807            // If property was created, "remove it" (by setting value to `undefined`)
9808            if ( !is(element[eventName], 'undefined') ) {
9809              element[eventName] = undefined;
9810            }
9811            element.removeAttribute(eventName);
9812          }
9813        }
9814
9815        element = null;
9816        return isSupported;
9817      }
9818      return isEventSupported;
9819    })(),
9820    /*>>hasevent*/
9821
9822    // TODO :: Add flag for hasownprop ? didn't last time
9823
9824    // hasOwnProperty shim by kangax needed for Safari 2.0 support
9825    _hasOwnProperty = ({}).hasOwnProperty, hasOwnProp;
9826
9827    if ( !is(_hasOwnProperty, 'undefined') && !is(_hasOwnProperty.call, 'undefined') ) {
9828      hasOwnProp = function (object, property) {
9829        return _hasOwnProperty.call(object, property);
9830      };
9831    }
9832    else {
9833      hasOwnProp = function (object, property) { /* yes, this can give false positives/negatives, but most of the time we don't care about those */
9834        return ((property in object) && is(object.constructor.prototype[property], 'undefined'));
9835      };
9836    }
9837
9838    // Adapted from ES5-shim https://github.com/kriskowal/es5-shim/blob/master/es5-shim.js
9839    // es5.github.com/#x15.3.4.5
9840
9841    if (!Function.prototype.bind) {
9842      Function.prototype.bind = function bind(that) {
9843
9844        var target = this;
9845
9846        if (typeof target != "function") {
9847            throw new TypeError();
9848        }
9849
9850        var args = slice.call(arguments, 1),
9851            bound = function () {
9852
9853            if (this instanceof bound) {
9854
9855              var F = function(){};
9856              F.prototype = target.prototype;
9857              var self = new F();
9858
9859              var result = target.apply(
9860                  self,
9861                  args.concat(slice.call(arguments))
9862              );
9863              if (Object(result) === result) {
9864                  return result;
9865              }
9866              return self;
9867
9868            } else {
9869
9870              return target.apply(
9871                  that,
9872                  args.concat(slice.call(arguments))
9873              );
9874
9875            }
9876
9877        };
9878
9879        return bound;
9880      };
9881    }
9882
9883    /**
9884     * setCss applies given styles to the Modernizr DOM node.
9885     */
9886    function setCss( str ) {
9887        mStyle.cssText = str;
9888    }
9889
9890    /**
9891     * setCssAll extrapolates all vendor-specific css strings.
9892     */
9893    function setCssAll( str1, str2 ) {
9894        return setCss(prefixes.join(str1 + ';') + ( str2 || '' ));
9895    }
9896
9897    /**
9898     * is returns a boolean for if typeof obj is exactly type.
9899     */
9900    function is( obj, type ) {
9901        return typeof obj === type;
9902    }
9903
9904    /**
9905     * contains returns a boolean for if substr is found within str.
9906     */
9907    function contains( str, substr ) {
9908        return !!~('' + str).indexOf(substr);
9909    }
9910
9911    /*>>testprop*/
9912
9913    // testProps is a generic CSS / DOM property test.
9914
9915    // In testing support for a given CSS property, it's legit to test:
9916    //    `elem.style[styleName] !== undefined`
9917    // If the property is supported it will return an empty string,
9918    // if unsupported it will return undefined.
9919
9920    // We'll take advantage of this quick test and skip setting a style
9921    // on our modernizr element, but instead just testing undefined vs
9922    // empty string.
9923
9924    // Because the testing of the CSS property names (with "-", as
9925    // opposed to the camelCase DOM properties) is non-portable and
9926    // non-standard but works in WebKit and IE (but not Gecko or Opera),
9927    // we explicitly reject properties with dashes so that authors
9928    // developing in WebKit or IE first don't end up with
9929    // browser-specific content by accident.
9930
9931    function testProps( props, prefixed ) {
9932        for ( var i in props ) {
9933            var prop = props[i];
9934            if ( !contains(prop, "-") && mStyle[prop] !== undefined ) {
9935                return prefixed == 'pfx' ? prop : true;
9936            }
9937        }
9938        return false;
9939    }
9940    /*>>testprop*/
9941
9942    // TODO :: add testDOMProps
9943    /**
9944     * testDOMProps is a generic DOM property test; if a browser supports
9945     *   a certain property, it won't return undefined for it.
9946     */
9947    function testDOMProps( props, obj, elem ) {
9948        for ( var i in props ) {
9949            var item = obj[props[i]];
9950            if ( item !== undefined) {
9951
9952                // return the property name as a string
9953                if (elem === false) return props[i];
9954
9955                // let's bind a function
9956                if (is(item, 'function')){
9957                  // default to autobind unless override
9958                  return item.bind(elem || obj);
9959                }
9960
9961                // return the unbound function or obj or value
9962                return item;
9963            }
9964        }
9965        return false;
9966    }
9967
9968    /*>>testallprops*/
9969    /**
9970     * testPropsAll tests a list of DOM properties we want to check against.
9971     *   We specify literally ALL possible (known and/or likely) properties on
9972     *   the element including the non-vendor prefixed one, for forward-
9973     *   compatibility.
9974     */
9975    function testPropsAll( prop, prefixed, elem ) {
9976
9977        var ucProp  = prop.charAt(0).toUpperCase() + prop.slice(1),
9978            props   = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' ');
9979
9980        // did they call .prefixed('boxSizing') or are we just testing a prop?
9981        if(is(prefixed, "string") || is(prefixed, "undefined")) {
9982          return testProps(props, prefixed);
9983
9984        // otherwise, they called .prefixed('requestAnimationFrame', window[, elem])
9985        } else {
9986          props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' ');
9987          return testDOMProps(props, prefixed, elem);
9988        }
9989    }
9990    /*>>testallprops*/
9991
9992
9993    /**
9994     * Tests
9995     * -----
9996     */
9997
9998    // The *new* flexbox
9999    // dev.w3.org/csswg/css3-flexbox
10000
10001    tests['flexbox'] = function() {
10002      return testPropsAll('flexWrap');
10003    };
10004
10005    // The *old* flexbox
10006    // www.w3.org/TR/2009/WD-css3-flexbox-20090723/
10007
10008    tests['flexboxlegacy'] = function() {
10009        return testPropsAll('boxDirection');
10010    };
10011
10012    // On the S60 and BB Storm, getContext exists, but always returns undefined
10013    // so we actually have to call getContext() to verify
10014    // github.com/Modernizr/Modernizr/issues/issue/97/
10015
10016    tests['canvas'] = function() {
10017        var elem = document.createElement('canvas');
10018        return !!(elem.getContext && elem.getContext('2d'));
10019    };
10020
10021    tests['canvastext'] = function() {
10022        return !!(Modernizr['canvas'] && is(document.createElement('canvas').getContext('2d').fillText, 'function'));
10023    };
10024
10025    // webk.it/70117 is tracking a legit WebGL feature detect proposal
10026
10027    // We do a soft detect which may false positive in order to avoid
10028    // an expensive context creation: bugzil.la/732441
10029
10030    tests['webgl'] = function() {
10031        return !!window.WebGLRenderingContext;
10032    };
10033
10034    /*
10035     * The Modernizr.touch test only indicates if the browser supports
10036     *    touch events, which does not necessarily reflect a touchscreen
10037     *    device, as evidenced by tablets running Windows 7 or, alas,
10038     *    the Palm Pre / WebOS (touch) phones.
10039     *
10040     * Additionally, Chrome (desktop) used to lie about its support on this,
10041     *    but that has since been rectified: crbug.com/36415
10042     *
10043     * We also test for Firefox 4 Multitouch Support.
10044     *
10045     * For more info, see: modernizr.github.com/Modernizr/touch.html
10046     */
10047
10048    tests['touch'] = function() {
10049        var bool;
10050
10051        if(('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {
10052          bool = true;
10053        } else {
10054          injectElementWithStyles(['@media (',prefixes.join('touch-enabled),('),mod,')','{#modernizr{top:9px;position:absolute}}'].join(''), function( node ) {
10055            bool = node.offsetTop === 9;
10056          });
10057        }
10058
10059        return bool;
10060    };
10061
10062
10063    // geolocation is often considered a trivial feature detect...
10064    // Turns out, it's quite tricky to get right:
10065    //
10066    // Using !!navigator.geolocation does two things we don't want. It:
10067    //   1. Leaks memory in IE9: github.com/Modernizr/Modernizr/issues/513
10068    //   2. Disables page caching in WebKit: webk.it/43956
10069    //
10070    // Meanwhile, in Firefox < 8, an about:config setting could expose
10071    // a false positive that would throw an exception: bugzil.la/688158
10072
10073    tests['geolocation'] = function() {
10074        return 'geolocation' in navigator;
10075    };
10076
10077
10078    tests['postmessage'] = function() {
10079      return !!window.postMessage;
10080    };
10081
10082
10083    // Chrome incognito mode used to throw an exception when using openDatabase
10084    // It doesn't anymore.
10085    tests['websqldatabase'] = function() {
10086      return !!window.openDatabase;
10087    };
10088
10089    // Vendors had inconsistent prefixing with the experimental Indexed DB:
10090    // - Webkit's implementation is accessible through webkitIndexedDB
10091    // - Firefox shipped moz_indexedDB before FF4b9, but since then has been mozIndexedDB
10092    // For speed, we don't test the legacy (and beta-only) indexedDB
10093    tests['indexedDB'] = function() {
10094      return !!testPropsAll("indexedDB", window);
10095    };
10096
10097    // documentMode logic from YUI to filter out IE8 Compat Mode
10098    //   which false positives.
10099    tests['hashchange'] = function() {
10100      return isEventSupported('hashchange', window) && (document.documentMode === undefined || document.documentMode > 7);
10101    };
10102
10103    // Per 1.6:
10104    // This used to be Modernizr.historymanagement but the longer
10105    // name has been deprecated in favor of a shorter and property-matching one.
10106    // The old API is still available in 1.6, but as of 2.0 will throw a warning,
10107    // and in the first release thereafter disappear entirely.
10108    tests['history'] = function() {
10109      return !!(window.history && history.pushState);
10110    };
10111
10112    tests['draganddrop'] = function() {
10113        var div = document.createElement('div');
10114        return ('draggable' in div) || ('ondragstart' in div && 'ondrop' in div);
10115    };
10116
10117    // FF3.6 was EOL'ed on 4/24/12, but the ESR version of FF10
10118    // will be supported until FF19 (2/12/13), at which time, ESR becomes FF17.
10119    // FF10 still uses prefixes, so check for it until then.
10120    // for more ESR info, see: mozilla.org/en-US/firefox/organizations/faq/
10121    tests['websockets'] = function() {
10122        return 'WebSocket' in window || 'MozWebSocket' in window;
10123    };
10124
10125
10126    // css-tricks.com/rgba-browser-support/
10127    tests['rgba'] = function() {
10128        // Set an rgba() color and check the returned value
10129
10130        setCss('background-color:rgba(150,255,150,.5)');
10131
10132        return contains(mStyle.backgroundColor, 'rgba');
10133    };
10134
10135    tests['hsla'] = function() {
10136        // Same as rgba(), in fact, browsers re-map hsla() to rgba() internally,
10137        //   except IE9 who retains it as hsla
10138
10139        setCss('background-color:hsla(120,40%,100%,.5)');
10140
10141        return contains(mStyle.backgroundColor, 'rgba') || contains(mStyle.backgroundColor, 'hsla');
10142    };
10143
10144    tests['multiplebgs'] = function() {
10145        // Setting multiple images AND a color on the background shorthand property
10146        //  and then querying the style.background property value for the number of
10147        //  occurrences of "url(" is a reliable method for detecting ACTUAL support for this!
10148
10149        setCss('background:url(https://),url(https://),red url(https://)');
10150
10151        // If the UA supports multiple backgrounds, there should be three occurrences
10152        //   of the string "url(" in the return value for elemStyle.background
10153
10154        return (/(url\s*\(.*?){3}/).test(mStyle.background);
10155    };
10156
10157
10158
10159    // this will false positive in Opera Mini
10160    //   github.com/Modernizr/Modernizr/issues/396
10161
10162    tests['backgroundsize'] = function() {
10163        return testPropsAll('backgroundSize');
10164    };
10165
10166    tests['borderimage'] = function() {
10167        return testPropsAll('borderImage');
10168    };
10169
10170
10171    // Super comprehensive table about all the unique implementations of
10172    // border-radius: muddledramblings.com/table-of-css3-border-radius-compliance
10173
10174    tests['borderradius'] = function() {
10175        return testPropsAll('borderRadius');
10176    };
10177
10178    // WebOS unfortunately false positives on this test.
10179    tests['boxshadow'] = function() {
10180        return testPropsAll('boxShadow');
10181    };
10182
10183    // FF3.0 will false positive on this test
10184    tests['textshadow'] = function() {
10185        return document.createElement('div').style.textShadow === '';
10186    };
10187
10188
10189    tests['opacity'] = function() {
10190        // Browsers that actually have CSS Opacity implemented have done so
10191        //  according to spec, which means their return values are within the
10192        //  range of [0.0,1.0] - including the leading zero.
10193
10194        setCssAll('opacity:.55');
10195
10196        // The non-literal . in this regex is intentional:
10197        //   German Chrome returns this value as 0,55
10198        // github.com/Modernizr/Modernizr/issues/#issue/59/comment/516632
10199        return (/^0.55$/).test(mStyle.opacity);
10200    };
10201
10202
10203    // Note, Android < 4 will pass this test, but can only animate
10204    //   a single property at a time
10205    //   goo.gl/v3V4Gp
10206    tests['cssanimations'] = function() {
10207        return testPropsAll('animationName');
10208    };
10209
10210
10211    tests['csscolumns'] = function() {
10212        return testPropsAll('columnCount');
10213    };
10214
10215
10216    tests['cssgradients'] = function() {
10217        /**
10218         * For CSS Gradients syntax, please see:
10219         * webkit.org/blog/175/introducing-css-gradients/
10220         * developer.mozilla.org/en/CSS/-moz-linear-gradient
10221         * developer.mozilla.org/en/CSS/-moz-radial-gradient
10222         * dev.w3.org/csswg/css3-images/#gradients-
10223         */
10224
10225        var str1 = 'background-image:',
10226            str2 = 'gradient(linear,left top,right bottom,from(#9f9),to(white));',
10227            str3 = 'linear-gradient(left top,#9f9, white);';
10228
10229        setCss(
10230             // legacy webkit syntax (FIXME: remove when syntax not in use anymore)
10231              (str1 + '-webkit- '.split(' ').join(str2 + str1) +
10232             // standard syntax             // trailing 'background-image:'
10233              prefixes.join(str3 + str1)).slice(0, -str1.length)
10234        );
10235
10236        return contains(mStyle.backgroundImage, 'gradient');
10237    };
10238
10239
10240    tests['cssreflections'] = function() {
10241        return testPropsAll('boxReflect');
10242    };
10243
10244
10245    tests['csstransforms'] = function() {
10246        return !!testPropsAll('transform');
10247    };
10248
10249
10250    tests['csstransforms3d'] = function() {
10251
10252        var ret = !!testPropsAll('perspective');
10253
10254        // Webkit's 3D transforms are passed off to the browser's own graphics renderer.
10255        //   It works fine in Safari on Leopard and Snow Leopard, but not in Chrome in
10256        //   some conditions. As a result, Webkit typically recognizes the syntax but
10257        //   will sometimes throw a false positive, thus we must do a more thorough check:
10258        if ( ret && 'webkitPerspective' in docElement.style ) {
10259
10260          // Webkit allows this media query to succeed only if the feature is enabled.
10261          // `@media (transform-3d),(-webkit-transform-3d){ ... }`
10262          injectElementWithStyles('@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}', function( node, rule ) {
10263            ret = node.offsetLeft === 9 && node.offsetHeight === 3;
10264          });
10265        }
10266        return ret;
10267    };
10268
10269
10270    tests['csstransitions'] = function() {
10271        return testPropsAll('transition');
10272    };
10273
10274
10275    /*>>fontface*/
10276    // @font-face detection routine by Diego Perini
10277    // javascript.nwbox.com/CSSSupport/
10278
10279    // false positives:
10280    //   WebOS github.com/Modernizr/Modernizr/issues/342
10281    //   WP7   github.com/Modernizr/Modernizr/issues/538
10282    tests['fontface'] = function() {
10283        var bool;
10284
10285        injectElementWithStyles('@font-face {font-family:"font";src:url("https://")}', function( node, rule ) {
10286          var style = document.getElementById('smodernizr'),
10287              sheet = style.sheet || style.styleSheet,
10288              cssText = sheet ? (sheet.cssRules && sheet.cssRules[0] ? sheet.cssRules[0].cssText : sheet.cssText || '') : '';
10289
10290          bool = /src/i.test(cssText) && cssText.indexOf(rule.split(' ')[0]) === 0;
10291        });
10292
10293        return bool;
10294    };
10295    /*>>fontface*/
10296
10297    // CSS generated content detection
10298    tests['generatedcontent'] = function() {
10299        var bool;
10300
10301        injectElementWithStyles(['#',mod,'{font:0/0 a}
10301#',mod,':after{content:"',smile,'";visibility:hidden;font:3px/1 a}'].join(''), function( node ) {
10302          bool = node.offsetHeight >= 3;
10303        });
10304
10305        return bool;
10306    };
10307
10308
10309
10310    // These tests evaluate support of the video/audio elements, as well as
10311    // testing what types of content they support.
10312    //
10313    // We're using the Boolean constructor here, so that we can extend the value
10314    // e.g.  Modernizr.video     // true
10315    //       Modernizr.video.ogg // 'probably'
10316    //
10317    // Codec values from : github.com/NielsLeenheer/html5test/blob/9106a8/index.html#L845
10318    //                     thx to NielsLeenheer and zcorpan
10319
10320    // Note: in some older browsers, "no" was a return value instead of empty string.
10321    //   It was live in FF3.5.0 and 3.5.1, but fixed in 3.5.2
10322    //   It was also live in Safari 4.0.0 - 4.0.4, but fixed in 4.0.5
10323
10324    tests['video'] = function() {
10325        var elem = document.createElement('video'),
10326            bool = false;
10327
10328        // IE9 Running on Windows Server SKU can cause an exception to be thrown, bug #224
10329        try {
10330            if ( bool = !!elem.canPlayType ) {
10331                bool      = new Boolean(bool);
10332                bool.ogg  = elem.canPlayType('video/ogg; codecs="theora"')      .replace(/^no$/,'');
10333
10334                // Without QuickTime, this value will be `undefined`. github.com/Modernizr/Modernizr/issues/546
10335                bool.h264 = elem.canPlayType('video/mp4; codecs="avc1.42E01E"') .replace(/^no$/,'');
10336
10337                bool.webm = elem.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,'');
10338            }
10339
10340        } catch(e) { }
10341
10342        return bool;
10343    };
10344
10345    tests['audio'] = function() {
10346        var elem = document.createElement('audio'),
10347            bool = false;
10348
10349        try {
10350            if ( bool = !!elem.canPlayType ) {
10351                bool      = new Boolean(bool);
10352                bool.ogg  = elem.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,'');
10353                bool.mp3  = elem.canPlayType('audio/mpeg;')               .replace(/^no$/,'');
10354
10355                // Mimetypes accepted:
10356                //   developer.mozilla.org/En/Media_formats_supported_by_the_audio_and_video_elements
10357                //   bit.ly/iphoneoscodecs
10358                bool.wav  = elem.canPlayType('audio/wav; codecs="1"')     .replace(/^no$/,'');
10359                bool.m4a  = ( elem.canPlayType('audio/x-m4a;')            ||
10360                              elem.canPlayType('audio/aac;'))             .replace(/^no$/,'');
10361            }
10362        } catch(e) { }
10363
10364        return bool;
10365    };
10366
10367
10368    // In FF4, if disabled, window.localStorage should === null.
10369
10370    // Normally, we could not test that directly and need to do a
10371    //   `('localStorage' in window) && ` test first because otherwise Firefox will
10372    //   throw bugzil.la/365772 if cookies are disabled
10373
10374    // Also in iOS5 Private Browsing mode, attempting to use localStorage.setItem
10375    // will throw the exception:
10376    //   QUOTA_EXCEEDED_ERRROR DOM Exception 22.
10377    // Peculiarly, getItem and removeItem calls do not throw.
10378
10379    // Because we are forced to try/catch this, we'll go aggressive.
10380
10381    // Just FWIW: IE8 Compat mode supports these features completely:
10382    //   www.quirksmode.org/dom/html5.html
10383    // But IE8 doesn't support either with local files
10384
10385    tests['localstorage'] = function() {
10386        try {
10387            localStorage.setItem(mod, mod);
10388            localStorage.removeItem(mod);
10389            return true;
10390        } catch(e) {
10391            return false;
10392        }
10393    };
10394
10395    tests['sessionstorage'] = function() {
10396        try {
10397            sessionStorage.setItem(mod, mod);
10398            sessionStorage.removeItem(mod);
10399            return true;
10400        } catch(e) {
10401            return false;
10402        }
10403    };
10404
10405
10406    tests['webworkers'] = function() {
10407        return !!window.Worker;
10408    };
10409
10410
10411    tests['applicationcache'] = function() {
10412        return !!window.applicationCache;
10413    };
10414
10415
10416    // Thanks to Erik Dahlstrom
10417    tests['svg'] = function() {
10418        return !!document.createElementNS && !!document.createElementNS(ns.svg, 'svg').createSVGRect;
10419    };
10420
10421    // specifically for SVG inline in HTML, not within XHTML
10422    // test page: paulirish.com/demo/inline-svg
10423    tests['inlinesvg'] = function() {
10424      var div = document.createElement('div');
10425      div.innerHTML = '<svg/>';
10426      return (div.firstChild && div.firstChild.namespaceURI) == ns.svg;
10427    };
10428
10429    // SVG SMIL animation
10430    tests['smil'] = function() {
10431        return !!document.createElementNS && /SVGAnimate/.test(toString.call(document.createElementNS(ns.svg, 'animate')));
10432    };
10433
10434    // This test is only for clip paths in SVG proper, not clip paths on HTML content
10435    // demo: srufaculty.sru.edu/david.dailey/svg/newstuff/clipPath4.svg
10436
10437    // However read the comments to dig into applying SVG clippaths to HTML content here:
10438    //   github.com/Modernizr/Modernizr/issues/213#issuecomment-1149491
10439    tests['svgclippaths'] = function() {
10440        return !!document.createElementNS && /SVGClipPath/.test(toString.call(document.createElementNS(ns.svg, 'clipPath')));
10441    };
10442
10443    /*>>webforms*/
10444    // input features and input types go directly onto the ret object, bypassing the tests loop.
10445    // Hold this guy to execute in a moment.
10446    function webforms() {
10447        /*>>input*/
10448        // Run through HTML5's new input attributes to see if the UA understands any.
10449        // We're using f which is the <input> element created early on
10450        // Mike Taylr has created a comprehensive resource for testing these attributes
10451        //   when applied to all input types:
10452        //   miketaylr.com/code/input-type-attr.html
10453        // spec: www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary
10454
10455        // Only input placeholder is tested while textarea's placeholder is not.
10456        // Currently Safari 4 and Opera 11 have support only for the input placeholder
10457        // Both tests are available in feature-detects/forms-placeholder.js
10458        Modernizr['input'] = (function( props ) {
10459            for ( var i = 0, len = props.length; i < len; i++ ) {
10460                attrs[ props[i] ] = !!(props[i] in inputElem);
10461            }
10462            if (attrs.list){
10463              // safari false positive's on datalist: webk.it/74252
10464              // see also github.com/Modernizr/Modernizr/issues/146
10465              attrs.list = !!(document.createElement('datalist') && window.HTMLDataListElement);
10466            }
10467            return attrs;
10468        })('autocomplete autofocus list placeholder max min multiple pattern required step'.split(' '));
10469        /*>>input*/
10470
10471        /*>>inputtypes*/
10472        // Run through HTML5's new input types to see if the UA understands any.
10473        //   This is put behind the tests runloop because it doesn't return a
10474        //   true/false like all the other tests; instead, it returns an object
10475        //   containing each input type with its corresponding true/false value
10476
10477        // Big thanks to @miketaylr for the html5 forms expertise. miketaylr.com/
10478        Modernizr['inputtypes'] = (function(props) {
10479
10480            for ( var i = 0, bool, inputElemType, defaultView, len = props.length; i < len; i++ ) {
10481
10482                inputElem.setAttribute('type', inputElemType = props[i]);
10483                bool = inputElem.type !== 'text';
10484
10485                // We first check to see if the type we give it sticks..
10486                // If the type does, we feed it a textual value, which shouldn't be val
10486id.
10487                // If the value doesn't stick, we know there's input sanitization which infers a custom UI
10488                if ( bool ) {
10489
10490                    inputElem.value         = smile;
10491                    inputElem.style.cssText = 'position:absolute;visibility:hidden;';
10492
10493                    if ( /^range$/.test(inputElemType) && inputElem.style.WebkitAppearance !== undefined ) {
10494
10495                      docElement.appendChild(inputElem);
10496                      defaultView = document.defaultView;
10497
10498                      // Safari 2-4 allows the smiley as a value, despite making a slider
10499                      bool =  defaultView.getComputedStyle &&
10500                              defaultView.getComputedStyle(inputElem, null).WebkitAppearance !== 'textfield' &&
10501                              // Mobile android web browser has false positive, so must
10502                              // check the height to see if the widget is actually there.
10503                              (inputElem.offsetHeight !== 0);
10504
10505                      docElement.removeChild(inputElem);
10506
10507                    } else if ( /^(search|tel)$/.test(inputElemType) ){
10508                      // Spec doesn't define any special parsing or detectable UI
10509                      //   behaviors so we pass these through as true
10510
10511                      // Interestingly, opera fails the earlier test, so it doesn't
10512                      //  even make it here.
10513
10514                    } else if ( /^(url|email)$/.test(inputElemType) ) {
10515                      // Real url and email support comes with prebaked validation.
10516                      bool = inputElem.checkValidity && inputElem.checkValidity() === false;
10517
10518                    } else {
10519                      // If the upgraded input compontent rejects the :) text, we got a winner
10520                      bool = inputElem.value != smile;
10521                    }
10522                }
10523
10524                inputs[ props[i] ] = !!bool;
10525            }
10526            return inputs;
10527        })('search tel url email datetime date month week time datetime-local number range color'.split(' '));
10528        /*>>inputtypes*/
10529    }
10530    /*>>webforms*/
10531
10532
10533    // End of test definitions
10534    // -----------------------
10535
10536
10537
10538    // Run through all tests and detect their support in the current UA.
10539    // todo: hypothetically we could be doing an array of tests and use a basic loop here.
10540    for ( var feature in tests ) {
10541        if ( hasOwnProp(tests, feature) ) {
10542            // run the test, throw the return value into the Modernizr,
10543            //   then based on that boolean, define an appropriate className
10544            //   and push it into an array of classes we'll join later.
10545            featureName  = feature.toLowerCase();
10546            Modernizr[featureName] = tests[feature]();
10547
10548            classes.push((Modernizr[featureName] ? '' : 'no-') + featureName);
10549        }
10550    }
10551
10552    /*>>webforms*/
10553    // input tests need to run.
10554    Modernizr.input || webforms();
10555    /*>>webforms*/
10556
10557
10558    /**
10559     * addTest allows the user to define their own feature tests
10560     * the result will be added onto the Modernizr object,
10561     * as well as an appropriate className set on the html element
10562     *
10563     * @param feature - String naming the feature
10564     * @param test - Function returning true if feature is supported, false if not
10565     */
10566     Modernizr.addTest = function ( feature, test ) {
10567       if ( typeof feature == 'object' ) {
10568         for ( var key in feature ) {
10569           if ( hasOwnProp( feature, key ) ) {
10570             Modernizr.addTest( key, feature[ key ] );
10571           }
10572         }
10573       } else {
10574
10575         feature = feature.toLowerCase();
10576
10577         if ( Modernizr[feature] !== undefined ) {
10578           // we're going to quit if you're trying to overwrite an existing test
10579           // if we were to allow it, we'd do this:
10580           //   var re = new RegExp("\\b(no-)?" + feature + "\\b");
10581           //   docElement.className = docElement.className.replace( re, '' );
10582           // but, no rly, stuff 'em.
10583           return Modernizr;
10584         }
10585
10586         test = typeof test == 'function' ? test() : test;
10587
10588         if (typeof enableClasses !== "undefined" && enableClasses) {
10589           docElement.className += ' ' + (test ? '' : 'no-') + feature;
10590         }
10591         Modernizr[feature] = test;
10592
10593       }
10594
10595       return Modernizr; // allow chaining.
10596     };
10597
10598
10599    // Reset modElem.cssText to nothing to reduce memory footprint.
10600    setCss('');
10601    modElem = inputElem = null;
10602
10603    /*>>shiv*/
10604    /**
10605     * @preserve HTML5 Shiv prev3.7.1 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
10606     */
10607    ;(function(window, document) {
10608        /*jshint evil:true */
10609        /** version */
10610        var version = '3.7.0';
10611
10612        /** Preset options */
10613        var options = window.html5 || {};
10614
10615        /** Used to skip problem elements */
10616        var reSkip = /^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i;
10617
10618        /** Not all elements can be cloned in IE **/
10619        var saveClones = /^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i;
10620
10621        /** Detect whether the browser supports default html5 styles */
10622        var supportsHtml5Styles;
10623
10624        /** Name of the expando, to work with multiple documents or to re-shiv one document */
10625        var expando = '_html5shiv';
10626
10627        /** The id for the the documents expando */
10628        var expanID = 0;
10629
10630        /** Cached data for each document */
10631        var expandoData = {};
10632
10633        /** Detect whether the browser supports unknown elements */
10634        var supportsUnknownElements;
10635
10636        (function() {
10637          try {
10638            var a = document.createElement('a');
10639            a.innerHTML = '<xyz></xyz>';
10640            //if the hidden property is implemented we can assume, that the browser supports basic HTML5 Styles
10641            supportsHtml5Styles = ('hidden' in a);
10642
10643            supportsUnknownElements = a.childNodes.length == 1 || (function() {
10644              // assign a false positive if unable to shiv
10645              (document.createElement)('a');
10646              var frag = document.createDocumentFragment();
10647              return (
10648                typeof frag.cloneNode == 'undefined' ||
10649                typeof frag.createDocumentFragment == 'undefined' ||
10650                typeof frag.createElement == 'undefined'
10651              );
10652            }());
10653          } catch(e) {
10654            // assign a false positive if detection fails => unable to shiv
10655            supportsHtml5Styles = true;
10656            supportsUnknownElements = true;
10657          }
10658
10659        }());
10660
10661        /*--------------------------------------------------------------------------*/
10662
10663        /**
10664         * Creates a style sheet with the given CSS text and adds it to the document.
10665         * @private
10666         * @param {Document} ownerDocument The document.
10667         * @param {String} cssText The CSS text.
10668         * @returns {StyleSheet} The style element.
10669         */
10670        function addStyleSheet(ownerDocument, cssText) {
10671          var p = ownerDocument.createElement('p'),
10672          parent = ownerDocument.getElementsByTagName('head')[0] || ownerDocument.documentElement;
10673
10674          p.innerHTML = 'x<style>' + cssText + '</style>';
10675          return parent.insertBefore(p.lastChild, parent.firstChild);
10676        }
10677
10678        /**
10679         * Returns the value of `html5.elements` as an array.
vendor: 5,515 bytes, lines 10680-10819
10680         * @private
10681         * @returns {Array} An array of shived element node names.
10682         */
10683        function getElements() {
10684          var elements = html5.elements;
10685          return typeof elements == 'string' ? elements.split(' ') : elements;
10686        }
10687
10688        /**
10689         * Returns the data associated to the given document
10690         * @private
10691         * @param {Document} ownerDocument The document.
10692         * @returns {Object} An object of data.
10693         */
10694        function getExpandoData(ownerDocument) {
10695          var data = expandoData[ownerDocument[expando]];
10696          if (!data) {
10697            data = {};
10698            expanID++;
10699            ownerDocument[expando] = expanID;
10700            expandoData[expanID] = data;
10701          }
10702          return data;
10703        }
10704
10705        /**
10706         * returns a shived element for the given nodeName and document
10707         * @memberOf html5
10708         * @param {String} nodeName name of the element
10709         * @param {Document} ownerDocument The context document.
10710         * @returns {Object} The shived element.
10711         */
10712        function createElement(nodeName, ownerDocument, data){
10713          if (!ownerDocument) {
10714            ownerDocument = document;
10715          }
10716          if(supportsUnknownElements){
10717            return ownerDocument.createElement(nodeName);
10718          }
10719          if (!data) {
10720            data = getExpandoData(ownerDocument);
10721          }
10722          var node;
10723
10724          if (data.cache[nodeName]) {
10725            node = data.cache[nodeName].cloneNode();
10726          } else if (saveClones.test(nodeName)) {
10727            node = (data.cache[nodeName] = data.createElem(nodeName)).cloneNode();
10728          } else {
10729            node = data.createElem(nodeName);
10730          }
10731
10732          // Avoid adding some elements to fragments in IE < 9 because
10733          // * Attributes like `name` or `type` cannot be set/changed once an element
10734          //   is inserted into a document/fragment
10735          // * Link elements with `src` attributes that are inaccessible, as with
10736          //   a 403 response, will cause the tab/window to crash
10737          // * Script elements appended to fragments will execute when their `src`
10738          //   or `text` property is set
10739          return node.canHaveChildren && !reSkip.test(nodeName) && !node.tagUrn ? data.frag.appendChild(node) : node;
10740        }
10741
10742        /**
10743         * returns a shived DocumentFragment for the given document
10744         * @memberOf html5
10745         * @param {Document} ownerDocument The context document.
10746         * @returns {Object} The shived DocumentFragment.
10747         */
10748        function createDocumentFragment(ownerDocument, data){
10749          if (!ownerDocument) {
10750            ownerDocument = document;
10751          }
10752          if(supportsUnknownElements){
10753            return ownerDocument.createDocumentFragment();
10754          }
10755          data = data || getExpandoData(ownerDocument);
10756          var clone = data.frag.cloneNode(),
10757          i = 0,
10758          elems = getElements(),
10759          l = elems.length;
10760          for(;i<l;i++){
10761            clone.createElement(elems[i]);
10762          }
10763          return clone;
10764        }
10765
10766        /**
10767         * Shivs the `createElement` and `createDocumentFragment` methods of the document.
10768         * @private
10769         * @param {Document|DocumentFragment} ownerDocument The document.
10770         * @param {Object} data of the document.
10771         */
10772        function shivMethods(ownerDocument, data) {
10773          if (!data.cache) {
10774            data.cache = {};
10775            data.createElem = ownerDocument.createElement;
10776            data.createFrag = ownerDocument.createDocumentFragment;
10777            data.frag = data.createFrag();
10778          }
10779
10780
10781          ownerDocument.createElement = function(nodeName) {
10782            //abort shiv
10783            if (!html5.shivMethods) {
10784              return data.createElem(nodeName);
10785            }
10786            return createElement(nodeName, ownerDocument, data);
10787          };
10788
10789          ownerDocument.createDocumentFragment = Function('h,f', 'return function(){' +
10790                                                          'var n=f.cloneNode(),c=n.createElement;' +
10791                                                          'h.shivMethods&&(' +
10792                                                          // unroll the `createElement` calls
10793                                                          getElements().join().replace(/[\w\-]+/g, function(nodeName) {
10794            data.createElem(nodeName);
10795            data.frag.createElement(nodeName);
10796            return 'c("' + nodeName + '")';
10797          }) +
10798            ');return n}'
10799                                                         )(html5, data.frag);
10800        }
10801
10802        /*--------------------------------------------------------------------------*/
10803
10804        /**
10805         * Shivs the given document.
10806         * @memberOf html5
10807         * @param {Document} ownerDocument The document to shiv.
10808         * @returns {Document} The shived document.
10809         */
10810        function shivDocument(ownerDocument) {
10811          if (!ownerDocument) {
10812            ownerDocument = document;
10813          }
10814          var data = getExpandoData(ownerDocument);
10815
10816          if (html5.shivCSS && !supportsHtml5Styles && !data.hasCSS) {
10817            data.hasCSS = !!addStyleSheet(ownerDocument,
10818                                          // corrects block display not defined in IE6/7/8/9
10819                                          'article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{dis
10819play:block}' +
10820                                            // adds styling not present in IE6/7/8/9
10821                                            'mark{background:#FF0;color:#000}' +
10822                                            // hides non-rendered elements
10823                                            'template{display:none}'
10824                                         );
10825          }
10826          if (!supportsUnknownElements) {
10827            shivMethods(ownerDocument, data);
10828          }
10829          return ownerDocument;
10830        }
10831
10832        /*--------------------------------------------------------------------------*/
10833
10834        /**
10835         * The `html5` object is exposed so that more elements can be shived and
10836         * existing shiving can be detected on iframes.
10837         * @type Object
10838         * @example
10839         *
10840         * // options can be changed before the script is included
10841         * html5 = { 'elements': 'mark section', 'shivCSS': false, 'shivMethods': false };
10842         */
10843        var html5 = {
10844
10845          /**
10846           * An array or space separated string of node names of the elements to shiv.
10847           * @memberOf html5
10848           * @type Array|String
10849           */
10850          'elements': options.elements || 'abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output progress section summary template time video',
10851
10852          /**
10853           * current version of html5shiv
10854           */
10855          'version': version,
10856
10857          /**
10858           * A flag to indicate that the HTML5 style sheet should be inserted.
10859           * @memberOf html5
10860           * @type Boolean
10861           */
10862          'shivCSS': (options.shivCSS !== false),
10863
10864          /**
10865           * Is equal to true if a browser supports creating unknown/HTML5 elements
10866           * @memberOf html5
10867           * @type boolean
10868           */
10869          'supportsUnknownElements': supportsUnknownElements,
10870
10871          /**
10872           * A flag to indicate that the document's `createElement` and `createDocumentFragment`
10873           * methods should be overwritten.
10874           * @memberOf html5
10875           * @type Boolean
10876           */
10877          'shivMethods': (options.shivMethods !== false),
10878
10879          /**
10880           * A string to describe the type of `html5` object ("default" or "default print").
10881           * @memberOf html5
10882           * @type String
10883           */
10884          'type': 'default',
10885
10886          // shivs the document according to the specified `html5` object options
10887          'shivDocument': shivDocument,
10888
10889          //creates a shived element
10890          createElement: createElement,
10891
10892          //creates a shived documentFragment
10893          createDocumentFragment: createDocumentFragment
10894        };
10895
10896        /*--------------------------------------------------------------------------*/
10897
10898        // expose html5
10899        window.html5 = html5;
10900
10901        // shiv the document
10902        shivDocument(document);
10903
10904    }(this, document));
10905    /*>>shiv*/
10906
10907    // Assign private properties to the return object with prefix
10908    Modernizr._version      = version;
10909
10910    // expose these for the plugin API. Look in the source for how to join() them against your input
10911    /*>>prefixes*/
10912    Modernizr._prefixes     = prefixes;
10913    /*>>prefixes*/
10914    /*>>domprefixes*/
10915    Modernizr._domPrefixes  = domPrefixes;
10916    Modernizr._cssomPrefixes  = cssomPrefixes;
10917    /*>>domprefixes*/
10918
10919    /*>>mq*/
10920    // Modernizr.mq tests a given media query, live against the current state of the window
10921    // A few important notes:
10922    //   * If a browser does not support media queries at all (eg. oldIE) the mq() will always return false
10923    //   * A max-width or orientation query will be evaluated against the current state, which may change later.
10924    //   * You must specify values. Eg. If you are testing support for the min-width media query use:
10925    //       Modernizr.mq('(min-width:0)')
10926    // usage:
10927    // Modernizr.mq('only screen and (max-width:768)')
10928    Modernizr.mq            = testMediaQuery;
10929    /*>>mq*/
10930
10931    /*>>hasevent*/
10932    // Modernizr.hasEvent() detects support for a given event, with an optional element to test on
10933    // Modernizr.hasEvent('gesturestart', elem)
10934    Modernizr.hasEvent      = isEventSupported;
10935    /*>>hasevent*/
10936
10937    /*>>testprop*/
10938    // Modernizr.testProp() investigates whether a given style property is recognized
10939    // Note that the property names must be provided in the camelCase variant.
10940    // Modernizr.testProp('pointerEvents')
10941    Modernizr.testProp      = function(prop){
10942        return testProps([prop]);
10943    };
10944    /*>>testprop*/
10945
10946    /*>>testallprops*/
10947    // Modernizr.testAllProps() investigates whether a given style property,
10948    //   or any of its vendor-prefixed variants, is recognized
10949    // Note that the property names must be provided in the camelCase variant.
10950    // Modernizr.testAllProps('boxSizing')
10951    Modernizr.testAllProps  = testPropsAll;
10952    /*>>testallprops*/
10953
10954
10955    /*>>teststyles*/
10956    // Modernizr.testStyles() allows you to add custom styles to the document and test an element afterwards
10957    // Modernizr.testStyles('#modernizr { position:absolute }', function(elem, rule){ ... })
10958    Modernizr.testStyles    = injectElementWithStyles;
10959    /*>>teststyles*/
10960
10961
10962    /*>>prefixed*/
10963    // Modernizr.prefixed() returns the prefixed or nonprefixed property name variant of your input
10964    // Modernizr.prefixed('boxSizing') // 'MozBoxSizing'
10965
10966    // Properties must be passed as dom-style camelcase, rather than `box-sizing` hypentated style.
10967    // Return values will also be the camelCase variant, if you need to translate that to hypenated style use:
10968    //
10969    //     str.replace(/([A-Z])/g, function(str,m1){ return '-' + m1.toLowerCase(); }).replace(/^ms-/,'-ms-');
10970
10971    // If you're trying to ascertain which transition end event to bind to, you might do something like...
10972    //
10973    //     var transEndEventNames = {
10974    //       'WebkitTransition' : 'webkitTransitionEnd',
10975    //       'MozTransition'    : 'transitionend',
10976    //       'OTransition'      : 'oTransitionEnd',
10977    //       'msTransition'     : 'MSTransitionEnd',
10978    //       'transition'       : 'transitionend'
10979    //     },
10980    //     transEndEventName = transEndEventNames[ Modernizr.prefixed('transition') ];
10981
10982    Modernizr.prefixed      = function(prop, obj, elem){
10983      if(!obj) {
10984        return testPropsAll(prop, 'pfx');
10985      } else {
10986        // Testing DOM property e.g. Modernizr.prefixed('requestAnimationFrame', window) // 'mozRequestAnimationFrame'
10987        return testPropsAll(prop, obj, elem);
10988      }
10989    };
10990    /*>>prefixed*/
10991
10992
10993    /*>>cssclasses*/
10994    // Remove "no-js" class from <html> element, if it exists:
10995    docElement.className = docElement.className.replace(/(^|\s)no-js(\s|$)/, '$1$2') +
10996
10997                            // Add the new classes to the <html> element.
10998                            (enableClasses ? ' js ' + classes.join(' ') : '');
10999    /*>>cssclasses*/
11000
11001    return Modernizr;
11002
11003})(this, this.document);
11004
11005/*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */
11006/*! NOTE: If you're already including a window.matchMedia polyfill via Modernizr or otherwise, you don't need this part */
11007
11008window.respond_staus = "pending";
11009window.matchMedia = window.matchMedia || (function( doc, undefined ) {
11010  "use strict";
11011
11012  var bool,
11013      docElem = doc.documentElement,
11014      refNode = docElem.firstElementChild || docElem.firstChild,
11015      // fakeBody required for <FF4 when executed in <head>
11016      fakeBody = doc.createElement( "body" ),
11017      div = doc.createElement( "div" );
11018
11019  div.id = "mq-test-1";
11020  div.style.cssText = "position:absolute;top:-100em";
11021  fakeBody.style.background = "none";
11022  fakeBody.appendChild(div);
11023
11024  return function(q){
11025
11026    div.innerHTML = "&shy;<style media=\"" + q + "\"> #mq-test-1 { width: 42px; }</style>";
11027
11028    docElem.insertBefore( fakeBody, refNode );
11029    bool = div.offsetWidth === 42;
11030    docElem.removeChild( fakeBody );
11031
11032    return {
11033      matches: bool,
11034      media: q
11035    };
11036
11037  };
11038
11039}( document ));
11040
11041
11042
11043
11044
11045/*! Respond.js v1.3.0: min/max-width media query polyfill. (c) Scott Jehl. MIT/GPLv2 Lic. j.mp/respondjs  */
11046(function ( win ){
11047
11048	"use strict";
11049
11050	//exposed namespace
11051	var respond = {};
11052	win.respond = respond;
11053
11054	//define update even in native-mq-supporting browsers, to avoid errors
11055	respond.update = function(){ };
11056
11057	//expose media query support flag for external use
11058	respond.mediaQueriesSupported	= win.matchMedia && win.matchMedia( "only all" ).matches;
11059
11060	//if media queries are supported, exit here
11061	if( respond.mediaQueriesSupported ){
11062    return;
11063	}
11064
11065	//define vars
11066	var doc = win.document,
11067		docElem = doc.documentElement,
11068		mediastyles = [],
11069		rules = [],
11070		appendedEls = [],
11071		parsedSheets = {},
11072		resizeThrottle = 30,
11073		head = doc.getElementsByTagName( "head" )[0] || docElem,
11074		base = doc.getElementsByTagName( "base" )[0],
11075		links = head.getElementsByTagName( "link" ),
11076		requestQueue = [],
11077
11078		//loop stylesheets, send text content to translate
11079		ripCSS = function(){
11080
11081			for( var i = 0; i < links.length; i++ ){
11082				var sheet = links[ i ],
11083				href = sheet.href,
11084				media = sheet.media,
11085				isCSS = sheet.rel && sheet.rel.toLowerCase() === "stylesheet";
11086
11087				//only links plz and prevent re-parsing
11088				if( !!href && isCSS && !parsedSheets[ href ] ){
11089					// selectivizr exposes css through the rawCssText expando
11090					if (sheet.styleSheet && sheet.styleSheet.rawCssText) {
11091						translate( sheet.styleSheet.rawCssText, href, media );
11092						parsedSheets[ href ] = true;
11093					} else {
11094						if( (!/^([a-zA-Z:]*\/\/)/.test( href ) && !base) ||
11095							href.replace( RegExp.$1, "" ).split( "/" )[0] === win.location.host ){
11096							requestQueue.push( {
11097								href: href,
11098								media: media
11099							} );
11100						}
11101					}
11102				}
11103			}
11104			makeRequests();
11105		},
11106
11107		//recurse through request queue, get css text
11108		makeRequests	= function(){
11109			if( requestQueue.length ){
11110				var thisRequest = requestQueue.shift();
11111
11112				ajax( thisRequest.href, function( styles ){
11113					translate( styles, thisRequest.href, thisRequest.media );
11114					parsedSheets[ thisRequest.href ] = true;
11115
11116					// by wrapping recursive function call in setTimeout
11117					// we prevent "Stack overflow" error in IE7
11118					win.setTimeout(function(){ makeRequests(); },0);
11119				});
11120			} else {
11121        $(window).trigger("onRespondFinish");
11122      }
11123		},
11124
11125		//find media blocks in css text, convert to style blocks
11126		translate = function( styles, href, media ){
11127			var qs = styles.match(  /@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi ),
11128				ql = qs && qs.length || 0;
11129
11130			//try to get CSS path
11131			href = href.substring( 0, href.lastIndexOf( "/" ) );
11132
11133			var repUrls	= function( css ){
11134					return css.replace( /(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g, "$1" + href + "$2$3" );
11135				},
11136				useMedia = !ql && media;
11137
11138			//if path exists, tack on trailing slash
11139			if( href.length ){ href += "/"; }
11140
11141			//if no internal queries exist, but media attr does, use that
11142			//note: this currently lacks support for situations where a media attr is specified on a link AND
11143				//its associated stylesheet has internal CSS media queries.
11144				//In those cases, the media attribute will currently be ignored.
11145			if( useMedia ){
11146				ql = 1;
11147			}
11148
11149			for( var i = 0; i < ql; i++ ){
11150				var fullq, thisq, eachq, eql;
11151
11152				//media attr
11153				if( useMedia ){
11154					fullq = media;
11155					rules.push( repUrls( styles ) );
11156				}
11157				//parse for styles
11158				else{
11159					fullq = qs[ i ].match( /@media *([^\{]+)\{([\S\s]+?)$/ ) && RegExp.$1;
11160					rules.push( RegExp.$2 && repUrls( RegExp.$2 ) );
11161				}
11162
11163				eachq = fullq.split( "," );
11164				eql	= eachq.length;
11165
11166				for( var j = 0; j < eql; j++ ){
11167					thisq = eachq[ j ];
11168					mediastyles.push( {
11169						media : thisq.split( "(" )[ 0 ].match( /(only\s+)?([a-zA-Z]+)\s?/ ) && RegExp.$2 || "all",
11170						rules : rules.length - 1,
11171						hasquery : thisq.indexOf("(") > -1,
11172						minw : thisq.match( /\(\s*min\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/ ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" ),
11173						maxw : thisq.match( /\(\s*max\-width\s*:\s*(\s*[0-9\.]+)(px|em)\s*\)/ ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" )
11174					} );
11175				}
11176			}
11177
11178			applyMedia();
11179		},
11180
11181		lastCall,
11182
11183		resizeDefer,
11184
11185		// returns the value of 1em in pixels
11186		getEmValue = function() {
11187			var ret,
11188				div = doc.createElement('div'),
11189				body = doc.body,
11190				fakeUsed = false;
11191
11192			div.style.cssText = "position:absolute;font-size:1em;width:1em";
11193
11194			if( !body ){
11195				body = fakeUsed = doc.createElement( "body" );
11196				body.style.background = "none";
11197			}
11198
11199			body.appendChild( div );
11200
11201			docElem.insertBefore( body, docElem.firstChild );
11202
11203			ret = div.offsetWidth;
11204
11205			if( fakeUsed ){
11206				docElem.removeChild( body );
11207			}
11208			else {
11209				body.removeChild( div );
11210			}
11211
11212			//also update eminpx before returning
11213			ret = eminpx = parseFloat(ret);
11214
11215			return ret;
11216		},
11217
11218		//cached container for 1em value, populated the first time it's needed
11219		eminpx,
11220
11221		//enable/disable styles
11222		applyMedia = function( fromResize ){
11223			var name = "clientWidth",
11224				docElemProp = docElem[ name ],
11225				currWidth = doc.compatMode === "CSS1Compat" && docElemProp || doc.body[ name ] || docElemProp,
11226				styleBlocks	= {},
11227				lastLink = links[ links.length-1 ],
11228				now = (new Date()).getTime();
11229
11230			//throttle resize calls
11231			if( fromResize && lastCall && now - lastCall < resizeThrottle ){
11232				win.clearTimeout( resizeDefer );
11233				resizeDefer = win.setTimeout( applyMedia, resizeThrottle );
11234				return;
11235			}
11236			else {
11237				lastCall = now;
11238			}
11239
11240			for( var i in mediastyles ){
11241				if( mediastyles.hasOwnProperty( i ) ){
11242					var thisstyle = mediastyles[ i ],
11243						min = thisstyle.minw,
11244						max = thisstyle.maxw,
11245						minnull = min === null,
11246						maxnull = max === null,
11247						em = "em";
11248
11249					if( !!min ){
11250						min = parseFloat( min ) * ( min.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 );
11251					}
11252					if( !!max ){
11253						max = parseFloat( max ) * ( max.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 );
11254					}
11255
11256					// if there's no media query at all (the () part), or min or max is not null, and if either is present, they're true
11257					if( !thisstyle.hasquery || ( !minnull || !maxnull ) && ( minnull || currWidth >= min ) && ( maxnull || currWidth <= max ) ){
11258						if( !styleBlocks[ thisstyle.media ] ){
11259							styleBlocks[ thisstyle.media ] = [];
11260						}
11261						styleBlocks[ thisstyle.media ].push( rules[ thisstyle.rules ] );
11262					}
11263				}
11264			}
11265
11266			//remove any existing respond style element(s)
11267			for( var j in appendedEls ){
11268				if( appendedEls.hasOwnProperty( j ) ){
11269					if( appendedEls[ j ] && appendedEls[ j ].parentNode === head ){
11270						head.removeChild( appendedEls[ j ] );
11271					}
11272				}
11273			}
11274
11275			//inject active styles, grouped by media type
11276			for( var k in styleBlocks ){
11277				if( styleBlocks.hasOwnProperty( k ) ){
11278					var ss = doc.createElement( "style" ),
11279						css = styleBlocks[ k ].join( "\n" );
11280
11281					ss.type = "text/css";
11282					ss.media = k;
11283
11284					//originally, ss was appended to a documentFragment and sheets were appended in bulk.
11285					//this caused crashes in IE in a number of circumstances, such as when the HTML element had a bg image set, so appending beforehand seems best. Thanks to @dvelyk for the initial research on this one!
11286					head.insertBefore( ss, lastLink.nextSibling );
11287
11288					if ( ss.styleSheet ){
11289						ss.styleSheet.cssText = css;
11290					}
11291					else {
11292						ss.appendChild( doc.createTextNode( css ) );
11293					}
11294
11295					//push to appendedEls to track for later removal
11296					appendedEls.push( ss );
11297				}
11298			}
11299		},
11300		//tweaked Ajax functions from Quirksmode
11301		ajax = function( url, callback ) {
11302			var req = xmlHttp();
11303			if (!req){
11304				return;
11305			}
11306			req.open( "GET", url, true );
11307			req.onreadystatechange = function () {
11308				if ( req.readyState !== 4 || req.status !== 200 && req.status !== 304 ){
11309					return;
11310				}
11311				callback( req.responseText );
11312			};
11313			if ( req.readyState === 4 ){
11314				return;
11315			}
11316			req.send( null );
11317		},
11318		//define ajax obj
11319		xmlHttp = (function() {
11320			var xmlhttpmethod = false;
11321			try {
11322				xmlhttpmethod = new win.XMLHttpRequest();
11323			}
11324			catch( e ){
11325				xmlhttpmethod = new win.ActiveXObject( "Microsoft.XMLHTTP" );
11326			}
11327			return function(){
11328				return xmlhttpmethod;
11329			};
11330		})();
11331
11332	//translate CSS
11333	// ripCSS();
11334
11335	//expose update for re-running respond later on
11336	respond.update = ripCSS;
11337
11338	//adjust on resize
11339	function callMedia(){
11340		applyMedia( true );
11341	}
11342	if( win.addEventListener ){
11343		win.addEventListener( "resize", callMedia, false );
11344	}
11345	else if( win.attachEvent ){
11346		win.attachEvent( "onresize", callMedia );
11347	}
11348})(this);
11349
11350// hide content until everything is loaded -> this requires jQuery
11351$(document).ready(function(){
11352	if (!respond.mediaQueriesSupported) {
11353		// var body = document.getElementsByTagName("body")[0];
11354    // body.style.cssText = "display: none !important";
11355	}
11356});
11357
11358var split_css_queue = [];
11359$(document).ready(function(){
11360
11361  if (bowser.version != undefined) {
11362    var browser = "";
11363    version = bowser.version.split(".")[0];
11364    if (bowser.msie === true) {
11365      browser = "msie";
11366    }
11367
11368    // if there is an IE
11369    if(browser == "msie" && (version == "8" || version == "9")) {
11370
11371      // find css file
11372      var paths = [
11373      "bme2014.css"
11374      ];
11375      var stylesheets = $("head").find("link");
11376
11377      $(paths).each(function(){
11378        style = this.toString();
11379
11380        stylesheets.each(function(){
11381          $styletag = $(this);
11382          href = $(this).attr("href").toString();
11383          filename = href.match(/.*\/(.*)$/)[1];
11384          cleared_filename = filename.split("?")[0];
11385          filepath = href.replace(filename, "");
11386          filename_wo_extension = cleared_filename.replace(".css", "");
11387
11388          // replace stylesheets
11389          if (cleared_filename == style.toString()) {
11390            // check the file url
11391            if (filepath.indexOf("//") > -1) {
11392              toolbox = true;
11393            } else {
11394              toolbox = false;
11395            }
11396            fetch_stylesheets(cleared_filename, filename_wo_extension, filepath, toolbox, 0);
11397          }
11398        });
11399      });
11400    }
11401  }
11402});
11403
11404
11405function fetch_stylesheets(filename, filename_wo_extension, filepath, toolbox, iterator) {
11406  origin = window.location.protocol + "//" +  window.location.host;
11407
11408  if (toolbox) {
11409    if (iterator === 0) {
11410      path = filepath + "split_" + filename;
11411    } else {
11412      path = filepath + "split_" + filename_wo_extension + "-blessed" + iterator + ".css";
11413    }
11414  } else {
11415    if (iterator === 0) {
11416      path = origin + filepath + "split_" + filename;
11417    } else {
11418      path = origin + filepath + "split_" + filename_wo_extension + "-blessed" + iterator + ".css";
11419    }
11420  }
11421
11422  iterator++;
11423
11424  if (iterator <= 2) {
11425    split_css_queue.push(path);
11426    fetch_stylesheets(filename, filename_wo_extension, filepath, toolbox, iterator);
11427  } else {
11428    inject_css_to_head();
11429  }
11430}
11431
11432function inject_css_to_head(){
11433  split_css_queue.reverse();
11434
11435  $(split_css_queue).each(function(){
11436    path = this;
11437
11438    $("head link[rel='stylesheet']").last().after("<link rel='stylesheet' href='" + path + "' type='text/css' media='screen' data-proxy='true'>");
11439  });
11440
11441  window.respond_staus = "ready";
11442  window.respond.update();
11443}
11444
11445
11446function clear_params(url) {
11447  var oldURL = style.toString();
11448  var index = 0;
11449  var newURL = oldURL;
11450  index = oldURL.indexOf('?');
11451  if(index == -1){
11452    index = oldURL.indexOf('#');
11453  }
11454  if(index != -1){
11455    newURL = oldURL.substring(0, index);
11456  }
11457  return newURL;
11458}
11459
11460/*!
11461  * Bowser - a browser detector
11462  * https://github.com/ded/bowser
11463  * MIT License | (c) Dustin Diaz 2014
11464  */
11465
11466!function (name, definition) {
11467  if (typeof module != 'undefined' && module.exports) module.exports['browser'] = definition()
11468  else if (typeof define == 'function' && define.amd) define(definition)
11469  else this[name] = definition()
11470}('bowser', function () {
11471  /**
11472    * See useragents.js for examples of navigator.userAgent
11473    */
11474
11475  var t = true
11476
11477  function detect(ua) {
11478
11479    function getFirstMatch(regex) {
11480      var match = ua.match(regex);
11481      return (match && match.length > 1 && match[1]) || '';
11482    }
11483
11484    var iosdevice = getFirstMatch(/(ipod|iphone|ipad)/i).toLowerCase()
11485      , likeAndroid = /like android/i.test(ua)
11486      , android = !likeAndroid && /android/i.test(ua)
11487      , versionIdentifier = getFirstMatch(/version\/(\d+(\.\d+)?)/i)
11488      , tablet = /tablet/i.test(ua)
11489      , mobile = !tablet && /[^-]mobi/i.test(ua)
11490      , result
11491
11492    if (/opera|opr/i.test(ua)) {
11493      result = {
11494        name: 'Opera'
11495      , opera: t
11496      , version: versionIdentifier || getFirstMatch(/(?:opera|opr)[\s\/](\d+(\.\d+)?)/i)
11497      }
11498    }
11499    else if (/windows phone/i.test(ua)) {
11500      result = {
11501        name: 'Windows Phone'
11502      , windowsphone: t
11503      , msie: t
11504      , version: getFirstMatch(/iemobile\/(\d+(\.\d+)?)/i)
11505      }
11506    }
11507    else if (/msie|trident/i.test(ua)) {
11508      result = {
11509        name: 'Internet Explorer'
11510      , msie: t
11511      , version: getFirstMatch(/(?:msie |rv:)(\d+(\.\d+)?)/i)
11512      }
11513    }
11514    else if (/chrome|crios|crmo/i.test(ua)) {
11515      result = {
11516        name: 'Chrome'
11517      , chrome: t
11518      , version: getFirstMatch(/(?:chrome|crios|crmo)\/(\d+(\.\d+)?)/i)
11519      }
11520    }
11521    else if (iosdevice) {
11522      result = {
11523        name : iosdevice == 'iphone' ? 'iPhone' : iosdevice == 'ipad' ? 'iPad' : 'iPod'
11524      }
11525      // WTF: version is not part of user agent in web apps
11526      if (versionIdentifier) {
11527        result.version = versionIdentifier
11528      }
11529    }
11530    else if (/sailfish/i.test(ua)) {
11531      result = {
11532        name: 'Sailfish'
11533      , sailfish: t
11534      , version: getFirstMatch(/sailfish\s?browser\/(\d+(\.\d+)?)/i)
11535      }
11536    }
11537    else if (/seamonkey\//i.test(ua)) {
11538      result = {
11539        name: 'SeaMonkey'
11540      , seamonkey: t
11541      , version: getFirstMatch(/seamonkey\/(\d+(\.\d+)?)/i)
11542      }
11543    }
11544    else if (/firefox|iceweasel/i.test(ua)) {
11545      result = {
11546        name: 'Firefox'
11547      , firefox: t
11548      , version: getFirstMatch(/(?:firefox|iceweasel)[ \/](\d+(\.\d+)?)/i)
11549      }
11550      if (/\((mobile|tablet);[^\)]*rv:[\d\.]+\)/i.test(ua)) {
11551        result.firefoxos = t
11552      }
11553    }
11554    else if (/silk/i.test(ua)) {
11555      result =  {
11556        name: 'Amazon Silk'
11557      , silk: t
11558      , version : getFirstMatch(/silk\/(\d+(\.\d+)?)/i)
11559      }
11560    }
11561    else if (android) {
11562      result = {
11563        name: 'Android'
11564      , version: versionIdentifier
11565      }
11566    }
11567    else if (/phantom/i.test(ua)) {
11568      result = {
11569        name: 'PhantomJS'
11570      , phantom: t
11571      , version: getFirstMatch(/phantomjs\/(\d+(\.\d+)?)/i)
11572      }
11573    }
11574    else if (/blackberry|\bbb\d+/i.test(ua) || /rim\stablet/i.test(ua)) {
11575      result = {
11576        name: 'BlackBerry'
11577      , blackberry: t
11578      , version: versionIdentifier || getFirstMatch(/blackberry[\d]+\/(\d+(\.\d+)?)/i)
11579      }
11580    }
11581    else if (/(web|hpw)os/i.test(ua)) {
11582      result = {
11583        name: 'WebOS'
11584      , webos: t
11585      , version: versionIdentifier || getFirstMatch(/w(?:eb)?osbrowser\/(\d+(\.\d+)?)/i)
11586      };
11587      /touchpad\//i.test(ua) && (result.touchpad = t)
11588    }
11589    else if (/bada/i.test(ua)) {
11590      result = {
11591        name: 'Bada'
11592      , bada: t
11593      , version: getFirstMatch(/dolfin\/(\d+(\.\d+)?)/i)
11594      };
11595    }
11596    else if (/tizen/i.test(ua)) {
11597      result = {
11598        name: 'Tizen'
11599      , tizen: t
11600      , version: getFirstMatch(/(?:tizen\s?)?browser\/(\d+(\.\d+)?)/i) || versionIdentifier
11601      };
11602    }
11603    else if (/safari/i.test(ua)) {
11604      result = {
11605        name: 'Safari'
11606      , safari: t
11607      , version: versionIdentifier
11608      }
11609    }
11610    else result = {}
11611
11612    // set webkit or gecko flag for browsers based on these engines
11613    if (/(apple)?webkit/i.test(ua)) {
11614      result.name = result.name || "Webkit"
11615      result.webkit = t
11616      if (!result.version && versionIdentifier) {
11617        result.version = versionIdentifier
11618      }
11619    } else if (!result.opera && /gecko\//i.test(ua)) {
11620      result.name = result.name || "Gecko"
11621      result.gecko = t
11622      result.version = result.version || getFirstMatch(/gecko\/(\d+(\.\d+)?)/i)
11623    }
11624
11625    // set OS flags for platforms that have multiple browsers
11626    if (android || result.silk) {
11627      result.android = t
11628    } else if (iosdevice) {
11629      result[iosdevice] = t
11630      result.ios = t
11631    }
11632
11633    // OS version extraction
11634    var osVersion = '';
11635    if (iosdevice) {
11636      osVersion = getFirstMatch(/os (\d+([_\s]\d+)*) like mac os x/i);
11637      osVersion = osVersion.replace(/[_\s]/g, '.');
11638    } else if (android) {
11639      osVersion = getFirstMatch(/android[ \/-](\d+(\.\d+)*)/i);
11640    } else if (result.windowsphone) {
11641      osVersion = getFirstMatch(/windows phone (?:os)?\s?(\d+(\.\d+)*)/i);
11642    } else if (result.webos) {
11643      osVersion = getFirstMatch(/(?:web|hpw)os\/(\d+(\.\d+)*)/i);
11644    } else if (result.blackberry) {
11645      osVersion = getFirstMatch(/rim\stablet\sos\s(\d+(\.\d+)*)/i);
11646    } else if (result.bada) {
11647      osVersion = getFirstMatch(/bada\/(\d+(\.\d+)*)/i);
11648    } else if (result.tizen) {
11649      osVersion = getFirstMatch(/tizen[\/\s](\d+(\.\d+)*)/i);
11650    }
11651    if (osVersion) {
11652      result.osversion = osVersion;
11653    }
11654
11655    // device type extraction
11656    var osMajorVersion = osVersion.split('.')[0];
11657    if (tablet || iosdevice == 'ipad' || (android && (osMajorVersion == 3 || (osMajorVersion == 4 && !mobile))) || result.silk) {
11658      result.tablet = t
11659    } else if (mobile || iosdevice == 'iphone' || iosdevice == 'ipod' || android || result.blackberry || result.webos || result.bada) {
11660      result.mobile = t
11661    }
11662
11663    // Graded Browser Support
11664    // http://developer.yahoo.com/yui/articles/gbs
11665    if ((result.msie && result.version >= 10) ||
11666        (result.chrome && result.version >= 20) ||
11667        (result.firefox && result.version >= 20.0) ||
11668        (result.safari && result.version >= 6) ||
11669        (result.opera && result.version >= 10.0) ||
11670        (result.ios && result.osversion && result.osversion.split(".")[0] >= 6) ||
11671        (result.blackberry && result.version >= 10.1)
11672        ) {
11673      result.a = t;
11674    }
11675    else if ((result.msie && result.version < 10) ||
11676        (result.chrome && result.version < 20) ||
11677        (result.firefox && result.version < 20.0) ||
11678        (result.safari && result.version < 6) ||
11679        (result.opera && result.version < 10.0) ||
11680        (result.ios && result.osversion && result.osversion.split(".")[0] < 6)
11681        ) {
11682      result.c = t
11683    } else result.x = t
11684
11685    return result
11686  }
11687
11688  var bowser = detect(typeof navigator !== 'undefined' ? navigator.userAgent : '')
11689
11690
11691  /*
11692   * Set our detect method to the main bowser object so we can
11693   * reuse it to test other user agents.
11694   * This is needed to implement future tests.
11695   */
11696  bowser._detect = detect;
11697
11698  return bowser
11699});
11700
11701$(document).ready(function(){
11702
11703  window.bodyclasses = "undefinedBrowser";
11704
11705  // check if bowser is included
11706  if (typeof bowser == 'undefined') {
11707    console.log("you need to include bowser https://github.com/ded/bowser");
11708  } else {
11709
11710    if (bowser.version != undefined) {
11711      if (bowser.safari === true) {
11712        window.bodyclasses = "safari";
11713      } else if (bowser.msie === true) {
11714        window.bodyclasses = "msie";
11715      } else if (bowser.firefox === true) {
11716        window.bodyclasses = "firefox";
11717      } else if (bowser.chrome === true) {
11718        window.bodyclasses = "chrome";
11719      } else if (bowser.opera === true) {
11720        window.bodyclasses = "opera";
11721      } else if (bowser.iphone) {
11722        window.bodyclasses = "iphone";
11723      } else if (bowser.android) {
11724        window.bodyclasses = "android";
11725      } else if (bowser.ipad) {
11726        window.bodyclasses = "ipad";
11727      }
11728      window.bodyclasses += " " + window.bodyclasses + bowser.version.split(".")[0];
11729
11730      // mobile
11731      if(bowser.mobile != undefined && bowser.mobile === true) {
11732        window.bodyclasses = window.bodyclasses + " mobile";
11733      }
11734
11735      // tablet
11736      if(bowser.tablet != undefined && bowser.tablet === true) {
11737        window.bodyclasses = window.bodyclasses + " tablet";
11738      }
11739
11740      // desktop
11741      if(bowser.tablet == undefined && bowser.mobile == undefined) {
11742        window.bodyclasses = window.bodyclasses + " desktop";
11743      }
11744    }
11745
11746    $("body").addClass(window.bodyclasses);
11747  }
11748});
11749
11750(function($) {
11751
11752  $.fn.sharpness = function( options ) {
11753
11754    // Establish our default settings
11755    var settings = $.extend({
11756      browsers: null,
11757      attribute: 'data-hires',
11758      start: null,
11759      complete: null
11760    }, options);
11761
11762    return this.each( function() {
11763      // start everthing
11764      if ( $.isFunction( settings.start ) ) {
11765        settings.start.call( this );
11766      }
11767
11768      if (settings.browsers === null) {
11769        prepare_swap($(this), settings);
11770      } else {
11771        // check if we got everything
11772        if (typeof bowser === 'undefined') {
11773          console.log("you need to include bowser https://github.com/ded/bowser");
11774        } else if(typeof window.bodyclasses === 'undefined') {
11775          console.log("you need to include demography https://github.com/andrezimpel/demography");
11776        } else {
11777          match = false;
11778          classversion = window.bodyclasses.split(" ");
11779
11780          $(classversion).each(function(index){
11781            brws_class = classversion[index];
11782            result = jQuery.inArray( brws_class, settings.browsers );
11783            if (result !== -1) {
11784              match = true;
11785            }
11786          });
11787
11788          if (!match) {
11789            prepare_swap($(this), settings);
11790          }
11791        }
11792      }
11793
11794      // set the callback
11795      if ( $.isFunction( settings.complete ) ) {
11796        settings.complete.call( this );
11797      }
11798    });
11799  }
11800}(jQuery));
11801
11802// function
11803function prepare_swap(elem, settings) {
11804  $this = elem;
11805  var hires_src = $this.attr(settings.attribute);
11806  var src = $this.attr("src");
11807  var img = $this;
11808
11809  var img_call = $.ajax(hires_src)
11810  .success(function() {
11811
11812    // swap image if the hires alternative is available
11813    swap_hires_image(img, hires_src, src);
11814  });
11815}
11816
11817// replace images
11818function swap_hires_image(element, hires_src, src) {
11819  $(element).attr("src", null);
11820  $(element).attr("src", hires_src);
11821  $(element).attr("data-original-src", src);
11822}
11823
11824/* ========================================================================
11825 * Bootstrap: transition.js v3.0.2
11826 * http://getbootstrap.com/javascript/#transitions
11827 * ========================================================================
11828 * Copyright 2013 Twitter, Inc.
11829 *
11830 * Licensed under the Apache License, Version 2.0 (the "License");
11831 * you may not use this file except in compliance with the License.
11832 * You may obtain a copy of the License at
11833 *
11834 * http://www.apache.org/licenses/LICENSE-2.0
11835 *
11836 * Unless required by applicable law or agreed to in writing, software
11837 * distributed under the License is distributed on an "AS IS" BASIS,
11838 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11839 * See the License for the specific language governing permissions and
11840 * limitations under the License.
11841 * ======================================================================== */
11842
11843
11844+function ($) { "use strict";
11845
11846  // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
11847  // ============================================================
11848
11849  function transitionEnd() {
11850    var el = document.createElement('bootstrap')
11851
11852    var transEndEventNames = {
11853      'WebkitTransition' : 'webkitTransitionEnd'
11854    , 'MozTransition'    : 'transitionend'
11855    , 'OTransition'      : 'oTransitionEnd otransitionend'
11856    , 'transition'       : 'transitionend'
11857    }
11858
11859    for (var name in transEndEventNames) {
11860      if (el.style[name] !== undefined) {
11861        return { end: transEndEventNames[name] }
11862      }
11863    }
11864  }
11865
11866  // http://blog.alexmaccaw.com/css-transitions
11867  $.fn.emulateTransitionEnd = function (duration) {
11868    var called = false, $el = this
11869    $(this).one($.support.transition.end, function () { called = true })
11870    var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
11871    setTimeout(callback, duration)
11872    return this
11873  }
11874
11875  $(function () {
11876    $.support.transition = transitionEnd()
11877  })
11878
11879}(jQuery);
11880
11881/* ========================================================================
11882 * Bootstrap: alert.js v3.0.2
11883 * http://getbootstrap.com/javascript/#alerts
11884 * ========================================================================
11885 * Copyright 2013 Twitter, Inc.
11886 *
11887 * Licensed under the Apache License, Version 2.0 (the "License");
11888 * you may not use this file except in compliance with the License.
11889 * You may obtain a copy of the License at
11890 *
11891 * http://www.apache.org/licenses/LICENSE-2.0
11892 *
11893 * Unless required by applicable law or agreed to in writing, software
11894 * distributed under the License is distributed on an "AS IS" BASIS,
11895 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11896 * See the License for the specific language governing permissions and
11897 * limitations under the License.
11898 * ======================================================================== */
11899
11900
11901+function ($) { "use strict";
11902
11903  // ALERT CLASS DEFINITION
11904  // ======================
11905
11906  var dismiss = '[data-dismiss="alert"]'
11907  var Alert   = function (el) {
11908    $(el).on('click', dismiss, this.close)
11909  }
11910
11911  Alert.prototype.close = function (e) {
11912    var $this    = $(this)
11913    var selector = $this.attr('data-target')
11914
11915    if (!selector) {
11916      selector = $this.attr('href')
11917      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
11918    }
11919
11920    var $parent = $(selector)
11921
11922    if (e) e.preventDefault()
11923
11924    if (!$parent.length) {
11925      $parent = $this.hasClass('alert') ? $this : $this.parent()
11926    }
11927
11928    $parent.trigger(e = $.Event('close.bs.alert'))
11929
11930    if (e.isDefaultPrevented()) return
11931
11932    $parent.removeClass('in')
11933
11934    function removeElement() {
11935      $parent.trigger('closed.bs.alert').remove()
11936    }
11937
11938    $.support.transition && $parent.hasClass('fade') ?
11939      $parent
11940        .one($.support.transition.end, removeElement)
11941        .emulateTransitionEnd(150) :
11942      removeElement()
11943  }
11944
11945
11946  // ALERT PLUGIN DEFINITION
11947  // =======================
11948
11949  var old = $.fn.alert
11950
11951  $.fn.alert = function (option) {
11952    return this.each(function () {
11953      var $this = $(this)
11954      var data  = $this.data('bs.alert')
11955
11956      if (!data) $this.data('bs.alert', (data = new Alert(this)))
11957      if (typeof option == 'string') data[option].call($this)
11958    })
11959  }
11960
11961  $.fn.alert.Constructor = Alert
11962
11963
11964  // ALERT NO CONFLICT
11965  // =================
11966
11967  $.fn.alert.noConflict = function () {
11968    $.fn.alert = old
11969    return this
11970  }
11971
11972
11973  // ALERT DATA-API
11974  // ==============
11975
11976  $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)
11977
11978}(jQuery);
11979
11980/* ========================================================================
11981 * Bootstrap: button.js v3.0.2
11982 * http://getbootstrap.com/javascript/#buttons
11983 * ========================================================================
11984 * Copyright 2013 Twitter, Inc.
11985 *
11986 * Licensed under the Apache License, Version 2.0 (the "License");
11987 * you may not use this file except in compliance with the License.
11988 * You may obtain a copy of the License at
11989 *
11990 * http://www.apache.org/licenses/LICENSE-2.0
11991 *
11992 * Unless required by applicable law or agreed to in writing, software
11993 * distributed under the License is distributed on an "AS IS" BASIS,
11994 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11995 * See the License for the specific language governing permissions and
11996 * limitations under the License.
11997 * ======================================================================== */
11998
11999
12000+function ($) { "use strict";
12001
12002  // BUTTON PUBLIC CLASS DEFINITION
12003  // ==============================
12004
12005  var Button = function (element, options) {
12006    this.$element = $(element)
12007    this.options  = $.extend({}, Button.DEFAULTS, options)
12008  }
12009
12010  Button.DEFAULTS = {
12011    loadingText: 'loading...'
12012  }
12013
12014  Button.prototype.setState = function (state) {
12015    var d    = 'disabled'
12016    var $el  = this.$element
12017    var val  = $el.is('input') ? 'val' : 'html'
12018    var data = $el.data()
12019
12020    state = state + 'Text'
12021
12022    if (!data.resetText) $el.data('resetText', $el[val]())
12023
12024    $el[val](data[state] || this.options[state])
12025
12026    // push to event loop to allow forms to submit
12027    setTimeout(function () {
12028      state == 'loadingText' ?
12029        $el.addClass(d).attr(d, d) :
12030        $el.removeClass(d).removeAttr(d);
12031    }, 0)
12032  }
12033
12034  Button.prototype.toggle = function () {
12035    var $parent = this.$element.closest('[data-toggle="buttons"]')
12036
12037    if ($parent.length) {
12038      var $input = this.$element.find('input')
12039        .prop('checked', !this.$element.hasClass('active'))
12040        .trigger('change')
12041      if ($input.prop('type') === 'radio') $parent.find('.active').removeClass('active')
12042    }
12043
12044    this.$element.toggleClass('active')
12045  }
12046
12047
12048  // BUTTON PLUGIN DEFINITION
12049  // ========================
12050
12051  var old = $.fn.button
12052
12053  $.fn.button = function (option) {
12054    return this.each(function () {
12055      var $this   = $(this)
12056      var data    = $this.data('bs.button')
12057      var options = typeof option == 'object' && option
12058
12059      if (!data) $this.data('bs.button', (data = new Button(this, options)))
12060
12061      if (option == 'toggle') data.toggle()
12062      else if (option) data.setState(option)
12063    })
12064  }
12065
12066  $.fn.button.Constructor = Button
12067
12068
12069  // BUTTON NO CONFLICT
12070  // ==================
12071
12072  $.fn.button.noConflict = function () {
12073    $.fn.button = old
12074    return this
12075  }
12076
12077
12078  // BUTTON DATA-API
12079  // ===============
12080
12081  $(document).on('click.bs.button.data-api', '[data-toggle^=button]', function (e) {
12082    var $btn = $(e.target)
12083    if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
12084    $btn.button('toggle')
12085    e.preventDefault()
12086  })
12087
12088}(jQuery);
12089
12090/* ========================================================================
12091 * Bootstrap: carousel.js v3.0.2
12092 * http://getbootstrap.com/javascript/#carousel
12093 * ========================================================================
12094 * Copyright 2013 Twitter, Inc.
12095 *
12096 * Licensed under the Apache License, Version 2.0 (the "License");
12097 * you may not use this file except in compliance with the License.
12098 * You may obtain a copy of the License at
12099 *
12100 * http://www.apache.org/licenses/LICENSE-2.0
12101 *
12102 * Unless required by applicable law or agreed to in writing, software
12103 * distributed under the License is distributed on an "AS IS" BASIS,
12104 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12105 * See the License for the specific language governing permissions and
12106 * limitations under the License.
12107 * ======================================================================== */
12108
12109
12110+function ($) { "use strict";
12111
12112  // CAROUSEL CLASS DEFINITION
12113  // =========================
12114
12115  var Carousel = function (element, options) {
12116    this.$element    = $(element)
12117    this.$indicators = this.$element.find('.carousel-indicators')
12118    this.options     = options
12119    this.paused      =
12120    this.sliding     =
12121    this.interval    =
12122    this.$active     =
12123    this.$items      = null
12124
12125    this.options.pause == 'hover' && this.$element
12126      .on('mouseenter', $.proxy(this.pause, this))
12127      .on('mouseleave', $.proxy(this.cycle, this))
12128  }
12129
12130  Carousel.DEFAULTS = {
12131    interval: 5000
12132  , pause: 'hover'
12133  , wrap: true
12134  }
12135
12136  Carousel.prototype.cycle =  function (e) {
12137    e || (this.paused = false)
12138
12139    this.interval && clearInterval(this.interval)
12140
12141    this.options.interval
12142      && !this.paused
12143      && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
12144
12145    return this
12146  }
12147
12148  Carousel.prototype.getActiveIndex = function () {
12149    this.$active = this.$element.find('.item.active')
12150    this.$items  = this.$active.parent().children()
12151
12152    return this.$items.index(this.$active)
12153  }
12154
12155  Carousel.prototype.to = function (pos) {
12156    var that        = this
12157    var activeIndex = this.getActiveIndex()
12158
12159    if (pos > (this.$items.length - 1) || pos < 0) return
12160
12161    if (this.sliding)       return this.$element.one('slid', function () { that.to(pos) })
12162    if (activeIndex == pos) return this.pause().cycle()
12163
12164    return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos]))
12165  }
12166
12167  Carousel.prototype.pause = function (e) {
12168    e || (this.paused = true)
12169
12170    if (this.$element.find('.next, .prev').length && $.support.transition.end) {
12171      this.$element.trigger($.support.transition.end)
12172      this.cycle(true)
12173    }
12174
12175    this.interval = clearInterval(this.interval)
12176
12177    return this
12178  }
12179
12180  Carousel.prototype.next = function () {
12181    if (this.sliding) return
12182    return this.slide('next')
12183  }
12184
12185  Carousel.prototype.prev = function () {
12186    if (this.sliding) return
12187    return this.slide('prev')
12188  }
12189
12190  Carousel.prototype.slide = function (type, next) {
12191    var $active   = this.$element.find('.item.active')
12192    var $next     = next || $active[type]()
12193    var isCycling = this.interval
12194    var direction = type == 'next' ? 'left' : 'right'
12195    var fallback  = type == 'next' ? 'first' : 'last'
12196    var that      = this
12197
12198    if (!$next.length) {
12199      if (!this.options.wrap) return
12200      $next = this.$element.find('.item')[fallback]()
12201    }
12202
12203    this.sliding = true
12204
12205    isCycling && this.pause()
12206
12207    var e = $.Event('slide.bs.carousel', { relatedTarget: $next[0], direction: direction })
12208
12209    if ($next.hasClass('active')) return
12210
12211    if (this.$indicators.length) {
12212      this.$indicators.find('.active').removeClass('active')
12213      this.$element.one('slid', function () {
12214        var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()])
12215        $nextIndicator && $nextIndicator.addClass('active')
12216      })
12217    }
12218
12219    if ($.support.transition && this.$element.hasClass('slide')) {
12220      this.$element.trigger(e)
12221      if (e.isDefaultPrevented()) return
12222      $next.addClass(type)
12223      $next[0].offsetWidth // force reflow
12224      $active.addClass(direction)
12225      $next.addClass(direction)
12226      $active
12227        .one($.support.transition.end, function () {
12228          $next.removeClass([type, direction].join(' ')).addClass('active')
12229          $active.removeClass(['active', direction].join(' '))
12230          that.sliding = false
12231          setTimeout(function () { that.$element.trigger('slid') }, 0)
12232        })
12233        .emulateTransitionEnd(600)
12234    } else {
12235      this.$element.trigger(e)
12236      if (e.isDefaultPrevented()) return
12237      $active.removeClass('active')
12238      $next.addClass('active')
12239      this.sliding = false
12240      this.$element.trigger('slid')
12241    }
12242
12243    isCycling && this.cycle()
12244
12245    return this
12246  }
12247
12248
12249  // CAROUSEL PLUGIN DEFINITION
12250  // ==========================
12251
12252  var old = $.fn.carousel
12253
12254  $.fn.carousel = function (option) {
12255    return this.each(function () {
12256      var $this   = $(this)
12257      var data    = $this.data('bs.carousel')
12258      var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option)
12259      var action  = typeof option == 'string' ? option : options.slide
12260
12261      if (!data) $this.data('bs.carousel', (data = new Carousel(this, options)))
12262      if (typeof option == 'number') data.to(option)
12263      else if (action) data[action]()
12264      else if (options.interval) data.pause().cycle()
12265    })
12266  }
12267
12268  $.fn.carousel.Constructor = Carousel
12269
12270
12271  // CAROUSEL NO CONFLICT
12272  // ====================
12273
12274  $.fn.carousel.noConflict = function () {
12275    $.fn.carousel = old
12276    return this
12277  }
12278
12279
12280  // CAROUSEL DATA-API
12281  // =================
12282
12283  $(document).on('click.bs.carousel.data-api', '[data-slide], [data-slide-to]', function (e) {
12284    var $this   = $(this), href
12285    var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
12286    var options = $.extend({}, $target.data(), $this.data())
12287    var slideIndex = $this.attr('data-slide-to')
12288    if (slideIndex) options.interval = false
12289
12290    $target.carousel(options)
12291
12292    if (slideIndex = $this.attr('data-slide-to')) {
12293      $target.data('bs.carousel').to(slideIndex)
12294    }
12295
12296    e.preventDefault()
12297  })
12298
12299  $(window).on('load', function () {
12300    $('[data-ride="carousel"]').each(function () {
12301      var $carousel = $(this)
12302      $carousel.carousel($carousel.data())
12303    })
12304  })
12305
12306}(jQuery);
12307
12308/* ========================================================================
12309 * Bootstrap: collapse.js v3.0.2
12310 * http://getbootstrap.com/javascript/#collapse
12311 * ========================================================================
12312 * Copyright 2013 Twitter, Inc.
12313 *
12314 * Licensed under the Apache License, Version 2.0 (the "License");
12315 * you may not use this file except in compliance with the License.
12316 * You may obtain a copy of the License at
12317 *
12318 * http://www.apache.org/licenses/LICENSE-2.0
12319 *
12320 * Unless required by applicable law or agreed to in writing, software
12321 * distributed under the License is distributed on an "AS IS" BASIS,
12322 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12323 * See the License for the specific language governing permissions and
12324 * limitations under the License.
12325 * ======================================================================== */
12326
12327
12328+function ($) { "use strict";
12329
12330  // COLLAPSE PUBLIC CLASS DEFINITION
12331  // ================================
12332
12333  var Collapse = function (element, options) {
12334    this.$element      = $(element)
12335    this.options       = $.extend({}, Collapse.DEFAULTS, options)
12336    this.transitioning = null
12337
12338    if (this.options.parent) this.$parent = $(this.options.parent)
12339    if (this.options.toggle) this.toggle()
12340  }
12341
12342  Collapse.DEFAULTS = {
12343    toggle: true
12344  }
12345
12346  Collapse.prototype.dimension = function () {
12347    var hasWidth = this.$element.hasClass('width')
12348    return hasWidth ? 'width' : 'height'
12349  }
12350
12351  Collapse.prototype.show = function () {
12352    if (this.transitioning || this.$element.hasClass('in')) return
12353
12354    var startEvent = $.Event('show.bs.collapse')
12355    this.$element.trigger(startEvent)
12356    if (startEvent.isDefaultPrevented()) return
12357
12358    var actives = this.$parent && this.$parent.find('> .panel > .in')
12359
12360    if (actives && actives.length) {
12361      var hasData = actives.data('bs.collapse')
12362      if (hasData && hasData.transitioning) return
12363      actives.collapse('hide')
12364      hasData || actives.data('bs.collapse', null)
12365    }
12366
12367    var dimension = this.dimension()
12368
12369    this.$element
12370      .removeClass('collapse')
12371      .addClass('collapsing')
12372      [dimension](0)
12373
12374    this.transitioning = 1
12375
12376    var complete = function () {
12377      this.$element
12378        .removeClass('collapsing')
12379        .addClass('in')
12380        [dimension]('auto')
12381      this.transitioning = 0
12382      this.$element.trigger('shown.bs.collapse')
12383    }
12384
12385    if (!$.support.transition) return complete.call(this)
12386
12387    var scrollSize = $.camelCase(['scroll', dimension].join('-'))
12388
12389    this.$element
12390      .one($.support.transition.end, $.proxy(complete, this))
12391      .emulateTransitionEnd(350)
12392      [dimension](this.$element[0][scrollSize])
12393  }
12394
12395  Collapse.prototype.hide = function () {
12396    if (this.transitioning || !this.$element.hasClass('in')) return
12397
12398    var startEvent = $.Event('hide.bs.collapse')
12399    this.$element.trigger(startEvent)
12400    if (startEvent.isDefaultPrevented()) return
12401
12402    var dimension = this.dimension()
12403
12404    this.$element
12405      [dimension](this.$element[dimension]())
12406      [0].offsetHeight
12407
12408    this.$element
12409      .addClass('collapsing')
12410      .removeClass('collapse')
12411      .removeClass('in')
12412
12413    this.transitioning = 1
12414
12415    var complete = function () {
12416      this.transitioning = 0
12417      this.$element
12418        .trigger('hidden.bs.collapse')
12419        .removeClass('collapsing')
12420        .addClass('collapse')
12421    }
12422
12423    if (!$.support.transition) return complete.call(this)
12424
12425    this.$element
12426      [dimension](0)
12427      .one($.support.transition.end, $.proxy(complete, this))
12428      .emulateTransitionEnd(350)
12429  }
12430
12431  Collapse.prototype.toggle = function () {
12432    this[this.$element.hasClass('in') ? 'hide' : 'show']()
12433  }
12434
12435
12436  // COLLAPSE PLUGIN DEFINITION
12437  // ==========================
12438
12439  var old = $.fn.collapse
12440
12441  $.fn.collapse = function (option) {
12442    return this.each(function () {
12443      var $this   = $(this)
12444      var data    = $this.data('bs.collapse')
12445      var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
12446
12447      if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
12448      if (typeof option == 'string') data[option]()
12449    })
12450  }
12451
12452  $.fn.collapse.Constructor = Collapse
12453
12454
12455  // COLLAPSE NO CONFLICT
12456  // ====================
12457
12458  $.fn.collapse.noConflict = function () {
12459    $.fn.collapse = old
12460    return this
12461  }
12462
12463
12464  // COLLAPSE DATA-API
12465  // =================
12466
12467  $(document).on('click.bs.collapse.data-api', '[data-toggle=collapse]', function (e) {
12468    var $this   = $(this), href
12469    var target  = $this.attr('data-target')
12470        || e.preventDefault()
12471        || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7
12472    var $target = $(target)
12473    var data    = $target.data('bs.collapse')
12474    var option  = data ? 'toggle' : $this.data()
12475    var parent  = $this.attr('data-parent')
12476    var $parent = parent && $(parent)
12477
12478    if (!data || !data.transitioning) {
12479      if ($parent) $parent.find('[data-toggle=collapse][data-parent="' + parent + '"]').not($this).addClass('collapsed')
12480      $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed')
12481    }
12482
12483    $target.collapse(option)
12484  })
12485
12486}(jQuery);
12487
12488/* ========================================================================
12489 * Bootstrap: dropdown.js v3.0.2
12490 * http://getbootstrap.com/javascript/#dropdowns
12491 * ========================================================================
12492 * Copyright 2013 Twitter, Inc.
12493 *
12494 * Licensed under the Apache License, Version 2.0 (the "License");
12495 * you may not use this file except in compliance with the License.
12496 * You may obtain a copy of the License at
12497 *
12498 * http://www.apache.org/licenses/LICENSE-2.0
12499 *
12500 * Unless required by applicable law or agreed to in writing, software
12501 * distributed under the License is distributed on an "AS IS" BASIS,
12502 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12503 * See the License for the specific language governing permissions and
12504 * limitations under the License.
12505 * ======================================================================== */
12506
12507
12508+function ($) { "use strict";
12509
12510  // DROPDOWN CLASS DEFINITION
12511  // =========================
12512
12513  var backdrop = '.dropdown-backdrop'
12514  var toggle   = '[data-toggle=dropdown]'
12515  var Dropdown = function (element) {
12516    var $el = $(element).on('click.bs.dropdown', this.toggle)
12517  }
12518
12519  Dropdown.prototype.toggle = function (e) {
12520    var $this = $(this)
12521
12522    if ($this.is('.disabled, :disabled')) return
12523
12524    var $parent  = getParent($this)
12525    var isActive = $parent.hasClass('open')
12526
12527    clearMenus()
12528
12529    if (!isActive) {
12530      if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
12531        // if mobile we we use a backdrop because click events don't delegate
12532        $('<div class="dropdown-backdrop"/>').insertAfter($(this)).on('click', clearMenus)
12533      }
12534
12535      $parent.trigger(e = $.Event('show.bs.dropdown'))
12536
12537      if (e.isDefaultPrevented()) return
12538
12539      $parent
12540        .toggleClass('open')
12541        .trigger('shown.bs.dropdown')
12542
12543      $this.focus()
12544    }
12545
12546    return false
12547  }
12548
12549  Dropdown.prototype.keydown = function (e) {
12550    if (!/(38|40|27)/.test(e.keyCode)) return
12551
12552    var $this = $(this)
12553
12554    e.preventDefault()
12555    e.stopPropagation()
12556
12557    if ($this.is('.disabled, :disabled')) return
12558
12559    var $parent  = getParent($this)
12560    var isActive = $parent.hasClass('open')
12561
12562    if (!isActive || (isActive && e.keyCode == 27)) {
12563      if (e.which == 27) $parent.find(toggle).focus()
12564      return $this.click()
12565    }
12566
12567    var $items = $('[role=menu] li:not(.divider):visible a', $parent)
12568
12569    if (!$items.length) return
12570
12571    var index = $items.index($items.filter(':focus'))
12572
12573    if (e.keyCode == 38 && index > 0)                 index--                        // up
12574    if (e.keyCode == 40 && index < $items.length - 1) index++                        // down
12575    if (!~index)                                      index=0
12576
12577    $items.eq(index).focus()
12578  }
12579
12580  function clearMenus() {
12581    $(backdrop).remove()
12582    $(toggle).each(function (e) {
12583      var $parent = getParent($(this))
12584      if (!$parent.hasClass('open')) return
12585      $parent.trigger(e = $.Event('hide.bs.dropdown'))
12586      if (e.isDefaultPrevented()) return
12587      $parent.removeClass('open').trigger('hidden.bs.dropdown')
12588    })
12589  }
12590
12591  function getParent($this) {
12592    var selector = $this.attr('data-target')
12593
12594    if (!selector) {
12595      selector = $this.attr('href')
12596      selector = selector && /#/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
12597    }
12598
12599    var $parent = selector && $(selector)
12600
12601    return $parent && $parent.length ? $parent : $this.parent()
12602  }
12603
12604
12605  // DROPDOWN PLUGIN DEFINITION
12606  // ==========================
12607
12608  var old = $.fn.dropdown
12609
12610  $.fn.dropdown = function (option) {
12611    return this.each(function () {
12612      var $this = $(this)
12613      var data  = $this.data('dropdown')
12614
12615      if (!data) $this.data('dropdown', (data = new Dropdown(this)))
12616      if (typeof option == 'string') data[option].call($this)
12617    })
12618  }
12619
12620  $.fn.dropdown.Constructor = Dropdown
12621
12622
12623  // DROPDOWN NO CONFLICT
12624  // ====================
12625
12626  $.fn.dropdown.noConflict = function () {
12627    $.fn.dropdown = old
12628    return this
12629  }
12630
12631
12632  // APPLY TO STANDARD DROPDOWN ELEMENTS
12633  // ===================================
12634
12635  $(document)
12636    .on('click.bs.dropdown.data-api', clearMenus)
12637    .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
12638    .on('click.bs.dropdown.data-api'  , toggle, Dropdown.prototype.toggle)
12639    .on('keydown.bs.dropdown.data-api', toggle + ', [role=menu]' , Dropdown.prototype.keydown)
12640
12641}(jQuery);
12642
12643/* ========================================================================
12644 * Bootstrap: modal.js v3.0.2
12645 * http://getbootstrap.com/javascript/#modals
12646 * ========================================================================
12647 * Copyright 2013 Twitter, Inc.
12648 *
12649 * Licensed under the Apache License, Version 2.0 (the "License");
12650 * you may not use this file except in compliance with the License.
12651 * You may obtain a copy of the License at
12652 *
12653 * http://www.apache.org/licenses/LICENSE-2.0
12654 *
12655 * Unless required by applicable law or agreed to in writing, software
12656 * distributed under the License is distributed on an "AS IS" BASIS,
12657 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12658 * See the License for the specific language governing permissions and
12659 * limitations under the License.
12660 * ======================================================================== */
12661
12662
12663+function ($) { "use strict";
12664
12665  // MODAL CLASS DEFINITION
12666  // ======================
12667
12668  var Modal = function (element, options) {
12669    this.options   = options
12670    this.$element  = $(element)
12671    this.$backdrop =
12672    this.isShown   = null
12673
12674    if (this.options.remote) this.$element.load(this.options.remote)
12675  }
12676
12677  Modal.DEFAULTS = {
12678      backdrop: true
12679    , keyboard: true
12680    , show: true
12681  }
12682
12683  Modal.prototype.toggle = function (_relatedTarget) {
12684    return this[!this.isShown ? 'show' : 'hide'](_relatedTarget)
12685  }
12686
12687  Modal.prototype.show = function (_relatedTarget) {
12688    var that = this
12689    var e    = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
12690
12691    this.$element.trigger(e)
12692
12693    if (this.isShown || e.isDefaultPrevented()) return
12694
12695    this.isShown = true
12696
12697    this.escape()
12698
12699    this.$element.on('click.dismiss.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
12700
12701    this.backdrop(function () {
12702      var transition = $.support.transition && that.$element.hasClass('fade')
12703
12704      if (!that.$element.parent().length) {
12705        that.$element.appendTo(document.body) // don't move modals dom position
12706      }
12707
12708      that.$element.show()
12709
12710      if (transition) {
12711        that.$element[0].offsetWidth // force reflow
12712      }
12713
12714      that.$element
12715        .addClass('in')
12716        .attr('aria-hidden', false)
12717
12718      that.enforceFocus()
12719
12720      var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
12721
12722      transition ?
12723        that.$element.find('.modal-dialog') // wait for modal to slide in
12724          .one($.support.transition.end, function () {
12725            that.$element.focus().trigger(e)
12726          })
12727          .emulateTransitionEnd(300) :
12728        that.$element.focus().trigger(e)
12729    })
12730  }
12731
12732  Modal.prototype.hide = function (e) {
12733    if (e) e.preventDefault()
12734
12735    e = $.Event('hide.bs.modal')
12736
12737    this.$element.trigger(e)
12738
12739    if (!this.isShown || e.isDefaultPrevented()) return
12740
12741    this.isShown = false
12742
12743    this.escape()
12744
12745    $(document).off('focusin.bs.modal')
12746
12747    this.$element
12748      .removeClass('in')
12749      .attr('aria-hidden', true)
12750      .off('click.dismiss.modal')
12751
12752    $.support.transition && this.$element.hasClass('fade') ?
12753      this.$element
12754        .one($.support.transition.end, $.proxy(this.hideModal, this))
12755        .emulateTransitionEnd(300) :
12756      this.hideModal()
12757  }
12758
12759  Modal.prototype.enforceFocus = function () {
12760    $(document)
12761      .off('focusin.bs.modal') // guard against infinite focus loop
12762      .on('focusin.bs.modal', $.proxy(function (e) {
12763        if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {
12764          this.$element.focus()
12765        }
12766      }, this))
12767  }
12768
12769  Modal.prototype.escape = function () {
12770    if (this.isShown && this.options.keyboard) {
12771      this.$element.on('keyup.dismiss.bs.modal', $.proxy(function (e) {
12772        e.which == 27 && this.hide()
12773      }, this))
12774    } else if (!this.isShown) {
12775      this.$element.off('keyup.dismiss.bs.modal')
12776    }
12777  }
12778
12779  Modal.prototype.hideModal = function () {
12780    var that = this
12781    this.$element.hide()
12782    this.backdrop(function () {
12783      that.removeBackdrop()
12784      that.$element.trigger('hidden.bs.modal')
12785    })
12786  }
12787
12788  Modal.prototype.removeBackdrop = function () {
12789    this.$backdrop && this.$backdrop.remove()
12790    this.$backdrop = null
12791  }
12792
12793  Modal.prototype.backdrop = function (callback) {
12794    var that    = this
12795    var animate = this.$element.hasClass('fade') ? 'fade' : ''
12796
12797    if (this.isShown && this.options.backdrop) {
12798      var doAnimate = $.support.transition && animate
12799
12800      this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
12801        .appendTo(document.body)
12802
12803      this.$element.on('click.dismiss.modal', $.proxy(function (e) {
12804        if (e.target !== e.currentTarget) return
12805        this.options.backdrop == 'static'
12806          ? this.$element[0].focus.call(this.$element[0])
12807          : this.hide.call(this)
12808      }, this))
12809
12810      if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
12811
12812      this.$backdrop.addClass('in')
12813
12814      if (!callback) return
12815
12816      doAnimate ?
12817        this.$backdrop
12818          .one($.support.transition.end, callback)
12819          .emulateTransitionEnd(150) :
12820        callback()
12821
12822    } else if (!this.isShown && this.$backdrop) {
12823      this.$backdrop.removeClass('in')
12824
12825      $.support.transition && this.$element.hasClass('fade')?
12826        this.$backdrop
12827          .one($.support.transition.end, callback)
12828          .emulateTransitionEnd(150) :
12829        callback()
12830
12831    } else if (callback) {
12832      callback()
12833    }
12834  }
12835
12836
12837  // MODAL PLUGIN DEFINITION
12838  // =======================
12839
12840  var old = $.fn.modal
12841
12842  $.fn.modal = function (option, _relatedTarget) {
12843    return this.each(function () {
12844      var $this   = $(this)
12845      var data    = $this.data('bs.modal')
12846      var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)
12847
12848      if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
12849      if (typeof option == 'string') data[option](_relatedTarget)
12850      else if (options.show) data.show(_relatedTarget)
12851    })
12852  }
12853
12854  $.fn.modal.Constructor = Modal
12855
12856
12857  // MODAL NO CONFLICT
12858  // =================
12859
12860  $.fn.modal.noConflict = function () {
12861    $.fn.modal = old
12862    return this
12863  }
12864
12865
12866  // MODAL DATA-API
12867  // ==============
12868
12869  $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
12870    var $this   = $(this)
12871    var href    = $this.attr('href')
12872    var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) //strip for ie7
12873    var option  = $target.data('modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
12874
12875    e.preventDefault()
12876
12877    $target
12878      .modal(option, this)
12879      .one('hide', function () {
12880        $this.is(':visible') && $this.focus()
12881      })
12882  })
12883
12884  $(document)
12885    .on('show.bs.modal',  '.modal', function () { $(document.body).addClass('modal-open') })
12886    .on('hidden.bs.modal', '.modal', function () { $(document.body).removeClass('modal-open') })
12887
12888}(jQuery);
12889
12890/* ========================================================================
12891 * Bootstrap: tooltip.js v3.0.2
12892 * http://getbootstrap.com/javascript/#tooltip
12893 * Inspired by the original jQuery.tipsy by Jason Frame
12894 * ========================================================================
12895 * Copyright 2013 Twitter, Inc.
12896 *
12897 * Licensed under the Apache License, Version 2.0 (the "License");
12898 * you may not use this file except in compliance with the License.
12899 * You may obtain a copy of the License at
12900 *
12901 * http://www.apache.org/licenses/LICENSE-2.0
12902 *
12903 * Unless required by applicable law or agreed to in writing, software
12904 * distributed under the License is distributed on an "AS IS" BASIS,
12905 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12906 * See the License for the specific language governing permissions and
12907 * limitations under the License.
12908 * ======================================================================== */
12909
12910
12911+function ($) { "use strict";
12912
12913  // TOOLTIP PUBLIC CLASS DEFINITION
12914  // ===============================
12915
12916  var Tooltip = function (element, options) {
12917    this.type       =
12918    this.options    =
12919    this.enabled    =
12920    this.timeout    =
12921    this.hoverState =
12922    this.$element   = null
12923
12924    this.init('tooltip', element, options)
12925  }
12926
12927  Tooltip.DEFAULTS = {
12928    animation: true
12929  , placement: 'top'
12930  , selector: false
12931  , template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'
12932  , trigger: 'hover focus'
12933  , title: ''
12934  , delay: 0
12935  , html: false
12936  , container: false
12937  }
12938
12939  Tooltip.prototype.init = function (type, element, options) {
12940    this.enabled  = true
12941    this.type     = type
12942    this.$element = $(element)
12943    this.options  = this.getOptions(options)
12944
12945    var triggers = this.options.trigger.split(' ')
12946
12947    for (var i = triggers.length; i--;) {
12948      var trigger = triggers[i]
12949
12950      if (trigger == 'click') {
12951        this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
12952      } else if (trigger != 'manual') {
12953        var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focus'
12954        var eventOut = trigger == 'hover' ? 'mouseleave' : 'blur'
12955
12956        this.$element.on(eventIn  + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
12957        this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
12958      }
12959    }
12960
12961    this.options.selector ?
12962      (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
12963      this.fixTitle()
12964  }
12965
12966  Tooltip.prototype.getDefaults = function () {
12967    return Tooltip.DEFAULTS
12968  }
12969
12970  Tooltip.prototype.getOptions = function (options) {
12971    options = $.extend({}, this.getDefaults(), this.$element.data(), options)
12972
12973    if (options.delay && typeof options.delay == 'number') {
12974      options.delay = {
12975        show: options.delay
12976      , hide: options.delay
12977      }
12978    }
12979
12980    return options
12981  }
12982
12983  Tooltip.prototype.getDelegateOptions = function () {
12984    var options  = {}
12985    var defaults = this.getDefaults()
12986
12987    this._options && $.each(this._options, function (key, value) {
12988      if (defaults[key] != value) options[key] = value
12989    })
12990
12991    return options
12992  }
12993
12994  Tooltip.prototype.enter = function (obj) {
12995    var self = obj instanceof this.constructor ?
12996      obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
12997
12998    clearTimeout(self.timeout)
12999
13000    self.hoverState = 'in'
13001
13002    if (!self.options.delay || !self.options.delay.show) return self.show()
13003
13004    self.timeout = setTimeout(function () {
13005      if (self.hoverState == 'in') self.show()
13006    }, self.options.delay.show)
13007  }
13008
13009  Tooltip.prototype.leave = function (obj) {
13010    var self = obj instanceof this.constructor ?
13011      obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
13012
13013    clearTimeout(self.timeout)
13014
13015    self.hoverState = 'out'
13016
13017    if (!self.options.delay || !self.options.delay.hide) return self.hide()
13018
13019    self.timeout = setTimeout(function () {
13020      if (self.hoverState == 'out') self.hide()
13021    }, self.options.delay.hide)
13022  }
13023
13024  Tooltip.prototype.show = function () {
13025    var e = $.Event('show.bs.'+ this.type)
13026
13027    if (this.hasContent() && this.enabled) {
13028      this.$element.trigger(e)
13029
13030      if (e.isDefaultPrevented()) return
13031
13032      var $tip = this.tip()
13033
13034      this.setContent()
13035
13036      if (this.options.animation) $tip.addClass('fade')
13037
13038      var placement = typeof this.options.placement == 'function' ?
13039        this.options.placement.call(this, $tip[0], this.$element[0]) :
13040        this.options.placement
13041
13042      var autoToken = /\s?auto?\s?/i
13043      var autoPlace = autoToken.test(placement)
13044      if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
13045
13046      $tip
13047        .detach()
13048        .css({ top: 0, left: 0, display: 'block' })
13049        .addClass(placement)
13050
13051      this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
13052
13053      var pos          = this.getPosition()
13054      var actualWidth  = $tip[0].offsetWidth
13055      var actualHeight = $tip[0].offsetHeight
13056
13057      if (autoPlace) {
13058        var $parent = this.$element.parent()
13059
13060        var orgPlacement = placement
13061        var docScroll    = document.documentElement.scrollTop || document.body.scrollTop
13062        var parentWidth  = this.options.container == 'body' ? window.innerWidth  : $parent.outerWidth()
13063        var parentHeight = this.options.container == 'body' ? window.innerHeight : $parent.outerHeight()
13064        var parentLeft   = this.options.container == 'body' ? 0 : $parent.offset().left
13065
13066        placement = placement == 'bottom' && pos.top   + pos.height  + actualHeight - docScroll > parentHeight  ? 'top'    :
13067                    placement == 'top'    && pos.top   - docScroll   - actualHeight < 0                         ? 'bottom' :
13068                    placement == 'right'  && pos.right + actualWidth > parentWidth                              ? 'left'   :
13069                    placement == 'left'   && pos.left  - actualWidth < parentLeft                               ? 'right'  :
13070                    placement
13071
13072        $tip
13073          .removeClass(orgPlacement)
13074          .addClass(placement)
13075      }
13076
13077      var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
13078
13079      this.applyPlacement(calculatedOffset, placement)
13080      this.$element.trigger('shown.bs.' + this.type)
13081    }
13082  }
13083
13084  Tooltip.prototype.applyPlacement = function(offset, placement) {
13085    var replace
13086    var $tip   = this.tip()
13087    var width  = $tip[0].offsetWidth
13088    var height = $tip[0].offsetHeight
13089
13090    // manually read margins because getBoundingClientRect includes difference
13091    var marginTop = parseInt($tip.css('margin-top'), 10)
13092    var marginLeft = parseInt($tip.css('margin-left'), 10)
13093
13094    // we must check for NaN for ie 8/9
13095    if (isNaN(marginTop))  marginTop  = 0
13096    if (isNaN(marginLeft)) marginLeft = 0
13097
13098    offset.top  = offset.top  + marginTop
13099    offset.left = offset.left + marginLeft
13100
13101    $tip
13102      .offset(offset)
13103      .addClass('in')
13104
13105    // check to see if placing tip in new offset caused the tip to resize itself
13106    var actualWidth  = $tip[0].offsetWidth
13107    var actualHeight = $tip[0].offsetHeight
13108
13109    if (placement == 'top' && actualHeight != height) {
13110      replace = true
13111      offset.top = offset.top + height - actualHeight
13112    }
13113
13114    if (/bottom|top/.test(placement)) {
13115      var delta = 0
13116
13117      if (offset.left < 0) {
13118        delta       = offset.left * -2
13119        offset.left = 0
13120
13121        $tip.offset(offset)
13122
13123        actualWidth  = $tip[0].offsetWidth
13124        actualHeight = $tip[0].offsetHeight
13125      }
13126
13127      this.replaceArrow(delta - width + actualWidth, actualWidth, 'left')
13128    } else {
13129      this.replaceArrow(actualHeight - height, actualHeight, 'top')
13130    }
13131
13132    if (replace) $tip.offset(offset)
13133  }
13134
13135  Tooltip.prototype.replaceArrow = function(delta, dimension, position) {
13136    this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + "%") : '')
13137  }
13138
13139  Tooltip.prototype.setContent = function () {
13140    var $tip  = this.tip()
13141    var title = this.getTitle()
13142
13143    $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
13144    $tip.removeClass('fade in top bottom left right')
13145  }
13146
13147  Tooltip.prototype.hide = function () {
13148    var that = this
13149    var $tip = this.tip()
13150    var e    = $.Event('hide.bs.' + this.type)
13151
13152    function complete() {
13153      if (that.hoverState != 'in') $tip.detach()
13154    }
13155
13156    this.$element.trigger(e)
13157
13158    if (e.isDefaultPrevented()) return
13159
13160    $tip.removeClass('in')
13161
13162    $.support.transition && this.$tip.hasClass('fade') ?
13163      $tip
13164        .one($.support.transition.end, complete)
13165        .emulateTransitionEnd(150) :
13166      complete()
13167
13168    this.$element.trigger('hidden.bs.' + this.type)
13169
13170    return this
13171  }
13172
13173  Tooltip.prototype.fixTitle = function () {
13174    var $e = this.$element
13175    if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
13176      $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
13177    }
13178  }
13179
13180  Tooltip.prototype.hasContent = function () {
13181    return this.getTitle()
13182  }
13183
13184  Tooltip.prototype.getPosition = function () {
13185    var el = this.$element[0]
13186    return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : {
13187      width: el.offsetWidth
13188    , height: el.offsetHeight
13189    }, this.$element.offset())
13190  }
13191
13192  Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
13193    return placement == 'bottom' ? { top: pos.top + pos.height,   left: pos.left + pos.width / 2 - actualWidth / 2  } :
13194           placement == 'top'    ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2  } :
13195           placement == 'left'   ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
13196        /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width   }
13197  }
13198
13199  Tooltip.prototype.getTitle = function () {
13200    var title
13201    var $e = this.$element
13202    var o  = this.options
13203
13204    title = $e.attr('data-original-title')
13205      || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)
13206
13207    return title
13208  }
13209
13210  Tooltip.prototype.tip = function () {
13211    return this.$tip = this.$tip || $(this.options.template)
13212  }
13213
13214  Tooltip.prototype.arrow = function () {
13215    return this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow')
13216  }
13217
13218  Tooltip.prototype.validate = function () {
13219    if (!this.$element[0].parentNode) {
13220      this.hide()
13221      this.$element = null
13222      this.options  = null
13223    }
13224  }
13225
13226  Tooltip.prototype.enable = function () {
13227    this.enabled = true
13228  }
13229
13230  Tooltip.prototype.disable = function () {
13231    this.enabled = false
13232  }
13233
13234  Tooltip.prototype.toggleEnabled = function () {
13235    this.enabled = !this.enabled
13236  }
13237
13238  Tooltip.prototype.toggle = function (e) {
13239    var self = e ? $(e.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) : this
13240    self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
13241  }
13242
13243  Tooltip.prototype.destroy = function () {
13244    this.hide().$element.off('.' + this.type).removeData('bs.' + this.type)
13245  }
13246
13247
13248  // TOOLTIP PLUGIN DEFINITION
13249  // =========================
13250
13251  var old = $.fn.tooltip
13252
13253  $.fn.tooltip = function (option) {
13254    return this.each(function () {
13255      var $this   = $(this)
13256      var data    = $this.data('bs.tooltip')
13257      var options = typeof option == 'object' && option
13258
13259      if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
13260      if (typeof option == 'string') data[option]()
13261    })
13262  }
13263
13264  $.fn.tooltip.Constructor = Tooltip
13265
13266
13267  // TOOLTIP NO CONFLICT
13268  // ===================
13269
13270  $.fn.tooltip.noConflict = function () {
13271    $.fn.tooltip = old
13272    return this
13273  }
13274
13275}(jQuery);
13276
13277/* ========================================================================
13278 * Bootstrap: popover.js v3.0.2
13279 * http://getbootstrap.com/javascript/#popovers
13280 * ========================================================================
13281 * Copyright 2013 Twitter, Inc.
13282 *
13283 * Licensed under the Apache License, Version 2.0 (the "License");
13284 * you may not use this file except in compliance with the License.
13285 * You may obtain a copy of the License at
13286 *
13287 * http://www.apache.org/licenses/LICENSE-2.0
13288 *
13289 * Unless required by applicable law or agreed to in writing, software
13290 * distributed under the License is distributed on an "AS IS" BASIS,
13291 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13292 * See the License for the specific language governing permissions and
13293 * limitations under the License.
13294 * ======================================================================== */
13295
13296
13297+function ($) { "use strict";
13298
13299  // POPOVER PUBLIC CLASS DEFINITION
13300  // ===============================
13301
13302  var Popover = function (element, options) {
13303    this.init('popover', element, options)
13304  }
13305
13306  if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
13307
13308  Popover.DEFAULTS = $.extend({} , $.fn.tooltip.Constructor.DEFAULTS, {
13309    placement: 'right'
13310  , trigger: 'click'
13311  , content: ''
13312  , template: '<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
13313  })
13314
13315
13316  // NOTE: POPOVER EXTENDS tooltip.js
13317  // ================================
13318
13319  Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)
13320
13321  Popover.prototype.constructor = Popover
13322
13323  Popover.prototype.getDefaults = function () {
13324    return Popover.DEFAULTS
13325  }
13326
13327  Popover.prototype.setContent = function () {
13328    var $tip    = this.tip()
13329    var title   = this.getTitle()
13330    var content = this.getContent()
13331
13332    $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
13333    $tip.find('.popover-content')[this.options.html ? 'html' : 'text'](content)
13334
13335    $tip.removeClass('fade top bottom left right in')
13336
13337    // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
13338    // this manually by checking the contents.
13339    if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()
13340  }
13341
13342  Popover.prototype.hasContent = function () {
13343    return this.getTitle() || this.getContent()
13344  }
13345
13346  Popover.prototype.getContent = function () {
13347    var $e = this.$element
13348    var o  = this.options
13349
13350    return $e.attr('data-content')
13351      || (typeof o.content == 'function' ?
13352            o.content.call($e[0]) :
13353            o.content)
13354  }
13355
13356  Popover.prototype.arrow = function () {
13357    return this.$arrow = this.$arrow || this.tip().find('.arrow')
13358  }
13359
13360  Popover.prototype.tip = function () {
13361    if (!this.$tip) this.$tip = $(this.options.template)
13362    return this.$tip
13363  }
13364
13365
13366  // POPOVER PLUGIN DEFINITION
13367  // =========================
13368
13369  var old = $.fn.popover
13370
13371  $.fn.popover = function (option) {
13372    return this.each(function () {
13373      var $this   = $(this)
13374      var data    = $this.data('bs.popover')
13375      var options = typeof option == 'object' && option
13376
13377      if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
13378      if (typeof option == 'string') data[option]()
13379    })
13380  }
13381
13382  $.fn.popover.Constructor = Popover
13383
13384
13385  // POPOVER NO CONFLICT
13386  // ===================
13387
13388  $.fn.popover.noConflict = function () {
13389    $.fn.popover = old
13390    return this
13391  }
13392
13393}(jQuery);
13394
13395/* ========================================================================
13396 * Bootstrap: scrollspy.js v3.0.2
13397 * http://getbootstrap.com/javascript/#scrollspy
13398 * ========================================================================
13399 * Copyright 2013 Twitter, Inc.
13400 *
13401 * Licensed under the Apache License, Version 2.0 (the "License");
13402 * you may not use this file except in compliance with the License.
13403 * You may obtain a copy of the License at
13404 *
13405 * http://www.apache.org/licenses/LICENSE-2.0
13406 *
13407 * Unless required by applicable law or agreed to in writing, software
13408 * distributed under the License is distributed on an "AS IS" BASIS,
13409 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13410 * See the License for the specific language governing permissions and
13411 * limitations under the License.
13412 * ======================================================================== */
13413
13414
13415+function ($) { "use strict";
13416
13417  // SCROLLSPY CLASS DEFINITION
13418  // ==========================
13419
13420  function ScrollSpy(element, options) {
13421    var href
13422    var process  = $.proxy(this.process, this)
13423
13424    this.$element       = $(element).is('body') ? $(window) : $(element)
13425    this.$body          = $('body')
13426    this.$scrollElement = this.$element.on('scroll.bs.scroll-spy.data-api', process)
13427    this.options        = $.extend({}, ScrollSpy.DEFAULTS, options)
13428    this.selector       = (this.options.target
13429      || ((href = $(element).attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
13430      || '') + ' .nav li > a'
13431    this.offsets        = $([])
13432    this.targets        = $([])
13433    this.activeTarget   = null
13434
13435    this.refresh()
13436    this.process()
13437  }
13438
13439  ScrollSpy.DEFAULTS = {
13440    offset: 10
13441  }
13442
13443  ScrollSpy.prototype.refresh = function () {
13444    var offsetMethod = this.$element[0] == window ? 'offset' : 'position'
13445
13446    this.offsets = $([])
13447    this.targets = $([])
13448
13449    var self     = this
13450    var $targets = this.$body
13451      .find(this.selector)
13452      .map(function () {
13453        var $el   = $(this)
13454        var href  = $el.data('target') || $el.attr('href')
13455        var $href = /^#\w/.test(href) && $(href)
13456
13457        return ($href
13458          && $href.length
13459          && [[ $href[offsetMethod]().top + (!$.isWindow(self.$scrollElement.get(0)) && self.$scrollElement.scrollTop()), href ]]) || null
13460      })
13461      .sort(function (a, b) { return a[0] - b[0] })
13462      .each(function () {
13463        self.offsets.push(this[0])
13464        self.targets.push(this[1])
13465      })
13466  }
13467
13468  ScrollSpy.prototype.process = function () {
13469    var scrollTop    = this.$scrollElement.scrollTop() + this.options.offset
13470    var scrollHeight = this.$scrollElement[0].scrollHeight || this.$body[0].scrollHeight
13471    var maxScroll    = scrollHeight - this.$scrollElement.height()
13472    var offsets      = this.offsets
13473    var targets      = this.targets
13474    var activeTarget = this.activeTarget
13475    var i
13476
13477    if (scrollTop >= maxScroll) {
13478      return activeTarget != (i = targets.last()[0]) && this.activate(i)
13479    }
13480
13481    for (i = offsets.length; i--;) {
13482      activeTarget != targets[i]
13483        && scrollTop >= offsets[i]
13484        && (!offsets[i + 1] || scrollTop <= offsets[i + 1])
13485        && this.activate( targets[i] )
13486    }
13487  }
13488
13489  ScrollSpy.prototype.activate = function (target) {
13490    this.activeTarget = target
13491
13492    $(this.selector)
13493      .parents('.active')
13494      .removeClass('active')
13495
13496    var selector = this.selector
13497      + '[data-target="' + target + '"],'
13498      + this.selector + '[href="' + target + '"]'
13499
13500    var active = $(selector)
13501      .parents('li')
13502      .addClass('active')
13503
13504    if (active.parent('.dropdown-menu').length)  {
13505      active = active
13506        .closest('li.dropdown')
13507        .addClass('active')
13508    }
13509
13510    active.trigger('activate')
13511  }
13512
13513
13514  // SCROLLSPY PLUGIN DEFINITION
13515  // ===========================
13516
13517  var old = $.fn.scrollspy
13518
13519  $.fn.scrollspy = function (option) {
13520    return this.each(function () {
13521      var $this   = $(this)
13522      var data    = $this.data('bs.scrollspy')
13523      var options = typeof option == 'object' && option
13524
13525      if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))
13526      if (typeof option == 'string') data[option]()
13527    })
13528  }
13529
13530  $.fn.scrollspy.Constructor = ScrollSpy
13531
13532
13533  // SCROLLSPY NO CONFLICT
13534  // =====================
13535
13536  $.fn.scrollspy.noConflict = function () {
13537    $.fn.scrollspy = old
13538    return this
13539  }
13540
13541
13542  // SCROLLSPY DATA-API
13543  // ==================
13544
13545  $(window).on('load', function () {
13546    $('[data-spy="scroll"]').each(function () {
13547      var $spy = $(this)
13548      $spy.scrollspy($spy.data())
13549    })
13550  })
13551
13552}(jQuery);
13553
13554/* ========================================================================
13555 * Bootstrap: tab.js v3.0.2
13556 * http://getbootstrap.com/javascript/#tabs
13557 * ========================================================================
13558 * Copyright 2013 Twitter, Inc.
13559 *
13560 * Licensed under the Apache License, Version 2.0 (the "License");
13561 * you may not use this file except in compliance with the License.
13562 * You may obtain a copy of the License at
13563 *
13564 * http://www.apache.org/licenses/LICENSE-2.0
13565 *
13566 * Unless required by applicable law or agreed to in writing, software
13567 * distributed under the License is distributed on an "AS IS" BASIS,
13568 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13569 * See the License for the specific language governing permissions and
13570 * limitations under the License.
13571 * ======================================================================== */
13572
13573
13574+function ($) { "use strict";
13575
13576  // TAB CLASS DEFINITION
13577  // ====================
13578
13579  var Tab = function (element) {
13580    this.element = $(element)
13581  }
13582
13583  Tab.prototype.show = function () {
13584    var $this    = this.element
13585    var $ul      = $this.closest('ul:not(.dropdown-menu)')
13586    var selector = $this.data('target')
13587
13588    if (!selector) {
13589      selector = $this.attr('href')
13590      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
13591    }
13592
13593    if ($this.parent('li').hasClass('active')) return
13594
13595    var previous = $ul.find('.active:last a')[0]
13596    var e        = $.Event('show.bs.tab', {
13597      relatedTarget: previous
13598    })
13599
13600    $this.trigger(e)
13601
13602    if (e.isDefaultPrevented()) return
13603
13604    var $target = $(selector)
13605
13606    this.activate($this.parent('li'), $ul)
13607    this.activate($target, $target.parent(), function () {
13608      $this.trigger({
13609        type: 'shown.bs.tab'
13610      , relatedTarget: previous
13611      })
13612    })
13613  }
13614
13615  Tab.prototype.activate = function (element, container, callback) {
13616    var $active    = container.find('> .active')
13617    var transition = callback
13618      && $.support.transition
13619      && $active.hasClass('fade')
13620
13621    function next() {
13622      $active
13623        .removeClass('active')
13624        .find('> .dropdown-menu > .active')
13625        .removeClass('active')
13626
13627      element.addClass('active')
13628
13629      if (transition) {
13630        element[0].offsetWidth // reflow for transition
13631        element.addClass('in')
13632      } else {
13633        element.removeClass('fade')
13634      }
13635
13636      if (element.parent('.dropdown-menu')) {
13637        element.closest('li.dropdown').addClass('active')
13638      }
13639
13640      callback && callback()
13641    }
13642
13643    transition ?
13644      $active
13645        .one($.support.transition.end, next)
13646        .emulateTransitionEnd(150) :
13647      next()
13648
13649    $active.removeClass('in')
13650  }
13651
13652
13653  // TAB PLUGIN DEFINITION
13654  // =====================
13655
13656  var old = $.fn.tab
13657
13658  $.fn.tab = function ( option ) {
13659    return this.each(function () {
13660      var $this = $(this)
13661      var data  = $this.data('bs.tab')
13662
13663      if (!data) $this.data('bs.tab', (data = new Tab(this)))
13664      if (typeof option == 'string') data[option]()
13665    })
13666  }
13667
13668  $.fn.tab.Constructor = Tab
13669
13670
13671  // TAB NO CONFLICT
13672  // ===============
13673
13674  $.fn.tab.noConflict = function () {
13675    $.fn.tab = old
13676    return this
13677  }
13678
13679
13680  // TAB DATA-API
13681  // ============
13682
13683  $(document).on('click.bs.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
13684    e.preventDefault()
13685    $(this).tab('show')
13686  })
13687
13688}(jQuery);
13689
13690/* ========================================================================
13691 * Bootstrap: affix.js v3.2.0
13692 * http://getbootstrap.com/javascript/#affix
13693 * ========================================================================
13694 * Copyright 2011-2014 Twitter, Inc.
13695 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
13696 * ======================================================================== */
13697
13698
13699+function ($) {
13700  'use strict';
13701
13702  // AFFIX CLASS DEFINITION
13703  // ======================
13704
13705  var Affix = function (element, options) {
13706    this.options = $.extend({}, Affix.DEFAULTS, options)
13707
13708    this.$target = $(this.options.target)
13709      .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))
13710      .on('click.bs.affix.data-api',  $.proxy(this.checkPositionWithEventLoop, this))
13711
13712    this.$element     = $(element)
13713    this.affixed      =
13714    this.unpin        =
13715    this.pinnedOffset = null
13716
13717    this.checkPosition()
13718  }
13719
13720  Affix.VERSION  = '3.2.0'
13721
13722  Affix.RESET    = 'affix affix-top affix-bottom'
13723
13724  Affix.DEFAULTS = {
13725    offset: 0,
13726    target: window
13727  }
13728
13729  Affix.prototype.getPinnedOffset = function () {
13730    if (this.pinnedOffset) return this.pinnedOffset
13731    this.$element.removeClass(Affix.RESET).addClass('affix')
13732    var scrollTop = this.$target.scrollTop()
13733    var position  = this.$element.offset()
13734    return (this.pinnedOffset = position.top - scrollTop)
13735  }
13736
13737  Affix.prototype.checkPositionWithEventLoop = function () {
13738    setTimeout($.proxy(this.checkPosition, this), 1)
13739  }
13740
13741  Affix.prototype.checkPosition = function () {
13742    if (!this.$element.is(':visible')) return
13743
13744    var scrollHeight = $(document).height()
13745    var scrollTop    = this.$target.scrollTop()
13746    var position     = this.$element.offset()
13747    var offset       = this.options.offset
13748    var offsetTop    = offset.top
13749    var offsetBottom = offset.bottom
13750
13751    if (typeof offset != 'object')         offsetBottom = offsetTop = offset
13752    if (typeof offsetTop == 'function')    offsetTop    = offset.top(this.$element)
13753    if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)
13754
13755    var affix = this.unpin   != null && (scrollTop + this.unpin <= position.top) ? false :
13756                offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ? 'bottom' :
13757                offsetTop    != null && (scrollTop <= offsetTop) ? 'top' : false
13758
13759    if (this.affixed === affix) return
13760    if (this.unpin != null) this.$element.css('top', '')
13761
13762    var affixType = 'affix' + (affix ? '-' + affix : '')
13763    var e         = $.Event(affixType + '.bs.affix')
13764
13765    this.$element.trigger(e)
13766
13767    if (e.isDefaultPrevented()) return
13768
13769    this.affixed = affix
13770    this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null
13771
13772    this.$element
13773      .removeClass(Affix.RESET)
13774      .addClass(affixType)
13775      .trigger($.Event(affixType.replace('affix', 'affixed')))
13776      
13777
13778    if (affix == 'bottom') {
13779      this.$element.offset({
13780        top: scrollHeight - this.$element.height() - offsetBottom
13781      })
13782    }
13783  }
13784
13785
13786  // AFFIX PLUGIN DEFINITION
13787  // =======================
13788
13789  function Plugin(option) {
13790    return this.each(function () {
13791      var $this   = $(this)
13792      var data    = $this.data('bs.affix')
13793      var options = typeof option == 'object' && option
13794
13795      if (!data) $this.data('bs.affix', (data = new Affix(this, options)))
13796      if (typeof option == 'string') data[option]()
13797    })
13798  }
13799
13800  var old = $.fn.affix
13801
13802  $.fn.affix             = Plugin
13803  $.fn.affix.Constructor = Affix
13804
13805
13806  // AFFIX NO CONFLICT
13807  // =================
13808
13809  $.fn.affix.noConflict = function () {
13810    $.fn.affix = old
13811    return this
13812  }
13813
13814
13815  // AFFIX DATA-API
13816  // ==============
13817
13818  $(window).on('load', function () {
13819    $('[data-spy="affix"]').each(function () {
13820      var $spy = $(this)
13821      var data = $spy.data()
13822
13823      data.offset = data.offset || {}
13824
13825      if (data.offsetBottom) data.offset.bottom = data.offsetBottom
13826      if (data.offsetTop)    data.offset.top    = data.offsetTop
13827
13828      Plugin.call($spy, data)
13829    })
13830  })
13831
13832}(jQuery);
13833
13834/*
13835 * blueimp Gallery JS 2.14.0
13836 * https://github.com/blueimp/Gallery
13837 *
13838 * Copyright 2013, Sebastian Tschan
13839 * https://blueimp.net
13840 *
13841 * Swipe implementation based on
13842 * https://github.com/bradbirdsall/Swipe
13843 *
13844 * Licensed under the MIT license:
13845 * http://www.opensource.org/licenses/MIT
13846 */
13847
13848/* global define, window, document, DocumentTouch */
13849
13850(function (factory) {
13851    'use strict';
13852    if (typeof define === 'function' && define.amd) {
13853        // Register as an anonymous AMD module:
13854        define(['./blueimp-helper'], factory);
13855    } else {
13856        // Browser globals:
13857        window.blueimp = window.blueimp || {};
13858        window.blueimp.Gallery = factory(
13859            window.blueimp.helper || window.jQuery
13860        );
13861    }
13862}(function ($) {
13863    'use strict';
13864
13865    function Gallery(list, options) {
13866        if (document.body.style.maxHeight === undefined) {
13867            // document.body.style.maxHeight is undefined on IE6 and lower
13868            return null;
13869        }
13870        if (!this || this.options !== Gallery.prototype.options) {
13871            // Called as function instead of as constructor,
13872            // so we simply return a new instance:
13873            return new Gallery(list, options);
13874        }
13875        if (!list || !list.length) {
13876            this.console.log(
13877                'blueimp Gallery: No or empty list provided as first argument.',
13878                list
13879            );
13880            return;
13881        }
13882        this.list = list;
13883        this.num = list.length;
13884        this.initOptions(options);
13885        this.initialize();
13886    }
13887
13888    $.extend(Gallery.prototype, {
13889
13890        options: {
13891            // The Id, element or querySelector of the gallery widget:
13892            container: '#blueimp-gallery',
13893            // The tag name, Id, element or querySelector of the slides container:
13894            slidesContainer: 'div',
13895            // The tag name, Id, element or querySelector of the title element:
13896            titleElement: 'h3',
13897            // The class to add when the gallery is visible:
13898            displayClass: 'blueimp-gallery-display',
13899            // The class to add when the gallery controls are visible:
13900            controlsClass: 'blueimp-gallery-controls',
13901            // The class to add when the gallery only displays one element:
13902            singleClass: 'blueimp-gallery-single',
13903            // The class to add when the left edge has been reached:
13904            leftEdgeClass: 'blueimp-gallery-left',
13905            // The class to add when the right edge has been reached:
13906            rightEdgeClass: 'blueimp-gallery-right',
13907            // The class to add when the automatic slideshow is active:
13908            playingClass: 'blueimp-gallery-playing',
13909            // The class for all slides:
13910            slideClass: 'slide',
13911            // The slide class for loading elements:
13912            slideLoadingClass: 'slide-loading',
13913            // The slide class for elements that failed to load:
13914            slideErrorClass: 'slide-error',
13915            // The class for the content element loaded into each slide:
13916            slideContentClass: 'slide-content',
13917            // The class for the "toggle" control:
13918            toggleClass: 'toggle',
13919            // The class for the "prev" control:
13920            prevClass: 'prev',
13921            // The class for the "next" control:
13922            nextClass: 'next',
13923            // The class for the "close" control:
13924            closeClass: 'close',
13925            // The class for the "play-pause" toggle control:
13926            playPauseClass: 'play-pause',
13927            // The list object property (or data attribute) with the object type:
13928            typeProperty: 'type',
13929            // The list object property (or data attribute) with the object title:
13930            titleProperty: 'title',
13931            // The list object property (or data attribute) with the object URL:
13932            urlProperty: 'href',
13933            // The gallery listens for transitionend events before triggering the
13934            // opened and closed events, unless the following option is set to false:
13935            displayTransition: true,
13936            // Defines if the gallery slides are cleared from the gallery modal,
13937            // or reused for the next gallery initialization:
13938            clearSlides: true,
13939            // Defines if images should be stretched to fill the available space,
13940            // while maintaining their aspect ratio (will only be enabled for browsers
13941            // supporting background-size="contain", which excludes IE < 9).
13942            // Set to "cover", to make images cover all available space (requires
13943            // support for background-size="cover", which excludes IE < 9):
13944            stretchImages: false,
13945            // Toggle the controls on pressing the Return key:
13946            toggleControlsOnReturn: true,
13947            // Toggle the automatic slideshow interval on pressing the Space key:
13948            toggleSlideshowOnSpace: true,
13949            // Navigate the gallery by pressing left and right on the keyboard:
13950            enableKeyboardNavigation: true,
13951            // Close the gallery on pressing the Esc key:
13952            closeOnEscape: true,
13953            // Close the gallery when clicking on an empty slide area:
13954            closeOnSlideClick: true,
13955            // Close the gallery by swiping up or down:
13956            closeOnSwipeUpOrDown: true,
13957            // Emulate touch events on mouse-pointer devices such as desktop browsers:
13958            emulateTouchEvents: true,
13959            // Stop touch events from bubbling up to ancestor elements of the Gallery:
13960            stopTouchEventsPropagation: false,
13961            // Hide the page scrollbars: 
13962            hidePageScrollbars: true,
13963            // Stops any touches on the container from scrolling the page:
13964            disableScroll: true,
13965            // Carousel mode (shortcut for carousel specific options):
13966            carousel: false,
13967            // Allow continuous navigation, moving from last to first
13968            // and from first to last slide:
13969            continuous: true,
13970            // Remove elements outside of the preload range from the DOM:
13971            unloadElements: true,
13972            // Start with the automatic slideshow:
13973            startSlideshow: false,
13974            // Delay in milliseconds between slides for the automatic slideshow:
13975            slideshowInterval: 5000,
13976            // The starting index as integer.
13977            // Can also be an object of the given list,
13978            // or an equal object with the same url property:
13979            index: 0,
13980            // The number of elements to load around the current index:
13981            preloadRange: 2,
13982            // The transition speed between slide changes in milliseconds:
13983            transitionSpeed: 400,
13984            // The transition speed for automatic slide changes, set to an integer
13985            // greater 0 to override the default transition speed:
13986            slideshowTransitionSpeed: undefined,
13987            // The event object for which the default action will be canceled
13988            // on Gallery initialization (e.g. the click event to open the Gallery):
13989            event: undefined,
13990            // Callback function executed when the Gallery is initialized.
13991            // Is called with the gallery instance as "this" object:
13992            onopen: undefined,
13993            // Callback function executed when the Gallery has been initialized
13994            // and the initialization transition has been completed.
13995            // Is called with the gallery instance as "this" object:
13996            onopened: undefined,
13997            // Callback function executed on slide change.
13998            // Is called with the gallery instance as "this" object and the
13999            // current index and slide as arguments:
14000            onslide: undefined,
14001            // Callback function executed after the slide change transition.
14002            // Is called with the gallery instance as "this" object and the
14003            // current index and slide as arguments:
14004            onslideend: undefined,
14005            // Callback function executed on slide content load.
14006            // Is called with the gallery instance as "this" object and the
14007            // slide index and slide element as arguments:
14008            onslidecomplete: undefined,
14009            // Callback function executed when the Gallery is about to be closed.
14010            // Is called with the gallery instance as "this" object:
14011            onclose: undefined,
14012            // Callback function executed when the Gallery has been closed
14013            // and the closing transition has been completed.
14014            // Is called with the gallery instance as "this" object:
14015            onclosed: undefined
14016        },
14017
14018        carouselOptions: {
14019            hidePageScrollbars: false,
14020            toggleControlsOnReturn: false,
14021            toggleSlideshowOnSpace: false,
14022            enableKeyboardNavigation: false,
14023            closeOnEscape: false,
14024            closeOnSlideClick: false,
14025            closeOnSwipeUpOrDown: false,
14026            disableScroll: false,
14027            startSlideshow: true
14028        },
14029
14030        console: window.console && typeof window.console.log === 'function' ?
14031            window.console
14031 :
14032            {log: function () {}},
14033
14034        // Detect touch, transition, transform and background-size support:
14035        support: (function (element) {
14036            var support = {
14037                    touch: window.ontouchstart !== undefined ||
14038                        (window.DocumentTouch && document instanceof DocumentTouch)
14039                },
14040                transitions = {
14041                    webkitTransition: {
14042                        end: 'webkitTransitionEnd',
14043                        prefix: '-webkit-'
14044                    },
14045                    MozTransition: {
14046                        end: 'transitionend',
14047                        prefix: '-moz-'
14048                    },
14049                    OTransition: {
14050                        end: 'otransitionend',
14051                        prefix: '-o-'
14052                    },
14053                    transition: {
14054                        end: 'transitionend',
14055                        prefix: ''
14056                    }
14057                },
14058                elementTests = function () {
14059                    var transition = support.transition,
14060                        prop,
14061                        translateZ;
14062                    document.body.appendChild(element);
14063                    if (transition) {
14064                        prop = transition.name.slice(0, -9) + 'ransform';
14065                        if (element.style[prop] !== undefined) {
14066                            element.style[prop] = 'translateZ(0)';
14067                            translateZ = window.getComputedStyle(element)
14068                                .getPropertyValue(transition.prefix + 'transform');
14069                            support.transform = {
14070                                prefix: transition.prefix,
14071                                name: prop,
14072                                translate: true,
14073                                translateZ: !!translateZ && translateZ !== 'none'
14074                            };
14075                        }
14076                    }
14077                    if (element.style.backgroundSize !== undefined) {
14078                        support.backgroundSize = {};
14079                        element.style.backgroundSize = 'contain';
14080                        support.backgroundSize.contain = window
14081                                .getComputedStyle(element)
14082                                .getPropertyValue('background-size') === 'contain';
14083                        element.style.backgroundSize = 'cover';
14084                        support.backgroundSize.cover = window
14085                                .getComputedStyle(element)
14086                                .getPropertyValue('background-size') === 'cover';
14087                    }
14088                    document.body.removeChild(element);
14089                };
14090            (function (support, transitions) {
14091                var prop;
14092                for (prop in transitions) {
14093                    if (transitions.hasOwnProperty(prop) &&
14094                            element.style[prop] !== undefined) {
14095                        support.transition = transitions[prop];
14096                        support.transition.name = prop;
14097                        break;
14098                    }
14099                }
14100            }(support, transitions));
14101            if (document.body) {
14102                elementTests();
14103            } else {
14104                $(document).on('DOMContentLoaded', elementTests);
14105            }
14106            return support;
14107            // Test element, has to be standard HTML and must not be hidden
14108            // for the CSS3 tests using window.getComputedStyle to be applicable:
14109        }(document.createElement('div'))),
14110
14111        requestAnimationFrame: window.requestAnimationFrame ||
14112            window.webkitRequestAnimationFrame ||
14113            window.mozRequestAnimationFrame,
14114
14115        initialize: function () {
14116            this.initStartIndex();
14117            if (this.initWidget() === false) {
14118                return false;
14119            }
14120            this.initEventListeners();
14121            // Load the slide at the given index:
14122            this.onslide(this.index);
14123            // Manually trigger the slideend event for the initial slide:
14124            this.ontransitionend();
14125            // Start the automatic slideshow if applicable:
14126            if (this.options.startSlideshow) {
14127                this.play();
14128            }
14129        },
14130
14131        slide: function (to, speed) {
14132            window.clearTimeout(this.timeout);
14133            var index = this.index,
14134                direction,
14135                naturalDirection,
14136                diff;
14137            if (index === to || this.num === 1) {
14138                return;
14139            }
14140            if (!speed) {
14141                speed = this.options.transitionSpeed;
14142            }
14143            if (this.support.transition) {
14144                if (!this.options.continuous) {
14145                    to = this.circle(to);
14146                }
14147                // 1: backward, -1: forward:
14148                direction = Math.abs(index - to) / (index - to);
14149                // Get the actual position of the slide:
14150                if (this.options.continuous) {
14151                    naturalDirection = direction;
14152                    direction = -this.positions[this.circle(to)] / this.slideWidth;
14153                    // If going forward but to < index, use to = slides.length + to
14154                    // If going backward but to > index, use to = -slides.length + to
14155                    if (direction !== naturalDirection) {
14156                        to = -direction * this.num + to;
14157                    }
14158                }
14159                diff = Math.abs(index - to) - 1;
14160                // Move all the slides between index and to in the right direction:
14161                while (diff) {
14162                    diff -= 1;
14163                    this.move(
14164                        this.circle((to > index ? to : index) - diff - 1),
14165                        this.slideWidth * direction,
14166                        0
14167                    );
14168                }
14169                to = this.circle(to);
14170                this.move(index, this.slideWidth * direction, speed);
14171                this.move(to, 0, speed);
14172                if (this.options.continuous) {
14173                    this.move(
14174                        this.circle(to - direction),
14175                        -(this.slideWidth * direction),
14176                        0
14177                    );
14178                }
14179            } else {
14180                to = this.circle(to);
14181                this.animate(index * -this.slideWidth, to * -this.slideWidth, speed);
14182            }
14183            this.onslide(to);
14184        },
14185
14186        getIndex: function () {
14187            return this.index;
14188        },
14189
14190        getNumber: function () {
14191            return this.num;
14192        },
14193
14194        prev: function () {
14195            if (this.options.continuous || this.index) {
14196                this.slide(this.index - 1);
14197            }
14198        },
14199
14200        next: function () {
14201            if (this.options.continuous || this.index < this.num - 1) {
14202                this.slide(this.index + 1);
14203            }
14204        },
14205
14206        play: function (time) {
14207            var that = this;
14208            window.clearTimeout(this.timeout);
14209            this.interval = time || this.options.slideshowInterval;
14210            if (this.elements[this.index] > 1) {
14211                this.timeout = this.setTimeout(
14212                    (!this.requestAnimationFrame && this.slide) || function (to, speed) {
14213                        that.animationFrameId = that.requestAnimationFrame.call(
14214                            window,
14215                            function () {
14216                                that.slide(to, speed);
14217                            }
14218                        );
14219                    },
14220                    [this.index + 1, this.options.slideshowTransitionSpeed],
14221                    this.interval
14222                );
14223            }
14224            this.container.addClass(this.options.playingClass);
14225        },
14226
14227        pause: function () {
14228            window.clearTimeout(this.timeout);
14229            this.interval = null;
14230            this.container.removeClass(this.options.playingClass);
14231        },
14232
14233        add: function (list) {
14234            var i;
14235            if (!list.concat) {
14236                // Make a real array out of the list to add:
14237                list = Array.prototype.slice.call(list);
14238            }
14239            if (!this.list.concat) {
14240                // Make a real array out of the Gallery list:
14241                this.list = Array.prototype.slice.call(this.list);
14242            }
14243            this.list = this.list.concat(list);
14244            this.num = this.list.length;
14245            if (this.num > 2 && this.options.continuous === null) {
14246                this.options.continuous = true;
14247                this.container.removeClass(this.options.leftEdgeClass);
14248            }
14249            this.container
14250                .removeClass(this.options.rightEdgeClass)
14251                .removeClass(this.options.singleClass);
14252            for (i = this.num - list.length; i < this.num; i += 1) {
14253                this.addSlide(i);
14254                this.positionSlide(i);
14255            }
14256            this.positions.length = this.num;
14257            this.initSlides(true);
14258        },
14259
14260        resetSlides: function () {
14261            this.slidesContainer.empty();
14262            this.slides = [];
14263        },
14264
14265        handleClose: function () {
14266            var options = this.options;
14267            this.destroyEventListeners();
14268            // Cancel the slideshow:
14269            this.pause();
14270            this.container[0].style.display = 'none';
14271            this.container
14272                .removeClass(options.displayClass)
14273                .removeClass(options.singleClass)
14274                .removeClass(options.leftEdgeClass)
14275                .removeClass(options.rightEdgeClass);
14276            if (options.hidePageScrollbars) {
14277                document.body.style.overflow = this.bodyOverflowStyle;
14278            }
14279            if (this.options.clearSlides) {
14280                this.resetSlides();
14281            }
14282            if (this.options.onclosed) {
14283                this.options.onclosed.call(this);
14284            }
14285        },
14286
14287        close: function () {
14288            var that = this,
14289                closeHandler = function (event) {
14290                    if (event.target === that.container[0]) {
14291                        that.container.off(
14292                            that.support.transition.end,
14293                            closeHandler
14294                        );
14295                        that.handleClose();
14296                    }
14297                };
14298            if (this.options.onclose) {
14299                this.options.onclose.call(this);
14300            }
14301            if (this.support.transition && this.options.displayTransition) {
14302                this.container.on(
14303                    this.support.transition.end,
14304                    closeHandler
14305                );
14306                this.container.removeClass(this.options.displayClass);
14307            } else {
14308                this.handleClose();
14309            }
14310        },
14311
14312        circle: function (index) {
14313            // Always return a number inside of the slides index range:
14314            return (this.num + (index % this.num)) % this.num;
14315        },
14316
14317        move: function (index, dist, speed) {
14318            this.translateX(index, dist, speed);
14319            this.positions[index] = dist;
14320        },
14321
14322        translate: function (index, x, y, speed) {
14323            var style = this.slides[index].style,
14324                transition = this.support.transition,
14325                transform = this.support.transform;
14326            style[transition.name + 'Duration'] = speed + 'ms';
14327            style[transform.name] = 'translate(' + x + 'px, ' + y + 'px)' +
14328                (transform.translateZ ? ' translateZ(0)' : '');
14329        },
14330
14331        translateX: function (index, x, speed) {
14332            this.translate(index, x, 0, speed);
14333        },
14334
14335        translateY: function (index, y, speed) {
14336            this.translate(index, 0, y, speed);
14337        },
14338
14339        animate: function (from, to, speed) {
14340            if (!speed) {
14341                this.slidesContainer[0].style.left = to + 'px';
14342                return;
14343            }
14344            var that = this,
14345                start = new Date().getTime(),
14346                timer = window.setInterval(function () {
14347                    var timeElap = new Date().getTime() - start;
14348                    if (timeElap > speed) {
14349                        that.slidesContainer[0].style.left = to + 'px';
14350                        that.ontransitionend();
14351                        window.clearInterval(timer);
14352                        return;
14353                    }
14354                    that.slidesContainer[0].style.left = (((to - from) *
14355                        (Math.floor((timeElap / speed) * 100) / 100)) +
14356                            from) + 'px';
14357                }, 4);
14358        },
14359
14360        preventDefault: function (event) {
14361            if (event.preventDefault) {
14362                event.preventDefault();
14363            } else {
14364                event.returnValue = false;
14365            }
14366        },
14367
14368        stopPropagation: function (event) {
14369            if (event.stopPropagation) {
14370                event.stopPropagation();
14371            } else {
14372                event.cancelBubble = true;
14373            }
14374        },
14375
14376        onresize: function () {
14377            this.initSlides(true);
14378        },
14379
14380        onmousedown: function (event) {
14381            // Trigger on clicks of the left mouse button only
14382            // and exclude video elements:
14383            if (event.which && event.which === 1 &&
14384                    event.target.nodeName !== 'VIDEO') {
14385                // Preventing the default mousedown action is required
14386                // to make touch emulation work with Firefox:
14387                event.preventDefault();
14388                (event.originalEvent || event).touches = [{
14389                    pageX: event.pageX,
14390                    pageY: event.pageY
14391                }];
14392                this.ontouchstart(event);
14393            }
14394        },
14395
14396        onmousemove: function (event) {
14397            if (this.touchStart) {
14398                (event.originalEvent || event).touches = [{
14399                    pageX: event.pageX,
14400                    pageY: event.pageY
14401                }];
14402                this.ontouchmove(event);
14403            }
14404        },
14405
14406        onmouseup: function (event) {
14407            if (this.touchStart) {
14408                this.ontouchend(event);
14409                delete this.touchStart;
14410            }
14411        },
14412
14413        onmouseout: function (event) {
14414            if (this.touchStart) {
14415                var target = event.target,
14416                    related = event.relatedTarget;
14417                if (!related || (related !== target &&
14418                        !$.contains(target, related))) {
14419                    this.onmouseup(event);
14420                }
14421            }
14422        },
14423
14424        ontouchstart: function (event) {
14425            if (this.options.stopTouchEventsPropagation) {
14426                this.stopPropagation(event);
14427            }
14428            // jQuery doesn't copy touch event properties by default,
14429            // so we have to access the originalEvent object:
14430            var touches = (event.originalEvent || event).touches[0];
14431            this.touchStart = {
14432                // Remember the initial touch coordinates:
14433                x: touches.pageX,
14434                y: touches.pageY,
14435                // Store the time to determine touch duration:
14436                time: Date.now()
14437            };
14438            // Helper variable to detect scroll movement:
14439            this.isScrolling = undefined;
14440            // Reset delta values:
14441            this.touchDelta = {};
14442        },
14443
14444        ontouchmove: function (event) {
14445            if (this.options.stopTouchEventsPropagation) {
14446                this.stopPropagation(event);
14447            }
14448            // jQuery doesn't copy touch event properties by default,
14449            // so we have to access the originalEvent object:
14450            var touches = (event.originalEvent || event).touches[0],
14451                scale = (event.originalEvent || event).scale,
14452                index = this.index,
14453                touchDeltaX,
14454                indices;
14455            // Ensure this is a one touch swipe and not, e.g. a pinch:
14456            if (touches.length > 1 || (scale && scale !== 1)) {
14457                return;
14458            }
14459            if (this.options.disableScroll) {
14460                event.preventDefault();
14461            }
14462            // Measure change in x and y coordinates:
14463            this.touchDelta = {
14464                x: touches.pageX - this.touchStart.x,
14465                y: touches.pageY - this.touchStart.y
14466            };
14467            touchDeltaX = this.touchDelta.x;
14468            // Detect if this is a vertical scroll movement (run only once per touch):
14469            if (this.isScrolling === undefined) {
14470                this.isScrolling = this.isScrolling ||
14471                    Math.abs(touchDeltaX) < Math.abs(this.touchDelta.y);
14472            }
14473            if (!this.isScrolling) {
14474                // Always prevent horizontal scroll:
14475                event.preventDefault();
14476                // Stop the slideshow:
14477                window.clearTimeout(this.timeout);
14478                if (this.options.continuous) {
14479                    indices = [
14480                        this.circle(index + 1),
14481                        index,
14482                        this.circle(index - 1)
14483                    ];
14484                } else {
14485                    // Increase resistance if first slide and sliding left
14486                    // or last slide and sliding right:
14487                    this.touchDelta.x = touchDeltaX =
14488                        touchDeltaX /
14489                        (((!index && touchDeltaX > 0) ||
14490                            (index === this.num - 1 && touchDeltaX < 0)) ?
14491                                (Math.abs(touchDeltaX) / this.slideWidth + 1) : 1);
14492                    indices = [index];
14493                    if (index) {
14494                        indices.push(index - 1);
14495                    }
14496                    if (index < this.num - 1) {
14497                        indices.unshift(index + 1);
14498                    }
14499                }
14500                while (indices.length) {
14501                    index = indices.pop();
14502                    this.translateX(index, touchDeltaX + this.positions[index], 0
14502);
14503                }
14504            } else if (this.options.closeOnSwipeUpOrDown) {
14505                this.translateY(index, this.touchDelta.y + this.positions[index], 0);
14506            }
14507        },
14508
14509        ontouchend: function (event) {
14510            if (this.options.stopTouchEventsPropagation) {
14511                this.stopPropagation(event);
14512            }
14513            var index = this.index,
14514                speed = this.options.transitionSpeed,
14515                slideWidth = this.slideWidth,
14516                isShortDuration = Number(Date.now() - this.touchStart.time) < 250,
14517                // Determine if slide attempt triggers next/prev slide:
14518                isValidSlide = (isShortDuration && Math.abs(this.touchDelta.x) > 20) ||
14519                    Math.abs(this.touchDelta.x) > slideWidth / 2,
14520                // Determine if slide attempt is past start or end:
14521                isPastBounds = (!index && this.touchDelta.x > 0) ||
14522                        (index === this.num - 1 && this.touchDelta.x < 0),
14523                isValidClose = !isValidSlide && this.options.closeOnSwipeUpOrDown &&
14524                    ((isShortDuration && Math.abs(this.touchDelta.y) > 20) ||
14525                        Math.abs(this.touchDelta.y) > this.slideHeight / 2),
14526                direction,
14527                indexForward,
14528                indexBackward,
14529                distanceForward,
14530                distanceBackward;
14531            if (this.options.continuous) {
14532                isPastBounds = false;
14533            }
14534            // Determine direction of swipe (true: right, false: left):
14535            direction = this.touchDelta.x < 0 ? -1 : 1;
14536            if (!this.isScrolling) {
14537                if (isValidSlide && !isPastBounds) {
14538                    indexForward = index + direction;
14539                    indexBackward = index - direction;
14540                    distanceForward = slideWidth * direction;
14541                    distanceBackward = -slideWidth * direction;
14542                    if (this.options.continuous) {
14543                        this.move(this.circle(indexForward), distanceForward, 0);
14544                        this.move(this.circle(index - 2 * direction), distanceBackward, 0);
14545                    } else if (indexForward >= 0 &&
14546                            indexForward < this.num) {
14547                        this.move(indexForward, distanceForward, 0);
14548                    }
14549                    this.move(index, this.positions[index] + distanceForward, speed);
14550                    this.move(
14551                        this.circle(indexBackward),
14552                        this.positions[this.circle(indexBackward)] + distanceForward,
14553                        speed
14554                    );
14555                    index = this.circle(indexBackward);
14556                    this.onslide(index);
14557                } else {
14558                    // Move back into position
14559                    if (this.options.continuous) {
14560                        this.move(this.circle(index - 1), -slideWidth, speed);
14561                        this.move(index, 0, speed);
14562                        this.move(this.circle(index + 1), slideWidth, speed);
14563                    } else {
14564                        if (index) {
14565                            this.move(index - 1, -slideWidth, speed);
14566                        }
14567                        this.move(index, 0, speed);
14568                        if (index < this.num - 1) {
14569                            this.move(index + 1, slideWidth, speed);
14570                        }
14571                    }
14572                }
14573            } else {
14574                if (isValidClose) {
14575                    this.close();
14576                } else {
14577                    // Move back into position
14578                    this.translateY(index, 0, speed);
14579                }
14580            }
14581        },
14582
14583        ontouchcancel: function (event) {
14584            if (this.touchStart) {
14585                this.ontouchend(event);
14586                delete this.touchStart;
14587            }
14588        },
14589
14590        ontransitionend: function (event) {
14591            var slide = this.slides[this.index];
14592            if (!event || slide === event.target) {
14593                if (this.interval) {
14594                    this.play();
14595                }
14596                this.setTimeout(
14597                    this.options.onslideend,
14598                    [this.index, slide]
14599                );
14600            }
14601        },
14602
14603        oncomplete: function (event) {
14604            var target = event.target || event.srcElement,
14605                parent = target && target.parentNode,
14606                index;
14607            if (!target || !parent) {
14608                return;
14609            }
14610            index = this.getNodeIndex(parent);
14611            $(parent).removeClass(this.options.slideLoadingClass);
14612            if (event.type === 'error') {
14613                $(parent).addClass(this.options.slideErrorClass);
14614                this.elements[index] = 3; // Fail
14615            } else {
14616                this.elements[index] = 2; // Done
14617            }
14618            // Fix for IE7's lack of support for percentage max-height:
14619            if (target.clientHeight > this.container[0].clientHeight) {
14620                target.style.maxHeight = this.container[0].clientHeight;
14621            }
14622            if (this.interval && this.slides[this.index] === parent) {
14623                this.play();
14624            }
14625            this.setTimeout(
14626                this.options.onslidecomplete,
14627                [index, parent]
14628            );
14629        },
14630
14631        onload: function (event) {
14632            this.oncomplete(event);
14633        },
14634
14635        onerror: function (event) {
14636            this.oncomplete(event);
14637        },
14638
14639        onkeydown: function (event) {
14640            switch (event.which || event.keyCode) {
14641            case 13: // Return
14642                if (this.options.toggleControlsOnReturn) {
14643                    this.preventDefault(event);
14644                    this.toggleControls();
14645                }
14646                break;
14647            case 27: // Esc
14648                if (this.options.closeOnEscape) {
14649                    this.close();
14650                }
14651                break;
14652            case 32: // Space
14653                if (this.options.toggleSlideshowOnSpace) {
14654                    this.preventDefault(event);
14655                    this.toggleSlideshow();
14656                }
14657                break;
14658            case 37: // Left
14659                if (this.options.enableKeyboardNavigation) {
14660                    this.preventDefault(event);
14661                    this.prev();
14662                }
14663                break;
14664            case 39: // Right
14665                if (this.options.enableKeyboardNavigation) {
14666                    this.preventDefault(event);
14667                    this.next();
14668                }
14669                break;
14670            }
14671        },
14672
14673        handleClick: function (event) {
14674            var options = this.options,
14675                target = event.target || event.srcElement,
14676                parent = target.parentNode,
14677                isTarget = function (className) {
14678                    return $(target).hasClass(className) ||
14679                        $(parent).hasClass(className);
14680                };
14681            if (isTarget(options.toggleClass)) {
14682                // Click on "toggle" control
14683                this.preventDefault(event);
14684                this.toggleControls();
14685            } else if (isTarget(options.prevClass)) {
14686                // Click on "prev" control
14687                this.preventDefault(event);
14688                this.prev();
14689            } else if (isTarget(options.nextClass)) {
14690                // Click on "next" control
14691                this.preventDefault(event);
14692                this.next();
14693            } else if (isTarget(options.closeClass)) {
14694                // Click on "close" control
14695                this.preventDefault(event);
14696                this.close();
14697            } else if (isTarget(options.playPauseClass)) {
14698                // Click on "play-pause" control
14699                this.preventDefault(event);
14700                this.toggleSlideshow();
14701            } else if (parent === this.slidesContainer[0]) {
14702                // Click on slide background
14703                this.preventDefault(event);
14704                if (options.closeOnSlideClick) {
14705                    this.close();
14706                } else {
14707                    this.toggleControls();
14708                }
14709            } else if (parent.parentNode &&
14710                    parent.parentNode === this.slidesContainer[0]) {
14711                // Click on displayed element
14712                this.preventDefault(event);
14713                this.toggleControls();
14714            }
14715        },
14716
14717        onclick: function (event) {
14718            if (this.options.emulateTouchEvents &&
14719                    this.touchDelta && (Math.abs(this.touchDelta.x) > 20 ||
14720                        Math.abs(this.touchDelta.y) >
14720 20)) {
14721                delete this.touchDelta;
14722                return;
14723            }
14724            return this.handleClick(event);
14725        },
14726
14727        updateEdgeClasses: function (index) {
14728            if (!index) {
14729                this.container.addClass(this.options.leftEdgeClass);
14730            } else {
14731                this.container.removeClass(this.options.leftEdgeClass);
14732            }
14733            if (index === this.num - 1) {
14734                this.container.addClass(this.options.rightEdgeClass);
14735            } else {
14736                this.container.removeClass(this.options.rightEdgeClass);
14737            }
14738        },
14739
14740        handleSlide: function (index) {
14741            if (!this.options.continuous) {
14742                this.updateEdgeClasses(index);
14743            }
14744            this.loadElements(index);
14745            if (this.options.unloadElements) {
14746                this.unloadElements(index);
14747            }
14748            this.setTitle(index);
14749        },
14750
14751        onslide: function (index) {
14752            this.index = index;
14753            this.handleSlide(index);
14754            this.setTimeout(this.options.onslide, [index, this.slides[index]]);
14755        },
14756
14757        setTitle: function (index) {
14758            var text = this.slides[index].firstChild.title,
14759                titleElement = this.titleElement;
14760            if (titleElement.length) {
14761                this.titleElement.empty();
14762                if (text) {
14763                    titleElement[0].appendChild(document.createTextNode(text));
14764                }
14765            }
14766        },
14767
14768        setTimeout: function (func, args, wait) {
14769            var that = this;
14770            return func && window.setTimeout(function () {
14771                func.apply(that, args || []);
14772            }, wait || 0);
14773        },
14774
14775        imageFactory: function (obj, callback) {
14776            var that = this,
14777                img = this.imagePrototype.cloneNode(false),
14778                url = obj,
14779                backgroundSize = this.options.stretchImages,
14780                called,
14781                element,
14782                callbackWrapper = function (event) {
14783                    if (!called) {
14784                        event = {
14785                            type: event.type,
14786                            target: element
14787                        };
14788                        if (!element.parentNode) {
14789                            // Fix for IE7 firing the load event for
14790                            // cached images before the element could
14791                            // be added to the DOM:
14792                            return that.setTimeout(callbackWrapper, [event]);
14793                        }
14794                        called = true;
14795                        $(img).off('load error', callbackWrapper);
14796                        if (backgroundSize) {
14797                            if (event.type === 'load') {
14798                                element.style.background = 'url("' + url +
14799                                    '") center no-repeat';
14800                                element.style.backgroundSize = backgroundSize;
14801                            }
14802                        }
14803                        callback(event);
14804                    }
14805                },
14806                title;
14807            if (typeof url !== 'string') {
14808                url = this.getItemProperty(obj, this.options.urlProperty);
14809                title = this.getItemProperty(obj, this.options.titleProperty);
14810            }
14811            if (backgroundSize === true) {
14812                backgroundSize = 'contain';
14813            }
14814            backgroundSize = this.support.backgroundSize &&
14815                this.support.backgroundSize[backgroundSize] && backgroundSize;
14816            if (backgroundSize) {
14817                element = this.elementPrototype.cloneNode(false);
14818            } else {
14819                element = img;
14820                img.draggable = false;
14821            }
14822            if (title) {
14823                element.title = title;
14824            }
14825            $(img).on('load error', callbackWrapper);
14826            img.src = url;
14827            return element;
14828        },
14829
14830        createElement: function (obj, callback) {
14831            var type = obj && this.getItemProperty(obj, this.options.typeProperty),
14832                factory = (type && this[type.split('/')[0] + 'Factory']) ||
14833                    this.imageFactory,
14834                element = obj && factory.call(this, obj, callback);
14835            if (!element) {
14836                element = this.elementPrototype.cloneNode(false);
14837                this.setTimeout(callback, [{
14838                    type: 'error',
14839                    target: element
14840                }]);
14841            }
14842            $(element).addClass(this.options.slideContentClass);
14843            return element;
14844        },
14845
14846        loadElement: function (index) {
14847            if (!this.elements[index]) {
14848                if (this.slides[index].firstChild) {
14849                    this.elements[index] = $(this.slides[index])
14850                        .hasClass(this.options.slideErrorClass) ? 3 : 2;
14851                } else {
14852                    this.elements[index] = 1; // Loading
14853                    $(this.slides[index]).addClass(this.options.slideLoadingClass);
14854                    this.slides[index].appendChild(this.createElement(
14855                        this.list[index],
14856                        this.proxyListener
14857                    ));
14858                }
14859            }
14860        },
14861
14862        loadElements: function (index) {
14863            var limit = Math.min(this.num, this.options.preloadRange * 2 + 1),
14864                j = index,
14865                i;
14866            for (i = 0; i < limit; i += 1) {
14867                // First load the current slide element (0),
14868                // then the next one (+1),
14869                // then the previous one (-2),
14870                // then the next after next (+2), etc.:
14871                j += i * (i % 2 === 0 ? -1 : 1);
14872                // Connect the ends of the list to load slide elements for
14873                // continuous navigation:
14874                j = this.circle(j);
14875                this.loadElement(j);
14876            }
14877        },
14878
14879        unloadElements: function (index) {
14880            var i,
14881                slide,
14882                diff;
14883            for (i in this.elements) {
14884                if (this.elements.hasOwnProperty(i)) {
14885                    diff = Math.abs(index - i);
14886                    if (diff > this.options.preloadRange &&
14887                            diff + this.options.preloadRange < this.num) {
14888                        slide = this.slides[i];
14889                        slide.removeChild(slide.firstChild);
14890                        delete this.elements[i];
14891                    }
14892                }
14893            }
14894        },
14895
14896        addSlide: function (index) {
14897            var slide = this.slidePrototype.cloneNode(false);
14898            slide.setAttribute('data-index', index);
14899            this.slidesContainer[0].appendChild(slide);
14900            this.slides.push(slide);
14901        },
14902
14903        positionSlide: function (index) {
14904            var slide = this.slides[index];
14905            slide.style.width = this.slideWidth + 'px';
14906            if (this.support.transition) {
14907                slide.style.left = (index * -this.slideWidth) + 'px';
14908                this.move(index, this.index > index ? -this.slideWidth :
14909                        (this.index < index ? this.slideWidth : 0), 0);
14910            }
14911        },
14912
14913        initSlides: function (reload) {
14914            var clearSlides,
14915                i;
14916            if (!reload) {
14917                this.positions = [];
14918                this.positions.length = this.num;
14919                this.elements = {};
14920                this.imagePrototype = document.createElement('img');
14921                this.elementPrototype = document.createElement('div');
14922                this.slidePrototype = document.createElement('div');
14923                $(this.slidePrototype).addClass(this.options.slideClass);
14924                this.slides = this.slidesContainer[0].children;
14925                clearSlides = this.options.clearSlides ||
14926                    this.slides.length !== this.num;
14927            }
14928            this.slideWidth = this.container[0].offsetWidth;
14929            this.slideHeight = this.container[0].offsetHeight;
14930            this.slidesContainer[0].style.width =
14931                (this.num * this.slideWidth) + 'px';
14932            if (clearSlides) {
14933                this.resetSlides();
14934            }
14935            for (i = 0; i < this.num; i += 1) {
14936                if (clearSlides) {
14937                    this.addSlide(i);
14938                }
14939                this.positionSlide(i);
14940            }
14941            // Reposition the slides before and after the given index:
14942            if (this.options.continuous && this.support.transition) {
14943                this.move(this.circle(this.index - 1), -this.slideWidth, 0);
14944                this.move(this.circle(this.index + 1), this.slideWidth, 0);
14945            }
14946            if (!this.support.transition) {
14947                this.slidesContainer[0].style.left =
14948                    (this.index * -this.slideWidth) + 'px';
14949            }
14950        },
14951
14952        toggleControls: function () {
14953            var controlsClass = this.options.controlsClass;
14954            if (this.container.hasClass(controlsClass)) {
14955                this.container.removeClass(controlsClass);
14956            } else {
14957                this.container.addClass(controlsClass);
14958            }
14959        },
14960
14961        toggleSlideshow: function () {
14962            if (!this.interval) {
14963                this.play();
14964            } else {
14965                this.pause();
14966            }
14967        },
14968
14969        getNodeIndex: function (element) {
14970            return parseInt(element.getAttribute('data-index'), 10);
14971        },
14972
14973        getNestedProperty: function (obj, property) {
14974            property.replace(
14975                // Matches native JavaScript notation in a String,
14976                // e.g. '["doubleQuoteProp"].dotProp[2]'
14977                /\[(?:'([^']+)'|"([^"]+)"|(\d+))\]|(?:(?:^|\.)([^\.\[]+))/g,
14978                function (str, singleQuoteProp, doubleQuoteProp, arrayIndex, dotProp) {
14979                    var prop = dotProp || singleQuoteProp || doubleQuoteProp ||
14980                            (arrayIndex && parseInt(arrayIndex, 10));
14981                    if (str && obj) {
14982                        obj = obj[prop];
14983                    }
14984                }
14985            );
14986            return obj;
14987        },
14988
14989        getDataProperty: function (obj, property) {
14990            if (obj.getAttribute) {
14991                var prop = obj.getAttribute('data-' +
14992                        property.replace(/([A-Z])/g, '-$1').toLowerCase());
14993                if (typeof prop === 'string') {
14994                    if (/^(true|false|null|-?\d+(\.\d+)?|\{[\s\S]*\}|\[[\s\S]*\])$/
14995                            .test(prop)) {
14996                        try {
14997                            return $.parseJSON(prop);
14998                        } catch (ignore) {}
14999                    }
15000                    return prop;
15001                }
15002            }
15003        },
15004
15005        getItemProperty: function (obj, property) {
15006            var prop = obj[property];
15007            if (prop === undefined) {
15008                prop = this.getDataProperty(obj, property);
15009                if (prop === undefined) {
15010                    prop = this.getNestedProperty(obj, property);
15011                }
15012            }
15013            return prop;
15014        },
15015
15016        initStartIndex: function () {
15017            var index = this.options.index,
15018                urlProperty = this.options.urlProperty,
15019                i;
15020            // Check if the index is given as a list object:
15021            if (index && typeof index !== 'number') {
15022                for (i = 0; i < this.num; i += 1) {
15023                    if (this.list[i] === index ||
15024                            this.getItemProperty(this.list[i], urlProperty) ===
15025                                this.getItemProperty(index, urlProperty)) {
15026                        index  = i;
15027                        break;
15028                    }
15029                }
15030            }
15031            // Make sure the index is in the list range:
15032            this.index = this.circle(parseInt(index, 10) || 0);
15033        },
15034
15035        initEventListeners: function () {
15036            var that = this,
15037                slidesContainer = this.slidesContainer,
15038                proxyListener = function (event) {
15039                    var type = that.support.transition &&
15040                            that.support.transition.end === event.type ?
15041                                    'transitionend' : event.type;
15042                    that['on' + type](event);
15043                };
15044            $(window).on('resize', proxyListener);
15045            $(document.body).on('keydown', proxyListener);
15046            this.container.on('click', proxyListener);
15047            if (this.support.touch) {
15048                slidesContainer
15049                    .on('touchstart touchmove touchend touchcancel', proxyListener);
15050            } else if (this.options.emulateTouchEvents &&
15051                    this.support.transition) {
15052                slidesContainer
15053                    .on('mousedown mousemove mouseup mouseout', proxyListener);
15054            }
15055            if (this.support.transition) {
15056                slidesContainer.on(
15057                    this.support.transition.end,
15058                    proxyListener
15059                );
15060            }
15061            this.proxyListener = proxyListener;
15062        },
15063
15064        destroyEventListeners: function () {
15065            var slidesContainer = this.slidesContainer,
15066                proxyListener = this.proxyListener;
15067            $(window).off('resize', proxyListener);
15068            $(document.body).off('keydown', proxyListener);
15069            this.container.off('click', proxyListener);
15070            if (this.support.touch) {
15071                slidesContainer
15072                    .off('touchstart touchmove touchend touchcancel', proxyListener);
15073            } else if (this.options.emulateTouchEvents &&
15074                    this.support.transition) {
15075                slidesContainer
15076                    .off('mousedown mousemove mouseup mouseout', proxyListener);
15077            }
15078            if (this.support.transition) {
15079                slidesContainer.off(
15080                    this.support.transition.end,
15081                    proxyListener
15082                );
15083            }
15084        },
15085
15086        handleOpen: function () {
15087            if (this.options.onopened) {
15088                this.options.onopened.call(this);
15089            }
15090        },
15091
15092        initWidget: function () {
15093            var that = this,
15094                openHandler = function (event) {
15095                    if (event.target === that.container[0]) {
15096                        that.container.off(
15097                            that.support.transition.end,
15098                            openHandler
15099                        );
15100                        that.handleOpen();
15101                    }
15102                };
15103            this.container = $(this.options.container);
15104            if (!this.container.length) {
15105                this.console.log(
15106                    'blueimp Gallery: Widget container not found.',
15107                    this.options.container
15108                );
15109                return false;
15110            }
15111            this.slidesContainer = this.container.find(
15112                this.options.slidesContainer
15113            ).first();
15114            if (!this.slidesContainer.length) {
15115                this.console.log(
15116                    'blueimp Gallery: Slides container not found.',
15117                    this.options.slidesContainer
15118                );
15119                return false;
15120            }
15121            this.titleElement = this.container.find(
15122                this.options.titleElement
15123            ).first();
15124            if (this.num === 1) {
15125                this.container.addClass(this.options.singleClass);
15126            }
15127            if (this.options.onopen) {
15128                this.options.onopen.call(this);
15129            }
15130            if (this.support.transition && this.options.displayTransition) {
15131                this.container.on(
15132                    this.support.transition.end,
15133                    openHandler
15134                );
15135            } else {
15136                this.handleOpen();
15137            }
15138            if (this.options.hidePageScrollbars) {
15139                // Hide the page scrollbars:
15140                this.bodyOverflowStyle = document.body.style.overflow;
15141                document.body.style.overflow = 'hidden';
15142            }
15143            this.container[0].style.display = 'block';
15144            this.initSlides();
15145            this.container.addClass(this.options.displayClass);
15146        },
15147
15148        initOptions: function (options) {
15149            // Create a copy of the prototype options:
15150            this.options = $.extend({}, this.options);
15151            // Check if carousel mode is enabled:
15152            if ((options && options.carousel) ||
15153                    (this.options.carousel && (!options || options.carousel !== false))) {
15154                $.extend(this.options, this.carouselOptions);
15155            }
15156            // Override any given options:
15157            $.extend(this.options, options);
15158            if (this.num < 3) {
15159                // 1 or 2 slides cannot be displayed continuous,
15160                // remember the original option by setting to null instead of false:
15161                this.options.continuous = this.options.continuous ? null : false;
15162            }
15163            if (!this.support.transition) {
15164                this.options.emulateTouchEvents = false;
15165            }
15166            if (this.options.event) {
15167                this.preventDefault(this.options.event);
15168            }
15169        }
15170
15171    });
15172
15173    return Gallery;
15174}));
15175
15176/*
15177 * blueimp Gallery Indicator JS 1.1.0
15178 * https://github.com/blueimp/Gallery
15179 *
15180 * Copyright 2013, Sebastian Tschan
15181 * https://blueimp.net
15182 *
15183 * Licensed under the MIT license:
15184 * http://www.opensource.org/licenses/MIT
15185 */
15186
15187/* global define, window, document */
15188
15189(function (factory) {
15190    'use strict';
15191    if (typeof define === 'function' && define.amd) {
15192        // Register as an anonymous AMD module:
15193        define([
15194            './blueimp-helper',
15195            './blueimp-gallery'
15196        ], factory);
15197    } else {
15198        // Browser globals:
15199        factory(
15200            window.blueimp.helper || window.jQuery,
15201            window.blueimp.Gallery
15202        );
15203    }
15204}(function ($, Gallery) {
15205    'use strict';
15206
15207    $.extend(Gallery.prototype.options, {
15208        // The tag name, Id, element or querySelector of the indicator container:
15209        indicatorContainer: 'ol',
15210        // The class for the active indicator:
15211        activeIndicatorClass: 'active',
15212        // The list object property (or data attribute) with the thumbnail URL,
15213        // used as alternative to a thumbnail child element:
15214        thumbnailProperty: 'thumbnail',
15215        // Defines if the gallery indicators should display a thumbnail:
15216        thumbnailIndicators: true
15217    });
15218
15219    var initSlides = Gallery.prototype.initSlides,
15220        addSlide = Gallery.prototype.addSlide,
15221        resetSlides = Gallery.prototype.resetSlides,
15222        handleClick = Gallery.prototype.handleClick,
15223        handleSlide = Gallery.prototype.handleSlide,
15224        handleClose = Gallery.prototype.handleClose;
15225
15226    $.extend(Gallery.prototype, {
15227
15228        createIndicator: function (obj) {
15229            var indicator = this.indicatorPrototype.cloneNode(false),
15230                title = this.getItemProperty(obj, this.options.titleProperty),
15231                thumbnailProperty = this.options.thumbnailProperty,
15232                thumbnailUrl,
15233                thumbnail;
15234            if (this.options.thumbnailIndicators) {
15235                thumbnail = obj.getElementsByTagName && $(obj).find('img')[0];
15236                if (thumbnail) {
15237                    thumbnailUrl = thumbnail.src;
15238                } else if (thumbnailProperty) {
15239                    thumbnailUrl = this.getItemProperty(obj, thumbnailProperty);
15240                }
15241                if (thumbnailUrl) {
15242                    indicator.style.backgroundImage = 'url("' + thumbnailUrl + '")';
15243                }
15244            }
15245            if (title) {
15246                indicator.title = title;
15247            }
15248            return indicator;
15249        },
15250
15251        addIndicator: function (index) {
15252            if (this.indicatorContainer.length) {
15253                var indicator = this.createIndicator(this.list[index]);
15254                indicator.setAttribute('data-index', index);
15255                this.indicatorContainer[0].appendChild(indicator);
15256                this.indicators.push(indicator);
15257            }
15258        },
15259
15260        setActiveIndicator: function (index) {
15261            if (this.indicators) {
15262                if (this.activeIndicator) {
15263                    this.activeIndicator
15264                        .removeClass(this.options.activeIndicatorClass);
15265                }
15266                this.activeIndicator = $(this.indicators[index]);
15267                this.activeIndicator
15268                    .addClass(this.options.activeIndicatorClass);
15269            }
15270        },
15271
15272        initSlides: function (reload) {
15273            if (!reload) {
15274                this.indicatorContainer = this.container.find(
15275                    this.options.indicatorContainer
15276                );
15277                if (this.indicatorContainer.length) {
15278                    this.indicatorPrototype = document.createElement('li');
15279                    this.indicators = this.indicatorContainer[0].children;
15280                }
15281            }
15282            initSlides.call(this, reload);
15283        },
15284
15285        addSlide: function (index) {
15286            addSlide.call(this, index);
15287            this.addIndicator(index);
15288        },
15289
15290        resetSlides: function () {
15291            resetSlides.call(this);
15292            this.indicatorContainer.empty();
15293            this.indicators = [];
15294        },
15295
15296        handleClick: function (event) {
15297            var target = event.target || event.srcElement,
15298                parent = target.parentNode;
15299            if (parent === this.indicatorContainer[0]) {
15300                // Click on indicator element
15301                this.preventDefault(event);
15302                this.slide(this.getNodeIndex(target));
15303            } else if (parent.parentNode === this.indicatorContainer[0]) {
15304                // Click on indicator child element
15305                this.preventDefault(event);
15306                this.slide(this.getNodeIndex(parent));
15307            } else {
15308                return handleClick.call(this, event);
15309            }
15310        },
15311
15312        handleSlide: function (index) {
15313            handleSlide.call(this, index);
15314            this.setActiveIndicator(index);
15315        },
15316
15317        handleClose: function () {
15318            if (this.activeIndicator) {
15319                this.activeIndicator
15320                    .removeClass(this.options.activeIndicatorClass);
15321            }
15322            handleClose.call(this);
15323        }
15324
15325    });
15326
15327    return Gallery;
15328}));
15329
15330/*
15331 * blueimp Gallery jQuery plugin 1.2.2
15332 * https://github.com/blueimp/Gallery
15333 *
15334 * Copyright 2013, Sebastian Tschan
15335 * https://blueimp.net
15336 *
15337 * Licensed under the MIT license:
15338 * http://www.opensource.org/licenses/MIT
15339 */
15340
15341/* global define, window, document */
15342
15343(function (factory) {
15344    'use strict';
15345    if (typeof define === 'function' && define.amd) {
15346        define([
15347            'jquery',
15348            './blueimp-gallery'
15349        ], factory);
15350    } else {
15351        factory(
15352            window.jQuery,
15353            window.blueimp.Gallery
15354        );
15355    }
15356}(function ($, Gallery) {
15357    'use strict';
15358
15359    // Global click handler to open links with data-gallery attribute
15360    // in the Gallery lightbox:
15361    $(document).on('click', '[data-gallery]', function (event) {
15362        // Get the container id from the data-gallery attribute:
15363        var id = $(this).data('gallery'),
15364            widget = $(id),
15365            container = (widget.length && widget) ||
15366                $(Gallery.prototype.options.container),
15367            callbacks = {
15368                onopen: function () {
15369                    container
15370                        .data('gallery', this)
15371                        .trigger('open');
15372                },
15373                onopened: function () {
15374                    container.trigger('opened');
15375                },
15376                onslide: function () {
15377                    container.trigger('slide', arguments);
15378                },
15379                onslideend: function () {
15380                    container.trigger('slideend', arguments);
15381                },
15382                onslidecomplete: function () {
15383                    container.trigger('slidecomplete', arguments);
15384                },
15385                onclose: function () {
15386                    container.trigger('close');
15387                },
15388                onclosed: function () {
15389                    container
15390                        .trigger('closed')
15391                        .removeData('gallery');
15392                }
15393            },
15394            options = $.extend(
15395                // Retrieve custom options from data-attributes
15396                // on the Gallery widget:
15397                container.data(),
15398                {
15399                    container: container[0],
15400                    index: this,
15401                    event: event
15402                },
15403                callbacks
15404            ),
15405            // Select all links with the same data-gallery attribute:
15406            links = $('[data-gallery="' + id + '"]');
15407        if (options.filter) {
15408            links = links.filter(options.filter);
15409        }
15410        return new Gallery(links, options);
15411    });
15412
15413}));
15414
15415/*
15416 * Bootstrap Image Gallery 3.0.1
15417 * https://github.com/blueimp/Bootstrap-Image-Gallery
15418 *
15419 * Copyright 2013, Sebastian Tschan
15420 * https://blueimp.net
15421 *
15422 * Licensed under the MIT license:
15423 * http://www.opensource.org/licenses/MIT
15424 */
15425
15426/*global define, window */
15427
15428(function (factory) {
15429    'use strict';
15430    if (typeof define === 'function' && define.amd) {
15431        define([
15432            'jquery',
15433            './blueimp-gallery'
15434        ], factory);
15435    } else {
15436        factory(
15437            window.jQuery,
15438            window.blueimp.Gallery
15439        );
15440    }
15441}(function ($, Gallery) {
15442    'use strict';
15443
15444    $.extend(Gallery.prototype.options, {
15445        useBootstrapModal: true
15446    });
15447
15448    var close = Gallery.prototype.close,
15449        imageFactory = Gallery.prototype.imageFactory,
15450        videoFactory = Gallery.prototype.videoFactory,
15451        textFactory = Gallery.prototype.textFactory;
15452
15453    $.extend(Gallery.prototype, {
15454
15455        modalFactory: function (obj, callback, factoryInterface, factory) {
15456            if (!this.options.useBootstrapModal || factoryInterface) {
15457                return factory.call(this, obj, callback, factoryInterface);
15458            }
15459            var that = this,
15460                modalTemplate = this.container.children('.modal'),
15461                modal = modalTemplate.clone().show()
15462                    .on('click', function (event) {
15463                        // Close modal if click is outside of modal-content:
15464                        if (event.target === modal[0] ||
15465                                event.target === modal.children()[0]) {
15466                            event.preventDefault();
15467                            event.stopPropagation();
15468                            that.close();
15469                        }
15470                    }),
15471                element = factory.call(this, obj, function (event) {
15472                    callback({
15473                        type: event.type,
15474                        target: modal[0]
15475                    });
15476                    modal.addClass('in');
15477                }, factoryInterface);
15478            modal.find('.modal-title').text(element.title || String.fromCharCode(160));
15479            modal.find('.modal-body').append(element);
15480            return modal[0];
15481        },
15482
15483        imageFactory: function (obj, callback, factoryInterface) {
15484            return this.modalFactory(obj, callback, factoryInterface, imageFactory);
15485        },
15486
15487        videoFactory: function (obj, callback, factoryInterface) {
15488            return this.modalFactory(obj, callback, factoryInterface, videoFactory);
15489        },
15490
15491        textFactory: function (obj, callback, factoryInterface) {
15492            return this.modalFactory(obj, callback, factoryInterface, textFactory);
15493        },
15494
15495        close: function () {
15496            this.container.find('.modal').removeClass('in');
15497            close.call(this);
15498        }
15499
15500    });
15501
15502}));
15503
15504/*!
15505 * typeahead.js 0.10.5
15506 * https://github.com/twitter/typeahead.js
15507 * Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT
15508 */
15509
15510(function($) {
15511    var _ = function() {
15512        "use strict";
15513        return {
15514            isMsie: function() {
15515                return /(msie|trident)/i.test(navigator.userAgent) ? navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2] : false;
15516            },
15517            isBlankString: function(str) {
15518                return !str || /^\s*$/.test(str);
15519            },
15520            escapeRegExChars: function(str) {
15521                return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
15522            },
15523            isString: function(obj) {
15524                return typeof obj === "string";
15525            },
15526            isNumber: function(obj) {
15527                return typeof obj === "number";
15528            },
15529            isArray: $.isArray,
15530            isFunction: $.isFunction,
15531            isObject: $.isPlainObject,
15532            isUndefined: function(obj) {
15533                return typeof obj === "undefined";
15534            },
15535            toStr: function toStr(s) {
15536                return _.isUndefined(s) || s === null ? "" : s + "";
15537            },
15538            bind: $.proxy,
15539            each: function(collection, cb) {
15540                $.each(collection, reverseArgs);
15541                function reverseArgs(index, value) {
15542                    return cb(value, index);
15543                }
15544            },
15545            map: $.map,
15546            filter: $.grep,
15547            every: function(obj, test) {
15548                var result = true;
15549                if (!obj) {
15550                    return result;
15551                }
15552                $.each(obj, function(key, val) {
15553                    if (!(result = test.call(null, val, key, obj))) {
15554                        return false;
15555                    }
15556                });
15557                return !!result;
15558            },
15559            some: function(obj, test) {
15560                var result = false;
vendor: 6,556 bytes, lines 15561-15750
15561                if (!obj) {
15562                    return result;
15563                }
15564                $.each(obj, function(key, val) {
15565                    if (result = test.call(null, val, key, obj)) {
15566                        return false;
15567                    }
15568                });
15569                return !!result;
15570            },
15571            mixin: $.extend,
15572            getUniqueId: function() {
15573                var counter = 0;
15574                return function() {
15575                    return counter++;
15576                };
15577            }(),
15578            templatify: function templatify(obj) {
15579                return $.isFunction(obj) ? obj : template;
15580                function template() {
15581                    return String(obj);
15582                }
15583            },
15584            defer: function(fn) {
15585                setTimeout(fn, 0);
15586            },
15587            debounce: function(func, wait, immediate) {
15588                var timeout, result;
15589                return function() {
15590                    var context = this, args = arguments, later, callNow;
15591                    later = function() {
15592                        timeout = null;
15593                        if (!immediate) {
15594                            result = func.apply(context, args);
15595                        }
15596                    };
15597                    callNow = immediate && !timeout;
15598                    clearTimeout(timeout);
15599                    timeout = setTimeout(later, wait);
15600                    if (callNow) {
15601                        result = func.apply(context, args);
15602                    }
15603                    return result;
15604                };
15605            },
15606            throttle: function(func, wait) {
15607                var context, args, timeout, result, previous, later;
15608                previous = 0;
15609                later = function() {
15610                    previous = new Date();
15611                    timeout = null;
15612                    result = func.apply(context, args);
15613                };
15614                return function() {
15615                    var now = new Date(), remaining = wait - (now - previous);
15616                    context = this;
15617                    args = arguments;
15618                    if (remaining <= 0) {
15619                        clearTimeout(timeout);
15620                        timeout = null;
15621                        previous = now;
15622                        result = func.apply(context, args);
15623                    } else if (!timeout) {
15624                        timeout = setTimeout(later, remaining);
15625                    }
15626                    return result;
15627                };
15628            },
15629            noop: function() {}
15630        };
15631    }();
15632    var VERSION = "0.10.5";
15633    var tokenizers = function() {
15634        "use strict";
15635        return {
15636            nonword: nonword,
15637            whitespace: whitespace,
15638            obj: {
15639                nonword: getObjTokenizer(nonword),
15640                whitespace: getObjTokenizer(whitespace)
15641            }
15642        };
15643        function whitespace(str) {
15644            str = _.toStr(str);
15645            return str ? str.split(/\s+/) : [];
15646        }
15647        function nonword(str) {
15648            str = _.toStr(str);
15649            return str ? str.split(/\W+/) : [];
15650        }
15651        function getObjTokenizer(tokenizer) {
15652            return function setKey() {
15653                var args = [].slice.call(arguments, 0);
15654                return function tokenize(o) {
15655                    var tokens = [];
15656                    _.each(args, function(k) {
15657                        tokens = tokens.concat(tokenizer(_.toStr(o[k])));
15658                    });
15659                    return tokens;
15660                };
15661            };
15662        }
15663    }();
15664    var LruCache = function() {
15665        "use strict";
15666        function LruCache(maxSize) {
15667            this.maxSize = _.isNumber(maxSize) ? maxSize : 100;
15668            this.reset();
15669            if (this.maxSize <= 0) {
15670                this.set = this.get = $.noop;
15671            }
15672        }
15673        _.mixin(LruCache.prototype, {
15674            set: function set(key, val) {
15675                var tailItem = this.list.tail, node;
15676                if (this.size >= this.maxSize) {
15677                    this.list.remove(tailItem);
15678                    delete this.hash[tailItem.key];
15679                }
15680                if (node = this.hash[key]) {
15681                    node.val = val;
15682                    this.list.moveToFront(node);
15683                } else {
15684                    node = new Node(key, val);
15685                    this.list.add(node);
15686                    this.hash[key] = node;
15687                    this.size++;
15688                }
15689            },
15690            get: function get(key) {
15691                var node = this.hash[key];
15692                if (node) {
15693                    this.list.moveToFront(node);
15694                    return node.val;
15695                }
15696            },
15697            reset: function reset() {
15698                this.size = 0;
15699                this.hash = {};
15700                this.list = new List();
15701            }
15702        });
15703        function List() {
15704            this.head = this.tail = null;
15705        }
15706        _.mixin(List.prototype, {
15707            add: function add(node) {
15708                if (this.head) {
15709                    node.next = this.head;
15710                    this.head.prev = node;
15711                }
15712                this.head = node;
15713                this.tail = this.tail || node;
15714            },
15715            remove: function remove(node) {
15716                node.prev ? node.prev.next = node.next : this.head = node.next;
15717                node.next ? node.next.prev = node.prev : this.tail = node.prev;
15718            },
15719            moveToFront: function(node) {
15720                this.remove(node);
15721                this.add(node);
15722            }
15723        });
15724        function Node(key, val) {
15725            this.key = key;
15726            this.val = val;
15727            this.prev = this.next = null;
15728        }
15729        return LruCache;
15730    }();
15731    var PersistentStorage = function() {
15732        "use strict";
15733        var ls, methods;
15734        try {
15735            ls = window.localStorage;
15736            ls.setItem("~~~", "!");
15737            ls.removeItem("~~~");
15738        } catch (err) {
15739            ls = null;
15740        }
15741        function PersistentStorage(namespace) {
15742            this.prefix = [ "__", namespace, "__" ].join("");
15743            this.ttlKey = "__ttl__";
15744            this.keyMatcher = new RegExp("^" + _.escapeRegExChars(this.prefix));
15745        }
15746        if (ls && window.JSON) {
15747            methods = {
15748                _prefix: function(key) {
15749                    return this.prefix + key;
15750                },
15751                _ttlKey: function(key) {
15752                    return this._prefix(key) + this.ttlKey;
15753                },
15754                get: function(key) {
15755                    if (this.isExpired(key)) {
15756                        this.remove(key);
15757                    }
15758                    return decode(ls.getItem(this._prefix(key)));
15759                },
15760                set: function(key, val, ttl) {
15761                    if (_.isNumber(ttl)) {
15762                        ls.setItem(this._ttlKey(key), encode(now() + ttl));
15763                    } else {
15764                        ls.removeItem(this._ttlKey(key));
15765                    }
15766                    return ls.setItem(this._prefix(key), encode(val));
15767                },
15768                remove: function(key) {
15769                    ls.removeItem(this._ttlKey(key));
15770                    ls.removeItem(this._prefix(key));
15771                    return this;
15772                },
15773                clear: function() {
15774                    var i, key, keys = [], len = ls.length;
15775                    for (i = 0; i < len; i++) {
15776                        if ((key = ls.key(i)).match(this.keyMatcher)) {
15777                            keys.push(key.replace(this.keyMatcher, ""));
15778                        }
15779                    }
15780                    for (i = keys.length; i--; ) {
15781                        this.remove(keys[i]);
15782                    }
15783                    return this;
15784                },
15785                isExpired: function(key) {
15786                    var ttl = decode(ls.getItem(this._ttlKey(key)));
15787                    return _.isNumber(ttl) && now() > ttl ? true : false;
15788                }
15789            };
15790        } else {
15791            methods = {
15792                get: _.noop,
15793                set: _.noop,
15794                remove: _.noop,
15795                clear: _.noop,
15796                isExpired: _.noop
15797            };
15798        }
15799        _.mixin(PersistentStorage.prototype, methods);
15800        return PersistentStorage;
15801        function now() {
15802            return new Date().getTime();
15803        }
15804        function encode(val) {
15805            return JSON.stringify(_.isUndefined(val) ? null : val);
15806        }
15807        function decode(val) {
15808            return JSON.parse(val);
15809        }
15810    }();
15811    var Transport = function() {
15812        "use strict";
15813        var pendingRequestsCount = 0, pendingRequests = {}, maxPendingRequests = 6, sharedCache = new LruCache(10);
15814        function Transport(o) {
15815            o = o || {};
15816            this.cancelled = false;
15817            this.lastUrl = null;
15818            this._send = o.transport ? callbackToDeferred(o.transport) : $.ajax;
15819            this._get = o.rateLimiter ? o.rateLimiter(this._get) : this._get;
15820            this._cache = o.cache === false ? new LruCache(0) : sharedCache;
15821        }
15822        Transport.setMaxPendingRequests = function setMaxPendingRequests(num) {
15823            maxPendingRequests = num;
15824        };
15825        Transport.resetCache = function resetCache() {
15826            sharedCache.reset();
15827        };
15828        _.mixin(Transport.prototype, {
15829            _get: function(url, o, cb) {
15830                var that = this, jqXhr;
15831                if (this.cancelled || url !== this.lastUrl) {
15832                    return;
15833                }
15834                if (jqXhr = pendingRequests[url]) {
15835                    jqXhr.done(done).fail(fail);
15836                } else if (pendingRequestsCount < maxPendingRequests) {
15837                    pendingRequestsCount++;
15838                    pendingRequests[url] = this._send(url, o).done(done).fail(fail).always(always);
15839                } else {
15840                    this.onDeckRequestArgs = [].slice.call(arguments, 0);
15841                }
15842                function done(resp) {
15843                    cb && cb(null, resp);
15844                    that._cache.set(url, resp);
15845                }
15846                function fail() {
15847                    cb && cb(true);
15848                }
15849                function always() {
15850                    pendingRequestsCount--;
15851                    delete pendingRequests[url];
15852                    if (that.onDeckRequestArgs) {
15853                        that._get.apply(that, that.onDeckRequestArgs);
15854                        that.onDeckRequestArgs = null;
15855                    }
15856                }
15857            },
15858            get: function(url, o, cb) {
15859                var resp;
15860                if (_.isFunction(o)) {
15861                    cb = o;
15862                    o = {};
15863                }
15864                this.cancelled = false;
15865                this.lastUrl = url;
15866                if (resp = this._cache.get(url)) {
15867                    _.defer(function() {
15868                        cb && cb(null, resp);
15869                    });
15870                } else {
15871                    this._get(url, o, cb);
15872                }
15873                return !!resp;
15874            },
15875            cancel: function() {
15876                this.cancelled = true;
15877            }
15878        });
15879        return Transport;
15880        function callbackToDeferred(fn) {
15881            return function customSendWrapper(url, o) {
15882                var deferred = $.Deferred();
15883                fn(url, o, onSuccess, onError);
15884                return deferred;
15885                function onSuccess(resp) {
15886                    _.defer(function() {
15887                        deferred.resolve(resp);
15888                    });
15889                }
15890                function onError(err) {
15891                    _.defer(function() {
15892                        deferred.reject(err);
15893                    });
15894                }
15895            };
15896        }
15897    }();
15898    var SearchIndex = function() {
15899        "use strict";
15900        function SearchIndex(o) {
15901            o = o || {};
15902            if (!o.datumTokenizer || !o.queryTokenizer) {
15903                $.error("datumTokenizer and queryTokenizer are both required");
15904            }
15905            this.datumTokenizer = o.datumTokenizer;
15906            this.queryTokenizer = o.queryTokenizer;
15907            this.reset();
15908        }
15909        _.mixin(SearchIndex.prototype, {
15910            bootstrap: function bootstrap(o) {
15911                this.datums = o.datums;
15912                this.trie = o.trie;
15913            },
15914            add: function(data) {
15915                var that = this;
15916                data = _.isArray(data) ? data : [ data ];
15917                _.each(data, function(datum) {
15918                    var id, tokens;
15919                    id = that.datums.push(datum) - 1;
15920                    tokens = normalizeTokens(that.datumTokenizer(datum));
15921                    _.each(tokens, function(token) {
15922                        var node, chars, ch;
15923                        node = that.trie;
15924                        chars = token.split("");
15925                        while (ch = chars.shift()) {
15926                            node = node.children[ch] || (node.children[ch] = newNode());
15927                            node.ids.push(id);
15928                        }
15929                    });
15930                });
15931            },
15932            get: function get(query) {
15933                var that = this, tokens, matches;
15934                tokens = normalizeTokens(this.queryTokenizer(query));
15935                _.each(tokens, function(token) {
15936                    var node, chars, ch, ids;
15937                    if (matches && matches.length === 0) {
15938                        return false;
15939                    }
15940                    node = that.trie;
15941                    chars = token.split("");
15942                    while (node && (ch = chars.shift())) {
15943                        node = node.children[ch];
15944                    }
15945                    if (node && chars.length === 0) {
15946                        ids = node.ids.slice(0);
15947                        matches = matches ? getIntersection(matches, ids) : ids;
15948                    } else {
15949                        matches = [];
15950                        return false;
15951                    }
15952                });
15953                return matches ? _.map(unique(matches), function(id) {
15954                    return that.datums[id];
15955                }) : [];
15956            },
15957            reset: function reset() {
15958                this.datums = [];
15959                this.trie = newNode();
15960            },
15961            serialize: function serialize() {
15962                return {
15963                    datums: this.datums,
15964                    trie: this.trie
15965                };
15966            }
15967        });
15968        return SearchIndex;
15969        function normalizeTokens(tokens) {
15970            tokens = _.filter(tokens, function(token) {
15971                return !!token;
15972            });
15973            tokens = _.map(tokens, function(token) {
15974                return token.toLowerCase();
15975            });
15976            return tokens;
15977        }
15978        function newNode() {
15979            return {
15980                ids: [],
15981                children: {}
15982            };
15983        }
15984        function unique(array) {
15985            var seen = {}, uniques = [];
15986            for (var i = 0, len = array.length; i < len; i++) {
15987                if (!seen[array[i]]) {
15988                    seen[array[i]] = true;
15989                    uniques.push(array[i]);
15990                }
15991            }
15992            return uniques;
15993        }
15994        function getIntersection(arrayA, arrayB) {
15995            var ai = 0, bi = 0, intersection = [];
15996            arrayA = arrayA.sort(compare);
15997            arrayB = arrayB.sort(compare);
15998            var lenArrayA = arrayA.length, lenArrayB = arrayB.length;
15999            while (ai < lenArrayA && bi < lenArrayB) {
16000                if (arrayA[ai] < arrayB[bi]) {
16001                    ai++;
16002                } else if (arrayA[ai] > arrayB[bi]) {
16003                    bi++;
16004                } else {
16005                    intersection.push(arrayA[ai]);
16006                    ai++;
16007                    bi++;
16008                }
16009            }
16010            return intersection;
16011            function compare(a, b) {
16012                return a - b;
16013            }
16014        }
16015    }();
16016    var oParser = function() {
16017        "use strict";
16018        return {
16019            local: getLocal,
16020            prefetch: getPrefetch,
16021            remote: getRemote
16022        };
16023        function getLocal(o) {
16024            return o.local || null;
16025        }
16026        function getPrefetch(o) {
16027            var prefetch, defaults;
16028            defaults = {
16029                url: null,
16030                thumbprint: "",
16031                ttl: 24 * 60 * 60 * 1e3,
16032                filter: null,
16033                ajax: {}
16034            };
16035            if (prefetch = o.prefetch || null) {
16036                prefetch = _.isString(prefetch) ? {
16037                    url: prefetch
16038                } : prefetch;
16039                prefetch = _.mixin(defaults, prefetch);
16040                prefetch.thumbprint = VERSION + prefetch.thumbprint;
16041                prefetch.ajax.type = prefetch.ajax.type || "GET";
16042                prefetch.ajax.dataType = prefetch.ajax.dataType || "json";
16043                !prefetch.url && $.error("prefetch requires url to be set");
16044            }
16045            return prefetch;
16046        }
16047        function getRemote(o) {
16048            var remote, defaults;
16049            defaults = {
16050                url: null,
16051                cache: true,
16052                wildcard: "%QUERY",
16053                replace: null,
16054                rateLimitBy: "debounce",
16055                rateLimitWait: 300,
16056                send: null,
16057                filter: null,
16058                ajax: {}
16059            };
16060            if (remote = o.remote || null) {
16061                remote = _.isString(remote) ? {
16062                    url: remote
16063                } : remote;
16064                remote = _.mixin(defaults, remote);
16065                remote.rateLimiter = /^throttle$/i.test(remote.rateLimitBy) ? byThrottle(remote.rateLimitWait) : byDebounce(remote.rateLimitWait);
16066                remote.ajax.type = remote.ajax.type || "GET";
16067                remote.ajax.dataType = remote.ajax.dataType || "json";
16068                delete remote.rateLimitBy;
16069                delete remote.rateLimitWait;
16070                !remote.url && $.error("remote requires url to be set");
16071            }
16072            return remote;
16073            function byDebounce(wait) {
16074                return function(fn) {
16075                    return _.debounce(fn, wait);
16076                };
16077            }
16078            function byThrottle(wait) {
16079                return function(fn) {
16080                    return _.throttle(fn, wait);
16081                };
16082            }
16083        }
16084    }();
16085    (function(root) {
16086        "use strict";
16087        var old, keys;
16088        old = root.Bloodhound;
16089        keys = {
16090            data: "data",
16091            protocol: "protocol",
16092            thumbprint: "thumbprint"
16093        };
16094        root.Bloodhound = Bloodhound;
16095        function Bloodhound(o) {
16096            if (!o || !o.local && !o.prefetch && !o.remote) {
16097                $.error("one of local, prefetch, or remote is required");
16098            }
16099            this.limit = o.limit || 5;
16100            this.sorter = getSorter(o.sorter);
16101            this.dupDetector = o.dupDetector || ignoreDuplicates;
16102            this.local = oParser.local(o);
16103            this.prefetch = oParser.prefetch(o);
16104            this.remote = oParser.remote(o);
16105            this.cacheKey = this.prefetch ? this.prefetch.cacheKey || this.prefetch.url : null;
16106            this.index = new SearchIndex({
16107                datumTokenizer: o.datumTokenizer,
16108                queryTokenizer: o.queryTokenizer
16109            });
16110            this.storage = this.cacheKey ? new PersistentStorage(this.cacheKey) : null;
16111        }
16112        Bloodhound.noConflict = function noConflict() {
16113            root.Bloodhound = old;
16114            return Bloodhound;
16115        };
16116        Bloodhound.tokenizers = tokenizers;
16117        _.mixin(Bloodhound.prototype, {
16118            _loadPrefetch: function loadPrefetch(o) {
16119                var that = this, serialized, deferred;
16120                if (serialized = this._readFromStorage(o.thumbprint)) {
16121                    this.index.bootstrap(serialized);
16122                    deferred = $.Deferred().resolve();
16123                } else {
16124                    deferred = $.ajax(o.url, o.ajax).done(handlePrefetchResponse);
16125                }
16126                return deferred;
16127                function handlePrefetchResponse(resp) {
16128                    that.clear();
16129                    that.add(o.filter ? o.filter(resp) : resp);
16130                    that._saveToStorage(that.index.serialize(), o.thumbprint, o.ttl);
16131                }
16132            },
16133            _getFromRemote: function getFromRemote(query, cb) {
16134                var that = this, url, uriEncodedQuery;
16135                if (!this.transport) {
16136                    return;
16137                }
16138                query = query || "";
16139                uriEncodedQuery = encodeURIComponent(query);
16140                url = this.remote.replace ? this.remote.replace(this.remote.url, query) : this.remote.url.replace(this.remote.wildcard, uriEncodedQuery);
16141                return this.transport.get(url, this.remote.ajax, handleRemoteResponse);
16142                function handleRemoteResponse(err, resp) {
16143                    err ? cb([]) : cb(that.remote.filter ? that.remote.filter(resp) : resp);
16144                }
16145            },
16146            _cancelLastRemoteRequest: function cancelLastRemoteRequest() {
16147                this.transport && this.transport.cancel();
16148            },
16149            _saveToStorage: function saveToStorage(data, thumbprint, ttl) {
16150                if (this.storage) {
16151                    this.storage.set(keys.data, data, ttl);
16152                    this.storage.set(keys.protocol, location.protocol, ttl);
16153                    this.storage.set(keys.thumbprint, thumbprint, ttl);
16154                }
16155            },
16156            _readFromStorage: function readFromStorage(thumbprint) {
16157                var stored = {}, isExpired;
16158                if (this.storage) {
16159                    stored.data = this.storage.get(keys.data);
16160                    stored.protocol = this.storage.get(keys.protocol);
16161                    stored.thumbprint = this.storage.get(keys.thumbprint);
16162                }
16163                isExpired = stored.thumbprint !== thumbprint || stored.protocol !== location.protocol;
16164                return stored.data && !isExpired ? stored.data : null;
16165            },
16166            _initialize: function initialize() {
16167                var that = this, local = this.local, deferred;
16168                deferred = this.prefetch ? this._loadPrefetch(this.prefetch) : $.Deferred().resolve();
16169                local && deferred.done(addLocalToIndex);
16170                this.transport = this.remote ? new Transport(this.remote) : null;
16171                return this.initPromise = deferred.promise();
16172                function addLocalToIndex() {
16173                    that.add(_.isFunction(local) ? local() : local);
16174                }
16175            },
16176            initialize: function initialize(force) {
16177                return !this.initPromise || force ? this._initialize() : this.initPromise;
16178            },
16179            add: function add(data) {
16180                this.index.add(data);
16181            },
16182            get: function get(query, cb) {
16183                var that = this, matches = [], cacheHit = false;
16184                matches = this.index.get(query);
16185                matches = this.sorter(matches).slice(0, this.limit);
16186                matches.length < this.limit ? cacheHit = this._getFromRemote(query, returnRemoteMatches) : this._cancelLastRemoteRequest();
16187                if (!cacheHit) {
16188                    (matches.length > 0 || !this.transport) && cb && cb(matches);
16189                }
16190                function returnRemoteMatches(remoteMatches) {
16191                    var matchesWithBackfill = matches.slice(0);
16192                    _.each(remoteMatches, function(remoteMatch) {
16193                        var isDuplicate;
16194                        isDuplicate = _.some(matchesWithBackfill, function(match) {
16195                            return that.dupDetector(remoteMatch, match);
16196                        });
16197                        !isDuplicate && matchesWithBackfill.push(remoteMatch);
16198                        return matchesWithBackfill.length < that.limit;
16199                    });
16200                    cb && cb(that.sorter(matchesWithBackfill));
16201                }
16202            },
16203            clear: function clear() {
16204                this.index.reset();
16205            },
16206            clearPrefetchCache: function clearPrefetchCache() {
16207                this.storage && this.storage.clear();
16208            },
16209            clearRemoteCache: function clearRemoteCache() {
16210                this.transport && Transport.resetCache();
16211            },
16212            ttAdapter: function ttAdapter() {
16213                return _.bind(this.get, this);
16214            }
16215        });
16216        return Bloodhound;
16217        function getSorter(sortFn) {
16218            return _.isFunction(sortFn) ? sort : noSort;
16219            function sort(array) {
16220                return array.sort(sortFn);
16221            }
16222            function noSort(array) {
16223                return array;
16224            }
16225        }
16226        function ignoreDuplicates() {
16227            return false;
16228        }
16229    })(this);
16230})(window.jQuery);
16231/*!
16232
16233 handlebars v2.0.0
16234
16235Copyright (C) 2011-2014 by Yehuda Katz
16236
16237Permission is hereby granted, free of charge, to any person obtaining a copy
16238of this software and associated documentation files (the "Software"), to deal
16239in the Software without restriction, including without limitation the rights
16240to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16241copies of the Software, and to permit persons to whom the Software is
16242furnished to do so, subject to the following conditions:
16243
16244The above copyright notice and this permission notice shall be included in
16245all copies or substantial portions of the Software.
16246
16247THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16248IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16249FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16250AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16251LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16252OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
16253THE SOFTWARE.
16254
16255@license
16256*/
16257/* exported Handlebars */
16258(function (root, factory) {
16259  if (typeof define === 'function' && define.amd) {
16260    define([], factory);
16261  } else if (typeof exports === 'object') {
16262    module.exports = factory();
16263  } else {
16264    root.Handlebars = root.Handlebars || factory();
16265  }
16266}(this, function () {
16267// handlebars/safe-string.js
16268var __module4__ = (function() {
16269  "use strict";
16270  var __exports__;
16271  // Build out our basic SafeString type
16272  function SafeString(string) {
16273    this.string = string;
16274  }
16275
16276  SafeString.prototype.toString = function() {
16277    return "" + this.string;
16278  };
16279
16280  __exports__ = SafeString;
16281  return __exports__;
16282})();
16283
16284// handlebars/utils.js
16285var __module3__ = (function(__dependency1__) {
16286  "use strict";
16287  var __exports__ = {};
16288  /*jshint -W004 */
16289  var SafeString = __dependency1__;
16290
16291  var escape = {
16292    "&": "&amp;",
16293    "<": "&lt;",
16294    ">": "&gt;",
16295    '"': "&quot;",
16296    "'": "&#x27;",
16297    "`": "&#x60;"
16298  };
16299
16300  var badChars = /[&<>"'`]/g;
16301  var possible = /[&<>"'`]/;
16302
16303  function escapeChar(chr) {
16304    return escape[chr];
16305  }
16306
16307  function extend(obj /* , ...source */) {
16308    for (var i = 1; i < arguments.length; i++) {
16309      for (var key in arguments[i]) {
16310        if (Object.prototype.hasOwnProperty.call(arguments[i], key)) {
16311          obj[key] = arguments[i][key];
16312        }
16313      }
16314    }
16315
16316    return obj;
16317  }
16318
16319  __exports__.extend = extend;var toString = Object.prototype.toString;
16320  __exports__.toString = toString;
16321  // Sourced from lodash
16322  // https://github.com/bestiejs/lodash/blob/master/LICENSE.txt
16323  var isFunction = function(value) {
16324    return typeof value === 'function';
16325  };
16326  // fallback for older versions of Chrome and Safari
16327  /* istanbul ignore next */
16328  if (isFunction(/x/)) {
16329    isFunction = function(value) {
16330      return typeof value === 'function' && toString.call(value) === '[object Function]';
16331    };
16332  }
16333  var isFunction;
16334  __exports__.isFunction = isFunction;
16335  /* istanbul ignore next */
16336  var isArray = Array.isArray || function(value) {
16337    return (value && typeof value === 'object') ? toString.call(value) === '[object Array]' : false;
16338  };
16339  __exports__.isArray = isArray;
16340
16341  function escapeExpression(string) {
16342    // don't escape SafeStrings, since they're already safe
16343    if (string instanceof SafeString) {
16344      return string.toString();
16345    } else if (string == null) {
16346      return "";
16347    } else if (!string) {
16348      return string + '';
16349    }
16350
16351    // Force a string conversion as this will be done by the append regardless and
16352    // the regex test will do this transparently behind the scenes, causing issues if
16353    // an object's to string has escaped characters in it.
16354    string = "" + string;
16355
16356    if(!possible.test(string)) { return string; }
16357    return string.replace(badChars, escapeChar);
16358  }
16359
16360  __exports__.escapeExpression = escapeExpression;function isEmpty(value) {
16361    if (!value && value !== 0) {
16362      return true;
16363    } else if (isArray(value) && value.length === 0) {
16364      return true;
16365    } else {
16366      return false;
16367    }
16368  }
16369
16370  __exports__.isEmpty = isEmpty;function appendContextPath(contextPath, id) {
16371    return (contextPath ? contextPath + '.' : '') + id;
16372  }
16373
16374  __exports__.appendContextPath = appendContextPath;
16375  return __exports__;
16376})(__module4__);
16377
16378// handlebars/exception.js
16379var __module5__ = (function() {
16380  "use strict";
16381  var __exports__;
16382
16383  var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack'];
16384
16385  function Exception(message, node) {
16386    var line;
16387    if (node && node.firstLine) {
16388      line = node.firstLine;
16389
16390      message += ' - ' + line + ':' + node.firstColumn;
16391    }
16392
16393    var tmp = Error.prototype.constructor.call(this, message);
16394
16395    // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work.
16396    for (var idx = 0; idx < errorProps.length; idx++) {
16397      this[errorProps[idx]] = tmp[errorProps[idx]];
16398    }
16399
16400    if (line) {
16401      this.lineNumber = line;
16402      this.column = node.firstColumn;
16403    }
16404  }
16405
16406  Exception.prototype = new Error();
16407
16408  __exports__ = Exception;
16409  return __exports__;
16410})();
16411
16412// handlebars/base.js
16413var __module2__ = (function(__dependency1__, __dependency2__) {
16414  "use strict";
16415  var __exports__ = {};
16416  var Utils = __dependency1__;
16417  var Exception = __dependency2__;
16418
16419  var VERSION = "2.0.0";
16420  __exports__.VERSION = VERSION;var COMPILER_REVISION = 6;
16421  __exports__.COMPILER_REVISION = COMPILER_REVISION;
16422  var REVISION_CHANGES = {
16423    1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it
16424    2: '== 1.0.0-rc.3',
16425    3: '== 1.0.0-rc.4',
16426    4: '== 1.x.x',
16427    5: '== 2.0.0-alpha.x',
16428    6: '>= 2.0.0-beta.1'
16429  };
16430  __exports__.REVISION_CHANGES = REVISION_CHANGES;
16431  var isArray = Utils.isArray,
16432      isFunction = Utils.isFunction,
16433      toString = Utils.toString,
16434      objectType = '[object Object]';
16435
16436  function HandlebarsEnvironment(helpers, partials) {
16437    this.helpers = helpers || {};
16438    this.partials = partials || {};
16439
16440    registerDefaultHelpers(this);
16441  }
16442
16443  __exports__.HandlebarsEnvironment = HandlebarsEnvironment;HandlebarsEnvironment.prototype = {
16444    constructor: HandlebarsEnvironment,
16445
16446    logger: logger,
16447    log: log,
16448
16449    registerHelper: function(name, fn) {
16450      if (toString.call(name) === objectType) {
16451        if (fn) { throw new Exception('Arg not supported with multiple helpers'); }
16452        Utils.extend(this.helpers, name);
16453      } else {
16454        this.helpers[name] = fn;
16455      }
16456    },
16457    unregisterHelper: function(name) {
16458      delete this.helpers[name];
16459    },
16460
16461    registerPartial: function(name, partial) {
16462      if (toString.call(name) === objectType) {
16463        Utils.extend(this.partials,  name);
16464      } else {
16465        this.partials[name] = partial;
16466      }
16467    },
16468    unregisterPartial: function(name) {
16469      delete this.partials[name];
16470    }
16471  };
16472
16473  function registerDefaultHelpers(instance) {
16474    instance.registerHelper('helperMissing', function(/* [args, ]options */) {
16475      if(arguments.length === 1) {
16476        // A missing field in a {{foo}} constuct.
16477        return undefined;
16478      } else {
16479        // Someone is actually trying to call something, blow up.
16480        throw new Exception("Missing helper: '" + arguments[arguments.length-1].name + "'");
16481      }
16482    });
16483
16484    instance.registerHelper('blockHelperMissing', function(context, options) {
16485      var inverse = options.inverse,
16486          fn = options.fn;
16487
16488      if(context === true) {
16489        return fn(this);
16490      } else if(context === false || context == null) {
16491        return inverse(this);
16492      } else if (isArray(context)) {
16493        if(context.length > 0) {
16494          if (options.ids) {
16495            options.ids = [options.name];
16496          }
16497
16498          return instance.helpers.each(context, options);
16499        } else {
16500          return inverse(this);
16501        }
16502      } else {
16503        if (options.data && options.ids) {
16504          var data = createFrame(options.data);
16505          data.contextPath = Utils.appendContextPath(options.data.contextPath, options.name);
16506          options = {data: data};
16507        }
16508
16509        return fn(context, options);
16510      }
16511    });
16512
16513    instance.registerHelper('each', function(context, options) {
16514      if (!options) {
16515        throw new Exception('Must pass iterator to #each');
16516      }
16517
16518      var fn = options.fn, inverse = options.inverse;
16519      var i = 0, ret = "", data;
16520
16521      var contextPath;
16522      if (options.data && options.ids) {
16523        contextPath = Utils.appendContextPath(options.data.contextPath, options.ids[0]) + '.';
16524      }
16525
16526      if (isFunction(context)) { context = context.call(this); }
16527
16528      if (options.data) {
16529        data = createFrame(options.data);
16530      }
16531
16532      if(context && typeof context === 'object') {
16533        if (isArray(context)) {
16534          for(var j = context.length; i<j; i++) {
16535            if (data) {
16536              data.index = i;
16537              data.first = (i === 0);
16538              data.last  = (i === (context.length-1));
16539
16540              if (contextPath) {
16541                data.contextPath = contextPath + i;
16542              }
16543            }
16544            ret = ret + fn(context[i], { data: data });
16545          }
16546        } else {
16547          for(var key in context) {
16548            if(context.hasOwnProperty(key)) {
16549              if(data) {
16550                data.key = key;
16551                data.index = i;
16552                data.first = (i === 0);
16553
16554                if (contextPath) {
16555                  data.contextPath = contextPath + key;
16556                }
16557              }
16558              ret = ret + fn(context[key], {data: data});
16559              i++;
16560            }
16561          }
16562        }
16563      }
16564
16565      if(i === 0){
16566        ret = inverse(this);
16567      }
16568
16569      return ret;
16570    });
16571
16572    instance.registerHelper('if', function(conditional, options) {
16573      if (isFunction(conditional)) { conditional = conditional.call(this); }
16574
16575      // Default behavior is to render the positive path if the value is truthy and not empty.
16576      // The `includeZero` option may be set to treat the condtional as purely not empty based on the
16577      // behavior of isEmpty. Effectively this determines if 0 is handled by the positive path or negative.
16578      if ((!options.hash.includeZero && !conditional) || Utils.isEmpty(conditional)) {
16579        return options.inverse(this);
16580      } else {
16581        return options.fn(this);
16582      }
16583    });
16584
16585    instance.registerHelper('unless', function(conditional, options) {
16586      return instance.helpers['if'].call(this, conditional, {fn: options.inverse, inverse: options.fn, hash: options.hash});
16587    });
16588
16589    instance.registerHelper('with', function(context, options) {
16590      if (isFunction(context)) { context = context.call(this); }
16591
16592      var fn = options.fn;
16593
16594      if (!Utils.isEmpty(context)) {
16595        if (options.data && options.ids) {
16596          var data = createFrame(options.data);
16597          data.contextPath = Utils.appendContextPath(options.data.contextPath, options.ids[0]);
16598          options = {data:data};
16599        }
16600
16601        return fn(context, options);
16602      } else {
16603        return options.inverse(this);
16604      }
16605    });
16606
16607    instance.registerHelper('log', function(message, options) {
16608      var level = options.data && options.data.level != null ? parseInt(options.data.level, 10) : 1;
16609      instance.log(level, message);
16610    });
16611
16612    instance.registerHelper('lookup', function(obj, field) {
16613      return obj && obj[field];
16614    });
16615  }
16616
16617  var logger = {
16618    methodMap: { 0: 'debug', 1: 'info', 2: 'warn', 3: 'error' },
16619
16620    // State enum
16621    DEBUG: 0,
16622    INFO: 1,
16623    WARN: 2,
16624    ERROR: 3,
16625    level: 3,
16626
16627    // can be overridden in the host environment
16628    log: function(level, message) {
16629      if (logger.level <= level) {
16630        var method = logger.methodMap[level];
16631        if (typeof console !== 'undefined' && console[method]) {
16632          console[method].call(console, message);
16633        }
16634      }
16635    }
16636  };
16637  __exports__.logger = logger;
16638  var log = logger.log;
16639  __exports__.log = log;
16640  var createFrame = function(object) {
16641    var frame = Utils.extend({}, object);
16642    frame._parent = object;
16643    return frame;
16644  };
16645  __exports__.createFrame = createFrame;
16646  return __exports__;
16647})(__module3__, __module5__);
16648
16649// handlebars/runtime.js
16650var __module6__ = (function(__dependency1__, __dependency2__, __dependency3__) {
16651  "use strict";
16652  var __exports__ = {};
16653  var Utils = __dependency1__;
16654  var Exception = __dependency2__;
16655  var COMPILER_REVISION = __dependency3__.COMPILER_REVISION;
16656  var REVISION_CHANGES = __dependency3__.REVISION_CHANGES;
16657  var createFrame = __dependency3__.createFrame;
16658
16659  function checkRevision(compilerInfo) {
16660    var compilerRevision = compilerInfo && compilerInfo[0] || 1,
16661        currentRevision = COMPILER_REVISION;
16662
16663    if (compilerRevision !== currentRevision) {
16664      if (compilerRevision < currentRevision) {
16665        var runtimeVersions = REVISION_CHANGES[currentRevision],
16666            compilerVersions = REVISION_CHANGES[compilerRevision];
16667        throw new Exception("Template was precompiled with an older version of Handlebars than the current runtime. "+
16668              "Please update your precompiler to a newer version ("+runtimeVersions+") or downgrade your runtime to an older version ("+compilerVersions+").");
16669      } else {
16670        // Use the embedded version info since the runtime doesn't know about this revision yet
16671        throw new Exception("Template was precompiled with a newer version of Handlebars than the current runtime. "+
16672              "Please update your runtime to a newer version ("+compilerInfo[1]+").");
16673      }
16674    }
16675  }
16676
16677  __exports__.checkRevision = checkRevision;// TODO: Remove this line and break up compilePartial
16678
16679  function template(templateSpec, env) {
16680    /* istanbul ignore next */
16681    if (!env) {
16682      throw new Exception("No environment passed to template");
16683    }
16684    if (!templateSpec || !templateSpec.main) {
16685      throw new Exception('Unknown template object: ' + typeof templateSpec);
16686    }
16687
16688    // Note: Using env.VM references rather than local var references throughout this section to allow
16689    // for external users to override these as psuedo-supported APIs.
16690    env.VM.checkRevision(templateSpec.compiler);
16691
16692    var invokePartialWrapper = function(partial, indent, name, context, hash, helpers, partials, data, depths) {
16693      if (hash) {
16694        context = Utils.extend({}, context, hash);
16695      }
16696
16697      var result = env.VM.invokePartial.call(this, partial, name, context, helpers, partials, data, depths);
16698
16699      if (result == null && env.compile) {
16700        var options = { helpers: helpers, partials: partials, data: data, depths: depths };
16701        partials[name] = env.compile(partial, { data: data !== undefined, compat: templateSpec.compat }, env);
16702        result = partials[name](context, options);
16703      }
16704      if (result != null) {
16705        if (indent) {
16706          var lines = result.split('\n');
16707          for (var i = 0, l = lines.length; i < l; i++) {
16708            if (!lines[i] && i + 1 === l) {
16709              break;
16710            }
16711
16712            lines[i] = indent + lines[i];
16713          }
16714          result = lines.join('\n');
16715        }
16716        return result;
16717      } else {
16718        throw new Exception("The partial " + name + " could not be compiled when running in runtime-only mode");
16719      }
16720    };
16721
16722    // Just add water
16723    var container = {
16724      lookup: function(depths, name) {
16725        var len = depths.length;
16726        for (var i = 0; i < len; i++) {
16727          if (depths[i] && depths[i][name] != null) {
16728            return depths[i][name];
16729          }
16730        }
16731      },
16732      lambda: function(current, context) {
16733        return typeof current === 'function' ? current.call(context) : current;
16734      },
16735
16736      escapeExpression: Utils.escapeExpression,
16737      invokePartial: invokePartialWrapper,
16738
16739      fn: function(i) {
16740        return templateSpec[i];
16741      },
16742
16743      programs: [],
16744      program: function(i, data, depths) {
16745        var programWrapper = this.programs[i],
16746            fn = this.fn(i);
16747        if (data || depths) {
16748          programWrapper = program(this, i, fn, data, depths);
16749        } else if (!programWrapper) {
16750          programWrapper = this.programs[i] = program(this, i, fn);
16751        }
16752        return programWrapper;
16753      },
16754
16755      data: function(data, depth) {
16756        while (data && depth--) {
16757          data = data._parent;
16758        }
16759        return data;
16760      },
16761      merge: function(param, common) {
16762        var ret = param || common;
16763
16764        if (param && common && (param !== common)) {
16765          ret = Utils.extend({}, common, param);
16766        }
16767
16768        return ret;
16769      },
16770
16771      noop: env.VM.noop,
16772      compilerInfo: templateSpec.compiler
16773    };
16774
16775    var ret = function(context, options) {
16776      options = options || {};
16777      var data = options.data;
16778
16779      ret._setup(options);
16780      if (!options.partial && templateSpec.useData) {
16781        data = initData(context, data);
16782      }
16783      var depths;
16784      if (templateSpec.useDepths) {
16785        depths = options.depths ? [context].concat(options.depths) : [context];
16786      }
16787
16788      return templateSpec.main.call(container, context, container.helpers, container.partials, data, depths);
16789    };
16790    ret.isTop = true;
16791
16792    ret._setup = function(options) {
16793      if (!options.partial) {
16794        container.helpers = container.merge(options.helpers, env.helpers);
16795
16796        if (templateSpec.usePartial) {
16797          container.partials = container.merge(options.partials, env.partials);
16798        }
16799      } else {
16800        container.helpers = options.helpers;
16801        container.partials = options.partials;
16802      }
16803    };
16804
16805    ret._child = function(i, data, depths) {
16806      if (templateSpec.useDepths && !depths) {
16807        throw new Exception('must pass parent depths');
16808      }
16809
16810      return program(container, i, templateSpec[i], data, depths);
16811    };
16812    return ret;
16813  }
16814
16815  __exports__.template = template;function program(container, i, fn, data, depths) {
16816    var prog = function(context, options) {
16817      options = options || {};
16818
16819      return fn.call(container, context, container.helpers, container.partials, options.data || data, depths && [context].concat(depths));
16820    };
16821    prog.program = i;
16822    prog.depth = depths ? depths.length : 0;
16823    return prog;
16824  }
16825
16826  __exports__.program = program;function invokePartial(partial, name, context, helpers, partials, data, depths) {
16827    var options = { partial: true, helpers: helpers, partials: partials, data: data, depths: depths };
16828
16829    if(partial === undefined) {
16830      throw new Exception("The partial " + name + " could not be found");
16831    } else if(partial instanceof Function) {
16832      return partial(context, options);
16833    }
16834  }
16835
16836  __exports__.invokePartial = invokePartial;function noop() { return ""; }
16837
16838  __exports__.noop = noop;function initData(context, data) {
16839    if (!data || !('root' in data)) {
16840      data = data ? createFrame(data) : {};
16841      data.root = context;
16842    }
16843    return data;
16844  }
16845  return __exports__;
16846})(__module3__, __module5__, __module2__);
16847
16848// handlebars.runtime.js
16849var __module1__ = (function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__) {
16850  "use strict";
16851  var __exports__;
16852  /*globals Handlebars: true */
16853  var base = __dependency1__;
16854
16855  // Each of these augment the Handlebars object. No need to setup here.
16856  // (This is done to easily share code between commonjs and browse envs)
16857  var SafeString = __dependency2__;
16858  var Exception = __dependency3__;
16859  var Utils = __dependency4__;
16860  var runtime = __dependency5__;
16861
16862  // For compatibility and usage outside of module systems, make the Handlebars object a namespace
16863  var create = function() {
16864    var hb = new base.HandlebarsEnvironment();
16865
16866    Utils.extend(hb, base);
16867    hb.SafeString = SafeString;
16868    hb.Exception = Exception;
16869    hb.Utils = Utils;
16870    hb.escapeExpression = Utils.escapeExpression;
16871
16872    hb.VM = runtime;
16873    hb.template = function(spec) {
16874      return runtime.template(spec, hb);
16875    };
16876
16877    return hb;
16878  };
16879
16880  var Handlebars = create();
16881  Handlebars.create = create;
16882
16883  Handlebars['default'] = Handlebars;
16884
16885  __exports__ = Handlebars;
16886  return __exports__;
16887})(__module2__, __module4__, __module5__, __module3__, __module6__);
16888
16889// handlebars/compiler/ast.js
16890var __module7__ = (function(__dependency1__) {
16891  "use strict";
16892  var __exports__;
16893  var Exception = __dependency1__;
16894
16895  function LocationInfo(locInfo) {
16896    locInfo = locInfo || {};
16897    this.firstLine   = locInfo.first_line;
16898    this.firstColumn = locInfo.first_column;
16899    this.lastColumn  = locInfo.last_column;
16900    this.lastLine    = locInfo.last_line;
16901  }
16902
16903  var AST = {
16904    ProgramNode: function(statements, strip, locInfo) {
16905      LocationInfo.call(this, locInfo);
16906      this.type = "program";
16907      this.statements = statements;
16908      this.strip = strip;
16909    },
16910
16911    MustacheNode: function(rawParams, hash, open, strip, locInfo) {
16912      LocationInfo.call(this, locInfo);
16913      this.type = "mustache";
16914      this.strip = strip;
16915
16916      // Open may be a string parsed from the parser or a passed boolean flag
16917      if (open != null && open.charAt) {
16918        // Must use charAt to support IE pre-10
16919        var escapeFlag = open.charAt(3) || open.charAt(2);
16920        this.escaped = escapeFlag !== '{' && escapeFlag !== '&';
16921      } else {
16922        this.escaped = !!open;
16923      }
16924
16925      if (rawParams instanceof AST.SexprNode) {
16926        this.sexpr = rawParams;
16927      } else {
16928        // Support old AST API
16929        this.sexpr = new AST.SexprNode(rawParams, hash);
16930      }
16931
16932      // Support old AST API that stored this info in MustacheNode
16933      this.id = this.sexpr.id;
16934      this.params = this.sexpr.params;
16935      this.hash = this.sexpr.hash;
16936      this.eligibleHelper = this.sexpr.eligibleHelper;
16937      this.isHelper = this.sexpr.isHelper;
16938    },
16939
16940    SexprNode: function(rawParams, hash, locInfo) {
16941      LocationInfo.call(this, locInfo);
16942
16943      this.type = "sexpr";
16944      this.hash = hash;
16945
16946      var id = this.id = rawParams[0];
16947      var params = this.params = rawParams.slice(1);
16948
16949      // a mustache is definitely a helper if:
16950      // * it is an eligible helper, and
16951      // * it has at least one parameter or hash segment
16952      this.isHelper = !!(params.length || hash);
16953
16954      // a mustache is an eligible helper if:
16955      // * its id is simple (a single part, not `this` or `..`)
16956      this.eligibleHelper = this.isHelper || id.isSimple;
16957
16958      // if a mustache is an eligible helper but not a definite
16959      // helper, it is ambiguous, and will be resolved in a later
16960      // pass or at runtime.
16961    },
16962
16963    PartialNode: function(partialName, context, hash, strip, locInfo) {
16964      LocationInfo.call(this, locInfo);
16965      this.type         = "partial";
16966      this.partialName  = partialName;
16967      this.context      = context;
16968      this.hash = hash;
16969      this.strip = strip;
16970
16971      this.strip.inlineStandalone = true;
16972    },
16973
16974    BlockNode: function(mustache, program, inverse, strip, locInfo) {
16975      LocationInfo.call(this, locInfo);
16976
16977      this.type = 'block';
16978      this.mustache = mustache;
16979      this.program  = program;
16980      this.inverse  = inverse;
16981      this.strip = strip;
16982
16983      if (inverse && !program) {
16984        this.isInverse = true;
16985      }
16986    },
16987
16988    RawBlockNode: function(mustache, content, close, locInfo) {
16989      LocationInfo.call(this, locInfo);
16990
16991      if (mustache.sexpr.id.original !== close) {
16992        throw new Exception(mustache.sexpr.id.original + " doesn't match " + close, this);
16993      }
16994
16995      content = new AST.ContentNode(content, locInfo);
16996
16997      this.type = 'block';
16998      this.mustache = mustache;
16999      this.program = new AST.ProgramNode([content], {}, locInfo);
17000    },
17001
17002    ContentNode: function(string, locInfo) {
17003      LocationInfo.call(this, locInfo);
17004      this.type = "content";
17005      this.original = this.string = string;
17006    },
17007
17008    HashNode: function(pairs, locInfo) {
17009      LocationInfo.call(this, locInfo);
17010      this.type = "hash";
17011      this.pairs = pairs;
17012    },
17013
17014    IdNode: function(parts, locInfo) {
17015      LocationInfo.call(this, locInfo);
17016      this.type = "ID";
17017
17018      var original = "",
17019          dig = [],
17020          depth = 0,
17021          depthString = '';
17022
17023      for(var i=0,l=parts.length; i<l; i++) {
17024        var part = parts[i].part;
17025        original += (parts[i].separator || '') + part;
17026
17027        if (part === ".." || part === "." || part === "this") {
17028          if (dig.length > 0) {
17029            throw new Exception("Invalid path: " + original, this);
17030          } else if (part === "..") {
17031            depth++;
17032            depthString += '../';
17033          } else {
17034            this.isScoped = true;
17035          }
17036        } else {
17037          dig.push(part);
17038        }
17039      }
17040
17041      this.original = original;
17042      this.parts    = dig;
17043      this.string   = dig.join('.');
17044      this.depth    = depth;
17045      this.idName   = depthString + this.string;
17046
17047      // an ID is simple if it only has one part, and that part is not
17048      // `..` or `this`.
17049      this.isSimple = parts.length === 1 && !this.isScoped && depth === 0;
17050
17051      this.stringModeValue = this.string;
17052    },
17053
17054    PartialNameNode: function(name, locInfo) {
17055      LocationInfo.call(this, locInfo);
17056      this.type = "PARTIAL_NAME";
17057      this.name = name.original;
17058    },
17059
17060    DataNode: function(id, locInfo) {
17061      LocationInfo.call(this, locInfo);
17062      this.type = "DATA";
17063      this.id = id;
17064      this.stringModeValue = id.stringModeValue;
17065      this.idName = '@' + id.stringModeValue;
17066    },
17067
17068    StringNode: function(string, locInfo) {
17069      LocationInfo.call(this, locInfo);
17070      this.type = "STRING";
17071      this.original =
17072        this.string =
17073        this.stringModeValue = string;
17074    },
17075
17076    NumberNode: function(number, locInfo) {
17077      LocationInfo.call(this, locInfo);
17078      this.type = "NUMBER";
17079      this.original =
17080        this.number = number;
17081      this.stringModeValue = Number(number);
17082    },
17083
17084    BooleanNode: function(bool, locInfo) {
17085      LocationInfo.call(this, locInfo);
17086      this.type = "BOOLEAN";
17087      this.bool = bool;
17088      this.stringModeValue = bool === "true";
17089    },
17090
17091    CommentNode: function(comment, locInfo) {
17092      LocationInfo.call(this, locInfo);
17093      this.type = "comment";
17094      this.comment = comment;
17095
17096      this.strip = {
17097        inlineStandalone: true
17098      };
17099    }
17100  };
17101
17102
17103  // Must be exported as an object rather than the root of the module as the jison lexer
17104  // most modify the object to operate properly.
17105  __exports__ = AST;
17106  return __exports__;
17107})(__module5__);
17108
17109// handlebars/compiler/parser.js
17110var __module9__ = (function() {
17111  "use strict";
17112  var __exports__;
17113  /* jshint ignore:start */
17114  /* istanbul ignore next */
17115  /* Jison generated parser */
17116  var handlebars = (function(){
17117  var parser = {trace: function trace() { },
17118  yy: {},
17119  symbols_: {"error":2,"root":3,"program":4,"EOF":5,"program_repetition0":6,"statement":7,"mustache":8,"block":9,"rawBlock":10,"partial":11,"CONTENT":12,"COMMENT":13,"openRawBlock":14,"END_RAW_BLOCK":15,"OPEN_RAW_BLOCK":16,"sexpr":17,"CLOSE_RAW_BLOCK":18,"openBlock":19,"block_option0":20,"closeBlock":21,"openInverse":22,"block_option1":23,"OPEN_BLOCK":24,"CLOSE":25,"OPEN_INVERSE":26,"inverseAndProgram":27,"INVERSE":28,"OPEN_ENDBLOCK":29,"path":30,"OPEN":31,"OPEN_UNESCAPED":32,"CLOSE_UNESCAPED":33,"OPEN_PARTIAL":34,"partialName":35,"param":36,"partial_option0":37,"partial_option1":38,"sexpr_repetition0":39,"sexpr_option0":40,"dataName":41,"STRING":42,"NUMBER":43,"BOOLEAN":44,"OPEN_SEXPR":45,"CLOSE_SEXPR":46,"hash":47,"hash_repetition_plus0":48,"hashSegment":49,"ID":50,"EQUALS":51,"DATA":52,"pathSegments":53,"SEP":54,"$accept":0,"$end":1},
17120  terminals_: {2:"error",5:"EOF",12:"CONTENT",13:"COMMENT",15:"END_RAW_BLOCK",16:"OPEN_RAW_BLOCK",18:"CLOSE_RAW_BLOCK",24:"OPEN_BLOCK",25:"CLOSE",26:"OPEN_INVERSE",28:"INVERSE",29:"OPEN_ENDBLOCK",31:"OPEN",32:"OPEN_UNESCAPED",33:"CLOSE_UNESCAPED",34:"OPEN_PARTIAL",42:"STRING",43:"NUMBER",44:"BOOLEAN",45:"OPEN_SEXPR",46:"CLOSE_SEXPR",50:"ID",51:"EQUALS",52:"DATA",54:"SEP"},
17121  productions_: [0,[3,2],[4,1],[7,1],[7,1],[7,1],[7,1],[7,1],[7,1],[10,3],[14,3],[9,4],[9,4],[19,3],[22,3],[27,2],[21,3],[8,3],[8,3],[11,5],[11,4],[17,3],[17,1],[36,1],[36,1],[36,1],[36,1],[36,1],[36,3],[47,1],[49,3],[35,1],[35,1],[35,1],[41,2],[30,1],[53,3],[53,1],[6,0],[6,2],[20,0],[20,1],[23,0],[23,1],[37,0],[37,1],[38,0],[38,1],[39,0],[39,2],[40,0],[40,1],[48,1],[48,2]],
17122  performAction: function anonymous(yytext,yyleng,yylineno,yy,yystate,$$,_$) {
17123
17124  var $0 = $$.length - 1;
17125  switch (yystate) {
17126  case 1: yy.prepareProgram($$[$0-1].statements, true); return $$[$0-1]; 
17127  break;
17128  case 2:this.$ = new yy.ProgramNode(yy.prepareProgram($$[$0]), {}, this._$);
17129  break;
17130  case 3:this.$ = $$[$0];
17131  break;
17132  case 4:this.$ = $$[$0];
17133  break;
17134  case 5:this.$ = $$[$0];
17135  break;
17136  case 6:this.$ = $$[$0];
17137  break;
17138  case 7:this.$ = new yy.ContentNode($$[$0], this._$);
17139  break;
17140  case 8:this.$ = new yy.CommentNode($$[$0], this._$);
17141  break;
17142  case 9:this.$ = new yy.RawBlockNode($$[$0-2], $$[$0-1], $$[$0], this._$);
17143  break;
17144  case 10:this.$ = new yy.MustacheNode($$[$0-1], null, '', '', this._$);
17145  break;
17146  case 11:this.$ = yy.prepareBlock($$[$0-3], $$[$0-2], $$[$0-1], $$[$0], false, this._$);
17147  break;
17148  case 12:this.$ = yy.prepareBlock($$[$0-3], $$[$0-2], $$[$0-1], $$[$0], true, this._$);
17149  break;
17150  case 13:this.$ = new yy.MustacheNode($$[$0-1], null, $$[$0-2], yy.stripFlags($$[$0-2], $$[$0]), this._$);
17151  break;
17152  case 14:this.$ = new yy.MustacheNode($$[$0-1], null, $$[$0-2], yy.stripFlags($$[$0-2], $$[$0]), this._$);
17153  break;
17154  case 15:this.$ = { strip: yy.stripFlags($$[$0-1], $$[$0-1]), program: $$[$0] };
17155  break;
17156  case 16:this.$ = {path: $$[$0-1], strip: yy.stripFlags($$[$0-2], $$[$0])};
17157  break;
17158  case 17:this.$ = new yy.MustacheNode($$[$0-1], null, $$[$0-2], yy.stripFlags($$[$0-2], $$[$0]), this._$);
17159  break;
17160  case 18:this.$ = new yy.MustacheNode($$[$0-1], null, $$[$0-2], yy.stripFlags($$[$0-2], $$[$0]), this._$);
17161  break;
17162  case 19:this.$ = new yy.PartialNode($$[$0-3], $$[$0-2], $$[$0-1], yy.stripFlags($$[$0-4], $$[$0]), this._$);
17163  break;
17164  case 20:this.$ = new yy.PartialNode($$[$0-2], undefined, $$[$0-1], yy.stripFlags($$[$0-3], $$[$0]), this._$);
17165  break;
17166  case 21:this.$ = new yy.SexprNode([$$[$0-2]].concat($$[$0-1]), $$[$0], this._$);
17167  break;
17168  case 22:this.$ = new yy.SexprNode([$$[$0]], null, this._$);
17169  break;
17170  case 23:this.$ = $$[$0];
17171  break;
17172  case 24:this.$ = new yy.StringNode($$[$0], this._$);
17173  break;
17174  case 25:this.$ = new yy.NumberNode($$[$0], this._$);
17175  break;
17176  case 26:this.$ = new yy.BooleanNode($$[$0], this._$);
17177  break;
17178  case 27:this.$ = $$[$0];
17179  break;
17180  case 28:$$[$0-1].isHelper = true; this.$ = $$[$0-1];
17181  break;
17182  case 29:this.$ = new yy.HashNode($$[$0], this._$);
17183  break;
17184  case 30:this.$ = [$$[$0-2], $$[$0]];
17185  break;
17186  case 31:this.$ = new yy.PartialNameNode($$[$0], this._$);
17187  break;
17188  case 32:this.$ = new yy.PartialNameNode(new yy.StringNode($$[$0], this._$), this._$);
17189  break;
17190  case 33:this.$ = new yy.PartialNameNode(new yy.NumberNode($$[$0], this._$));
17191  break;
17192  case 34:this.$ = new yy.DataNode($$[$0], this._$);
17193  break;
17194  case 35:this.$ = new yy.IdNode($$[$0], this._$);
17195  break;
17196  case 36: $$[$0-2].push({part: $$[$0], separator: $$[$0-1]}); this.$ = $$[$0-2]; 
17197  break;
17198  case 37:this.$ = [{part: $$[$0]}];
17199  break;
17200  case 38:this.$ = [];
17201  break;
17202  case 39:$$[$0-1].push($$[$0]);
17203  break;
17204  case 48:this.$ = [];
17205  break;
17206  case 49:$$[$0-1].push($$[$0]);
17207  break;
17208  case 52:this.$ = [$$[$0]];
17209  break;
17210  case 53:$$[$0-1].push($$[$0]);
17211  break;
17212  }
17213  },
17214  table: [{3:1,4:2,5:[2,38],6:3,12:[2,38],13:[2,38],16:[2,38],24:[2,38],26:[2,38],31:[2,38],32:[2,38],34:[2,38]},{1:[3]},{5:[1,4]}
vendor: 10,615 bytes, lines 17214-17335
17214,{5:[2,2],7:5,8:6,9:7,10:8,11:9,12:[1,10],13:[1,11],14:16,16:[1,20],19:14,22:15,24:[1,18],26:[1,19],28:[2,2],29:[2,2],31:[1,12],32:[1,13],34:[1,17]},{1:[2,1]},{5:[2,39],12:[2,39],13:[2,39],16:[2,39],24:[2,39],26:[2,39],28:[2,39],29:[2,39],31:[2,39],32:[2,39],34:[2,39]},{5:[2,3],12:[2,3],13:[2,3],16:[2,3],24:[2,3],26:[2,3],28:[2,3],29:[2,3],31:[2,3],32:[2,3],34:[2,3]},{5:[2,4],12:[2,4],13:[2,4],16:[2,4],24:[2,4],26:[2,4],28:[2,4],29:[2,4],31:[2,4],32:[2,4],34:[2,4]},{5:[2,5],12:[2,5],13:[2,5],16:[2,5],24:[2,5],26:[2,5],28:[2,5],29:[2,5],31:[2,5],32:[2,5],34:[2,5]},{5:[2,6],12:[2,6],13:[2,6],16:[2,6],24:[2,6],26:[2,6],28:[2,6],29:[2,6],31:[2,6],32:[2,6],34:[2,6]},{5:[2,7],12:[2,7],13:[2,7],16:[2,7],24:[2,7],26:[2,7],28:[2,7],29:[2,7],31:[2,7],32:[2,7],34:[2,7]},{5:[2,8],12:[2,8],13:[2,8],16:[2,8],24:[2,8],26:[2,8],28:[2,8],29:[2,8],31:[2,8],32:[2,8],34:[2,8]},{17:21,30:22,41:23,50:[1,26],52:[1,25],53:24},{17:27,30:22,41:23,50:[1,26],52:[1,25],53:24},{4:28,6:3,12:[2,38],13:[2,38],16:[2,38],24:[2,38],26:[2,38],28:[2,38],29:[2,38],31:[2,38],32:[2,38],34:[2,38]},{4:29,6:3,12:[2,38],13:[2,38],16:[2,38],24:[2,38],26:[2,38],28:[2,38],29:[2,38],31:[2,38],32:[2,38],34:[2,38]},{12:[1,30]},{30:32,35:31,42:[1,33],43:[1,34],50:[1,26],53:24},{17:35,30:22,41:23,50:[1,26],52:[1,25],53:24},{17:36,30:22,41:23,50:[1,26],52:[1,25],53:24},{17:37,30:22,41:23,50:[1,26],52:[1,25],53:24},{25:[1,38]},{18:[2,48],25:[2,48],33:[2,48],39:39,42:[2,48],43:[2,48],44:[2,48],45:[2,48],46:[2,48],50:[2,48],52:[2,48]},{18:[2,22],25:[2,22],33:[2,22],46:[2,22]},{18:[2,35],25:[2,35],33:[2,35],42:[2,35],43:[2,35],44:[2,35],45:[2,35],46:[2,35],50:[2,35],52:[2,35],54:[1,40]},{30:41,50:[1,26],53:24},{18:[2,37],25:[2,37],33:[2,37],42:[2,37],43:[2,37],44:[2,37],45:[2,37],46:[2,37],50:[2,37],52:[2,37],54:[2,37]},{33:[1,42]},{20:43,27:44,28:[1,45],29:[2,40]},{23:46,27:47,28:[1,45],29:[2,42]},{15:[1,48]},{25:[2,46],30:51,36:49,38:50,41:55,42:[1,52],43:[1,53],44:[1,54],45:[1,56],47:57,48:58,49:60,50:[1,59],52:[1,25],53:24},{25:[2,31],42:[2,31],43:[2,31],44:[2,31],45:[2,31],50:[2,31],52:[2,31]},{25:[2,32],42:[2,32],43:[2,32],44:[2,32],45:[2,32],50:[2,32],52:[2,32]},{25:[2,33],42:[2,33],43:[2,33],44:[2,33],45:[2,33],50:[2,33],52:[2,33]},{25:[1,61]},{25:[1,62]},{18:[1,63]},{5:[2,17],12:[2,17],13:[2,17],16:[2,17],24:[2,17],26:[2,17],28:[2,17],29:[2,17],31:[2,17],32:[2,17],34:[2,17]},{18:[2,50],25:[2,50],30:51,33:[2,50],36:65,40:64,41:55,42:[1,52],43:[1,53],44:[1,54],45:[1,56],46:[2,50],47:66,48:58,49:60,50:[1,59],52:[1,25],53:24},{50:[1,67]},{18:[2,34],25:[2,34],33:[2,34],42:[2,34],43:[2,34],44:[2,34],45:[2,34],46:[2,34],50:[2,34],52:[2,34]},{5:[2,18],12:[2,18],13:[2,18],16:[2,18],24:[2,18],26:[2,18],28:[2,18],29:[2,18],31:[2,18],32:[2,18],34:[2,18]},{21:68,29:[1,69]},{29:[2,41]},{4:70,6:3,12:[2,38],13:[2,38],16:[2,38],24:[2,38],26:[2,38],29:[2,38],31:[2,38],32:[2,38],34:[2,38]},{21:71,29:[1,69]},{29:[2,43]},{5:[2,9],12:[2,9],13:[2,9],16:[2,9],24:[2,9],26:[2,9],28:[2,9],29:[2,9],31:[2,9],32:[2,9],34:[2,9]},{25:[2,44],37:72,47:73,48:58,49:60,50:[1,74]},{25:[1,75]},{18:[2,23],25:[2,23],33:[2,23],42:[2,23],43:[2,23],44:[2,23],45:[2,23],46:[2,23],50:[2,23],52:[2,23]},{18:[2,24],25:[2,24],33:[2,24],42:[2,24],43:[2,24],44:[2,24],45:[2,24],46:[2,24],50:[2,24],52:[2,24]},{18:[2,25],25:[2,25],33:[2,25],42:[2,25],43:[2,25],44:[2,25],45:[2,25],46:[2,25],50:[2,25],52:[2,25]},{18:[2,26],25:[2,26],33:[2,26],42:[2,26],43:[2,26],44:[2,26],45:[2,26],46:[2,26],50:[2,26],52:[2,26]},{18:[2,27],25:[2,27],33:[2,27],42:[2,27],43:[2,27],44:[2,27],45:[2,27],46:[2,27],50:[2,27],52:[2,27]},{17:76,30:22,41:23,50:[1,26],52:[1,25],53:24},{25:[2,47]},{18:[2,29],25:[2,29],33:[2,29],46:[2,29],49:77,50:[1,74]},{18:[2,37],25:[2,37],33:[2,37],42:[2,37],43:[2,37],44:[2,37],45:[2,37],46:[2,37],50:[2,37],51:[1,78],52:[2,37],54:[2,37]},{18:[2,52],25:[2,52],33:[2,52],46:[2,52],50:[2,52]},{12:[2,13],13:[2,13],16:[2,13],24:[2,13],26:[2,13],28:[2,13],29:[2,13],31:[2,13],32:[2,13],34:[2,13]},{12:[2,14],13:[2,14],16:[2,14],24:[2,14],26:[2,14],28:[2,14],29:[2,14],31:[2,14],32:[2,14],34:[2,14]},{12:[2,10]},{18:[2,21],25:[2,21],33:[2,21],46:[2,21]},{18:[2,49],25:[2,49],33:[2,49],42:[2,49],43:[2,49],44:[2,49],45:[2,49],46:[2,49],50:[2,49],52:[2,49]},{18:[2,51],25:[2,51],33:[2,51],46:[2,51]},{18:[2,36],25:[2,36],33:[2,36],42:[2,36],43:[2,36],44:[2,36],45:[2,36],46:[2,36],50:[2,36],52:[2,36],54:[2,36]},{5:[2,11],12:[2,11],13:[2,11],16:[2,11],24:[2,11],26:[2,11],28:[2,11],29:[2,11],31:[2,11],32:[2,11],34:[2,11]},{30:79,50:[1,26],53:24},{29:[2,15]},{5:[2,12],12:[2,12],13:[2,12],16:[2,12],24:[2,12],26:[2,12],28:[2,12],29:[2,12],31:[2,12],32:[2,12],34:[2,12]},{25:[1,80]},{25:[2,45]},{51:[1,78]},{5:[2,20],12:[2,20],13:[2,20],16:[2,20],24:[2,20],26:[2,20],28:[2,20],29:[2,20],31:[2,20],32:[2,20],34:[2,20]},{46:[1,81]},{18:[2,53],25:[2,53],33:[2,53],46:[2,53],50:[2,53]},{30:51,36:82,41:55,42:[1,52],43:[1,53],44:[1,54],45:[1,56],50:[1,26],52:[1,25],53:24},{25:[1,83]},{5:[2,19],12:[2,19],13:[2,19],16:[2,19],24:[2,19],26:[2,19],28:[2,19],29:[2,19],31:[2,19],32:[2,19],34:[2,19]},{18:[2,28],25:[2,28],33:[2,28],42:[2,28],43:[2,28],44:[2,28],45:[2,28],46:[2,28],50:[2,28],52:[2,28]},{18:[2,30],25:[2,30],33:[2,30],46:[2,30],50:[2,30]},{5:[2,16],12:[2,16],13:[2,16],16:[2,16],24:[2,16],26:[2,16],28:[2,16],29:[2,16],31:[2,16],32:[2,16],34:[2,16]}],
17215  defaultActions: {4:[2,1],44:[2,41],47:[2,43],57:[2,47],63:[2,10],70:[2,15],73:[2,45]},
17216  parseError: function parseError(str, hash) {
17217      throw new Error(str);
17218  },
17219  parse: function parse(input) {
17220      var self = this, stack = [0], vstack = [null], lstack = [], table = this.table, yytext = "", yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1;
17221      this.lexer.setInput(input);
17222      this.lexer.yy = this.yy;
17223      this.yy.lexer = this.lexer;
17224      this.yy.parser = this;
17225      if (typeof this.lexer.yylloc == "undefined")
17226          this.lexer.yylloc = {};
17227      var yyloc = this.lexer.yylloc;
17228      lstack.push(yyloc);
17229      var ranges = this.lexer.options && this.lexer.options.ranges;
17230      if (typeof this.yy.parseError === "function")
17231          this.parseError = this.yy.parseError;
17232      function popStack(n) {
17233          stack.length = stack.length - 2 * n;
17234          vstack.length = vstack.length - n;
17235          lstack.length = lstack.length - n;
17236      }
17237      function lex() {
17238          var token;
17239          token = self.lexer.lex() || 1;
17240          if (typeof token !== "number") {
17241              token = self.symbols_[token] || token;
17242          }
17243          return token;
17244      }
17245      var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected;
17246      while (true) {
17247          state = stack[stack.length - 1];
17248          if (this.defaultActions[state]) {
17249              action = this.defaultActions[state];
17250          } else {
17251              if (symbol === null || typeof symbol == "undefined") {
17252                  symbol = lex();
17253              }
17254              action = table[state] && table[state][symbol];
17255          }
17256          if (typeof action === "undefined" || !action.length || !action[0]) {
17257              var errStr = "";
17258              if (!recovering) {
17259                  expected = [];
17260                  for (p in table[state])
17261                      if (this.terminals_[p] && p > 2) {
17262                          expected.push("'" + this.terminals_[p] + "'");
17263                      }
17264                  if (this.lexer.showPosition) {
17265                      errStr = "Parse error on line " + (yylineno + 1) + ":\n" + this.lexer.showPosition() + "\nExpecting " + expected.join(", ") + ", got '" + (this.terminals_[symbol] || symbol) + "'";
17266                  } else {
17267                      errStr = "Parse error on line " + (yylineno + 1) + ": Unexpected " + (symbol == 1?"end of input":"'" + (this.terminals_[symbol] || symbol) + "'");
17268                  }
17269                  this.parseError(errStr, {text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, loc: yyloc, expected: expected});
17270              }
17271          }
17272          if (action[0] instanceof Array && action.length > 1) {
17273              throw new Error("Parse Error: multiple actions possible at state: " + state + ", token: " + symbol);
17274          }
17275          switch (action[0]) {
17276          case 1:
17277              stack.push(symbol);
17278              vstack.push(this.lexer.yytext);
17279              lstack.push(this.lexer.yylloc);
17280              stack.push(action[1]);
17281              symbol = null;
17282              if (!preErrorSymbol) {
17283                  yyleng = this.lexer.yyleng;
17284                  yytext = this.lexer.yytext;
17285                  yylineno = this.lexer.yylineno;
17286                  yyloc = this.lexer.yylloc;
17287                  if (recovering > 0)
17288                      recovering--;
17289              } else {
17290                  symbol = preErrorSymbol;
17291                  preErrorSymbol = null;
17292              }
17293              break;
17294          case 2:
17295              len = this.productions_[action[1]][1];
17296              yyval.$ = vstack[vstack.length - len];
17297              yyval._$ = {first_line: lstack[lstack.length - (len || 1)].first_line, last_line: lstack[lstack.length - 1].last_line, first_column: lstack[lstack.length - (len || 1)].first_column, last_column: lstack[lstack.length - 1].last_column};
17298              if (ranges) {
17299                  yyval._$.range = [lstack[lstack.length - (len || 1)].range[0], lstack[lstack.length - 1].range[1]];
17300              }
17301              r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack);
17302              if (typeof r !== "undefined") {
17303                  return r;
17304              }
17305              if (len) {
17306                  stack = stack.slice(0, -1 * len * 2);
17307                  vstack = vstack.slice(0, -1 * len);
17308                  lstack = lstack.slice(0, -1 * len);
17309              }
17310              stack.push(this.productions_[action[1]][0]);
17311              vstack.push(yyval.$);
17312              lstack.push(yyval._$);
17313              newState = table[stack[stack.length - 2]][stack[stack.length - 1]];
17314              stack.push(newState);
17315              break;
17316          case 3:
17317              return true;
17318          }
17319      }
17320      return true;
17321  }
17322  };
17323  /* Jison generated lexer */
17324  var lexer = (function(){
17325  var lexer = ({EOF:1,
17326  parseError:function parseError(str, hash) {
17327          if (this.yy.parser) {
17328              this.yy.parser.parseError(str, hash);
17329          } else {
17330              throw new Error(str);
17331          }
17332      },
17333  setInput:function (input) {
17334          this._input = input;
17335          this._more = this._less = this.done = false;
vendor: 4,430 bytes, lines 17336-17453
17336          this.yylineno = this.yyleng = 0;
17337          this.yytext = this.matched = this.match = '';
17338          this.conditionStack = ['INITIAL'];
17339          this.yylloc = {first_line:1,first_column:0,last_line:1,last_column:0};
17340          if (this.options.ranges) this.yylloc.range = [0,0];
17341          this.offset = 0;
17342          return this;
17343      },
17344  input:function () {
17345          var ch = this._input[0];
17346          this.yytext += ch;
17347          this.yyleng++;
17348          this.offset++;
17349          this.match += ch;
17350          this.matched += ch;
17351          var lines = ch.match(/(?:\r\n?|\n).*/g);
17352          if (lines) {
17353              this.yylineno++;
17354              this.yylloc.last_line++;
17355          } else {
17356              this.yylloc.last_column++;
17357          }
17358          if (this.options.ranges) this.yylloc.range[1]++;
17359
17360          this._input = this._input.slice(1);
17361          return ch;
17362      },
17363  unput:function (ch) {
17364          var len = ch.length;
17365          var lines = ch.split(/(?:\r\n?|\n)/g);
17366
17367          this._input = ch + this._input;
17368          this.yytext = this.yytext.substr(0, this.yytext.length-len-1);
17369          //this.yyleng -= len;
17370          this.offset -= len;
17371          var oldLines = this.match.split(/(?:\r\n?|\n)/g);
17372          this.match = this.match.substr(0, this.match.length-1);
17373          this.matched = this.matched.substr(0, this.matched.length-1);
17374
17375          if (lines.length-1) this.yylineno -= lines.length-1;
17376          var r = this.yylloc.range;
17377
17378          this.yylloc = {first_line: this.yylloc.first_line,
17379            last_line: this.yylineno+1,
17380            first_column: this.yylloc.first_column,
17381            last_column: lines ?
17382                (lines.length === oldLines.length ? this.yylloc.first_column : 0) + oldLines[oldLines.length - lines.length].length - lines[0].length:
17383                this.yylloc.first_column - len
17384            };
17385
17386          if (this.options.ranges) {
17387              this.yylloc.range = [r[0], r[0] + this.yyleng - len];
17388          }
17389          return this;
17390      },
17391  more:function () {
17392          this._more = true;
17393          return this;
17394      },
17395  less:function (n) {
17396          this.unput(this.match.slice(n));
17397      },
17398  pastInput:function () {
17399          var past = this.matched.substr(0, this.matched.length - this.match.length);
17400          return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, "");
17401      },
17402  upcomingInput:function () {
17403          var next = this.match;
17404          if (next.length < 20) {
17405              next += this._input.substr(0, 20-next.length);
17406          }
17407          return (next.substr(0,20)+(next.length > 20 ? '...':'')).replace(/\n/g, "");
17408      },
17409  showPosition:function () {
17410          var pre = this.pastInput();
17411          var c = new Array(pre.length + 1).join("-");
17412          return pre + this.upcomingInput() + "\n" + c+"^";
17413      },
17414  next:function () {
17415          if (this.done) {
17416              return this.EOF;
17417          }
17418          if (!this._input) this.done = true;
17419
17420          var token,
17421              match,
17422              tempMatch,
17423              index,
17424              col,
17425              lines;
17426          if (!this._more) {
17427              this.yytext = '';
17428              this.match = '';
17429          }
17430          var rules = this._currentRules();
17431          for (var i=0;i < rules.length; i++) {
17432              tempMatch = this._input.match(this.rules[rules[i]]);
17433              if (tempMatch && (!match || tempMatch[0].length > match[0].length)) {
17434                  match = tempMatch;
17435                  index = i;
17436                  if (!this.options.flex) break;
17437              }
17438          }
17439          if (match) {
17440              lines = match[0].match(/(?:\r\n?|\n).*/g);
17441              if (lines) this.yylineno += lines.length;
17442              this.yylloc = {first_line: this.yylloc.last_line,
17443                             last_line: this.yylineno+1,
17444                             first_column: this.yylloc.last_column,
17445                             last_column: lines ? lines[lines.length-1].length-lines[lines.length-1].match(/\r?\n?/)[0].length : this.yylloc.last_column + match[0].length};
17446              this.yytext += match[0];
17447              this.match += match[0];
17448              this.matches = match;
17449              this.yyleng = this.yytext.length;
17450              if (this.options.ranges) {
17451                  this.yylloc.range = [this.offset, this.offset += this.yyleng];
17452              }
17453              this._more = false;
vendor: 5,475 bytes, lines 17454-17607
17454              this._input = this._input.slice(match[0].length);
17455              this.matched += match[0];
17456              token = this.performAction.call(this, this.yy, this, rules[index],this.conditionStack[this.conditionStack.length-1]);
17457              if (this.done && this._input) this.done = false;
17458              if (token) return token;
17459              else return;
17460          }
17461          if (this._input === "") {
17462              return this.EOF;
17463          } else {
17464              return this.parseError('Lexical error on line '+(this.yylineno+1)+'. Unrecognized text.\n'+this.showPosition(),
17465                      {text: "", token: null, line: this.yylineno});
17466          }
17467      },
17468  lex:function lex() {
17469          var r = this.next();
17470          if (typeof r !== 'undefined') {
17471              return r;
17472          } else {
17473              return this.lex();
17474          }
17475      },
17476  begin:function begin(condition) {
17477          this.conditionStack.push(condition);
17478      },
17479  popState:function popState() {
17480          return this.conditionStack.pop();
17481      },
17482  _currentRules:function _currentRules() {
17483          return this.conditions[this.conditionStack[this.conditionStack.length-1]].rules;
17484      },
17485  topState:function () {
17486          return this.conditionStack[this.conditionStack.length-2];
17487      },
17488  pushState:function begin(condition) {
17489          this.begin(condition);
17490      }});
17491  lexer.options = {};
17492  lexer.performAction = function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) {
17493
17494
17495  function strip(start, end) {
17496    return yy_.yytext = yy_.yytext.substr(start, yy_.yyleng-end);
17497  }
17498
17499
17500  var YYSTATE=YY_START
17501  switch($avoiding_name_collisions) {
17502  case 0:
17503                                     if(yy_.yytext.slice(-2) === "\\\\") {
17504                                       strip(0,1);
17505                                       this.begin("mu");
17506                                     } else if(yy_.yytext.slice(-1) === "\\") {
17507                                       strip(0,1);
17508                                       this.begin("emu");
17509                                     } else {
17510                                       this.begin("mu");
17511                                     }
17512                                     if(yy_.yytext) return 12;
17513                                   
17514  break;
17515  case 1:return 12;
17516  break;
17517  case 2:
17518                                     this.popState();
17519                                     return 12;
17520                                   
17521  break;
17522  case 3:
17523                                    yy_.yytext = yy_.yytext.substr(5, yy_.yyleng-9);
17524                                    this.popState();
17525                                    return 15;
17526                                   
17527  break;
17528  case 4: return 12; 
17529  break;
17530  case 5:strip(0,4); this.popState(); return 13;
17531  break;
17532  case 6:return 45;
17533  break;
17534  case 7:return 46;
17535  break;
17536  case 8: return 16; 
17537  break;
17538  case 9:
17539                                    this.popState();
17540                                    this.begin('raw');
17541                                    return 18;
17542                                   
17543  break;
17544  case 10:return 34;
17545  break;
17546  case 11:return 24;
17547  break;
17548  case 12:return 29;
17549  break;
17550  case 13:this.popState(); return 28;
17551  break;
17552  case 14:this.popState(); return 28;
17553  break;
17554  case 15:return 26;
17555  break;
17556  case 16:return 26;
17557  break;
17558  case 17:return 32;
17559  break;
17560  case 18:return 31;
17561  break;
17562  case 19:this.popState(); this.begin('com');
17563  break;
17564  case 20:strip(3,5); this.popState(); return 13;
17565  break;
17566  case 21:return 31;
17567  break;
17568  case 22:return 51;
17569  break;
17570  case 23:return 50;
17571  break;
17572  case 24:return 50;
17573  break;
17574  case 25:return 54;
17575  break;
17576  case 26:// ignore whitespace
17577  break;
17578  case 27:this.popState(); return 33;
17579  break;
17580  case 28:this.popState(); return 25;
17581  break;
17582  case 29:yy_.yytext = strip(1,2).replace(/\\"/g,'"'); return 42;
17583  break;
17584  case 30:yy_.yytext = strip(1,2).replace(/\\'/g,"'"); return 42;
17585  break;
17586  case 31:return 52;
17587  break;
17588  case 32:return 44;
17589  break;
17590  case 33:return 44;
17591  break;
17592  case 34:return 43;
17593  break;
17594  case 35:return 50;
17595  break;
17596  case 36:yy_.yytext = strip(1,2); return 50;
17597  break;
17598  case 37:return 'INVALID';
17599  break;
17600  case 38:return 5;
17601  break;
17602  }
17603  };
17604  lexer.rules = [/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|\\\{\{|\\\\\{\{|$)))/,/^(?:\{\{\{\{\/[^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=[=}\s\/.])\}\}\}\})/,/^(?:[^\x00]*?(?=(\{\{\{\{\/)))/,/^(?:[\s\S]*?--\}\})/,/^(?:\()/,/^(?:\))/,/^(?:\{\{\{\{)/,/^(?:\}\}\}\})/,/^(?:\{\{(~)?>)/,/^(?:\{\{(~)?#)/,/^(?:\{\{(~)?\/)/,/^(?:\{\{(~)?\^\s*(~)?\}\})/,/^(?:\{\{(~)?\s*else\s*(~)?\}\})/,/^(?:\{\{(~)?\^)/,/^(?:\{\{(~)?\s*else\b)/,/^(?:\{\{(~)?\{)/,/^(?:\{\{(~)?&)/,/^(?:\{\{!--)/,/^(?:\{\{![\s\S]*?\}\})/,/^(?:\{\{(~)?)/,/^(?:=)/,/^(?:\.\.)/,/^(?:\.(?=([=~}\s\/.)])))/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}(~)?\}\})/,/^(?:(~)?\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@)/,/^(?:true(?=([~}\s)])))/,/^(?:false(?=([~}\s)])))/,/^(?:-?[0-9]+(?:\.[0-9]+)?(?=([~}\s)])))/,/^(?:([^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=([=~}\s\/.)]))))/,/^(?:\[[^\]]*\])/,/^(?:.)/,/^(?:$)/];
17605  lexer.conditions = {"mu":{"rules":[6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38],"inclusive":false},"emu":{"rules":[2],"inclusive":false},"com":{"rules":[5],"inclusive":false},"raw":{"rules":[3,4],"inclusive":false},"INITIAL":{"rules":[0,1,38],"inclusive":true}};
17606  return lexer;})()
17607  parser.lexer = lexer;
17608  function Parser () { this.yy = {}; }Parser.prototype = parser;parser.Parser = Parser;
17609  return new Parser;
17610  })();__exports__ = handlebars;
17611  /* jshint ignore:end */
17612  return __exports__;
17613})();
17614
17615// handlebars/compiler/helpers.js
17616var __module10__ = (function(__dependency1__) {
17617  "use strict";
17618  var __exports__ = {};
17619  var Exception = __dependency1__;
17620
17621  function stripFlags(open, close) {
17622    return {
17623      left: open.charAt(2) === '~',
17624      right: close.charAt(close.length-3) === '~'
17625    };
17626  }
17627
17628  __exports__.stripFlags = stripFlags;
17629  function prepareBlock(mustache, program, inverseAndProgram, close, inverted, locInfo) {
17630    /*jshint -W040 */
17631    if (mustache.sexpr.id.original !== close.path.original) {
17632      throw new Exception(mustache.sexpr.id.original + ' doesn\'t match ' + close.path.original, mustache);
17633    }
17634
17635    var inverse = inverseAndProgram && inverseAndProgram.program;
17636
17637    var strip = {
17638      left: mustache.strip.left,
17639      right: close.strip.right,
17640
17641      // Determine the standalone candiacy. Basically flag our content as being possibly standalone
17642      // so our parent can determine if we actually are standalone
17643      openStandalone: isNextWhitespace(program.statements),
17644      closeStandalone: isPrevWhitespace((inverse || program).statements)
17645    };
17646
17647    if (mustache.strip.right) {
17648      omitRight(program.statements, null, true);
17649    }
17650
17651    if (inverse) {
17652      var inverseStrip = inverseAndProgram.strip;
17653
17654      if (inverseStrip.left) {
17655        omitLeft(program.statements, null, true);
17656      }
17657      if (inverseStrip.right) {
17658        omitRight(inverse.statements, null, true);
17659      }
17660      if (close.strip.left) {
17661        omitLeft(inverse.statements, null, true);
17662      }
17663
17664      // Find standalone else statments
17665      if (isPrevWhitespace(program.statements)
17666          && isNextWhitespace(inverse.statements)) {
17667
17668        omitLeft(program.statements);
17669        omitRight(inverse.statements);
17670      }
17671    } else {
17672      if (close.strip.left) {
17673        omitLeft(program.statements, null, true);
17674      }
17675    }
17676
17677    if (inverted) {
17678      return new this.BlockNode(mustache, inverse, program, strip, locInfo);
17679    } else {
17680      return new this.BlockNode(mustache, program, inverse, strip, locInfo);
17681    }
17682  }
17683
17684  __exports__.prepareBlock = prepareBlock;
17685  function prepareProgram(statements, isRoot) {
17686    for (var i = 0, l = statements.length; i < l; i++) {
17687      var current = statements[i],
17688          strip = current.strip;
17689
17690      if (!strip) {
17691        continue;
17692      }
17693
17694      var _isPrevWhitespace = isPrevWhitespace(statements, i, isRoot, current.type === 'partial'),
17695          _isNextWhitespace = isNextWhitespace(statements, i, isRoot),
17696
17697          openStandalone = strip.openStandalone && _isPrevWhitespace,
17698          closeStandalone = strip.closeStandalone && _isNextWhitespace,
17699          inlineStandalone = strip.inlineStandalone && _isPrevWhitespace && _isNextWhitespace;
17700
17701      if (strip.right) {
17702        omitRight(statements, i, true);
17703      }
17704      if (strip.left) {
17705        omitLeft(statements, i, true);
17706      }
17707
17708      if (inlineStandalone) {
17709        omitRight(statements, i);
17710
17711        if (omitLeft(statements, i)) {
17712          // If we are on a standalone node, save the indent info for partials
17713          if (current.type === 'partial') {
17714            current.indent = (/([ \t]+$)/).exec(statements[i-1].original) ? RegExp.$1 : '';
17715          }
17716        }
17717      }
17718      if (openStandalone) {
17719        omitRight((current.program || current.inverse).statements);
17720
17721        // Strip out the previous content node if it's whitespace only
17722        omitLeft(statements, i);
17723      }
17724      if (closeStandalone) {
17725        // Always strip the next node
17726        omitRight(statements, i);
17727
17728        omitLeft((current.inverse || current.program).statements);
17729      }
17730    }
17731
17732    return statements;
17733  }
17734
17735  __exports__.prepareProgram = prepareProgram;function isPrevWhitespace(statements, i, isRoot) {
17736    if (i === undefined) {
17737      i = statements.length;
17738    }
17739
17740    // Nodes that end with newlines are considered whitespace (but are special
17741    // cased for strip operations)
17742    var prev = statements[i-1],
17743        sibling = statements[i-2];
17744    if (!prev) {
17745      return isRoot;
17746    }
17747
17748    if (prev.type === 'content') {
17749      return (sibling || !isRoot ? (/\r?\n\s*?$/) : (/(^|\r?\n)\s*?$/)).test(prev.original);
17750    }
17751  }
17752  function isNextWhitespace(statements, i, isRoot) {
17753    if (i === undefined) {
17754      i = -1;
17755    }
17756
17757    var next = statements[i+1],
17758        sibling = statements[i+2];
17759    if (!next) {
17760      return isRoot;
17761    }
17762
17763    if (next.type === 'content') {
17764      return (sibling || !isRoot ? (/^\s*?\r?\n/) : (/^\s*?(\r?\n|$)/)).test(next.original);
17765    }
17766  }
17767
17768  // Marks the node to the right of the position as omitted.
17769  // I.e. {{foo}}' ' will mark the ' ' node as omitted.
17770  //
17771  // If i is undefined, then the first child will be marked as such.
17772  //
17773  // If mulitple is truthy then all whitespace will be stripped out until non-whitespace
17774  // content is met.
17775  function omitRight(statements, i, multiple) {
17776    var current = statements[i == null ? 0 : i + 1];
17777    if (!current || current.type !== 'content' || (!multiple && current.rightStripped)) {
17778      return;
17779    }
17780
17781    var original = current.string;
17782    current.string = current.string.replace(multiple ? (/^\s+/) : (/^[ \t]*\r?\n?/), '');
17783    current.rightStripped = current.string !== original;
17784  }
17785
17786  // Marks the node to the left of the position as omitted.
17787  // I.e. ' '{{foo}} will mark the ' ' node as omitted.
17788  //
17789  // If i is undefined then the last child will be marked as such.
17790  //
17791  // If mulitple is truthy then all whitespace will be stripped out until non-whitespace
17792  // content is met.
17793  function omitLeft(statements, i, multiple) {
17794    var current = statements[i == null ? statements.length - 1 : i - 1];
17795    if (!current || current.type !== 'content' || (!multiple && current.leftStripped)) {
17796      return;
17797    }
17798
17799    // We omit the last node if it's whitespace only and not preceeded by a non-content node.
17800    var original = current.string;
17801    current.string = current.string.replace(multiple ? (/\s+$/) : (/[ \t]+$/), '');
17802    current.leftStripped = current.string !== original;
17803    return current.leftStripped;
17804  }
17805  return __exports__;
17806})(__module5__);
17807
17808// handlebars/compiler/base.js
17809var __module8__ = (function(__dependency1__, __dependency2__, __dependency3__, __dependency4__) {
17810  "use strict";
17811  var __exports__ = {};
17812  var parser = __dependency1__;
17813  var AST = __dependency2__;
17814  var Helpers = __dependency3__;
17815  var extend = __dependency4__.extend;
17816
17817  __exports__.parser = parser;
17818
17819  var yy = {};
17820  extend(yy, Helpers, AST);
17821
17822  function parse(input) {
17823    // Just return if an already-compile AST was passed in.
17824    if (input.constructor === AST.ProgramNode) { return input; }
17825
17826    parser.yy = yy;
17827
17828    return parser.parse(input);
17829  }
17830
17831  __exports__.parse = parse;
17832  return __exports__;
17833})(__module9__, __module7__, __module10__, __module3__);
17834
17835// handlebars/compiler/compiler.js
17836var __module11__ = (function(__dependency1__, __dependency2__) {
17837  "use strict";
17838  var __exports__ = {};
17839  var Exception = __dependency1__;
17840  var isArray = __dependency2__.isArray;
17841
17842  var slice = [].slice;
17843
17844  function Compiler() {}
17845
17846  __exports__.Compiler = Compiler;// the foundHelper register will disambiguate helper lookup from finding a
17847  // function in a context. This is necessary for mustache compatibility, which
17848  // requires that context functions in blocks are evaluated by blockHelperMissing,
17849  // and then proceed as if the resulting value was provided to blockHelperMissing.
17850
17851  Compiler.prototype = {
17852    compiler: Compiler,
17853
17854    equals: function(other) {
17855      var len = this.opcodes.length;
17856      if (other.opcodes.length !== len) {
17857        return false;
17858      }
17859
17860      for (var i = 0; i < len; i++) {
17861        var opcode = this.opcodes[i],
17862            otherOpcode = other.opcodes[i];
17863        if (opcode.opcode !== otherOpcode.opcode || !argEquals(opcode.args, otherOpcode.args)) {
17864          return false;
17865        }
17866      }
17867
17868      // We know that length is the same between the two arrays because they are directly tied
17869      // to the opcode behavior above.
17870      len = this.children.length;
17871      for (i = 0; i < len; i++) {
17872        if (!this.children[i].equals(other.children[i])) {
17873          return false;
17874        }
17875      }
17876
17877      return true;
17878    },
17879
17880    guid: 0,
17881
17882    compile: function(program, options) {
17883      this.opcodes = [];
17884      this.children = [];
17885      this.depths = {list: []};
17886      this.options = options;
17887      this.stringParams = options.stringParams;
17888      this.trackIds = options.trackIds;
17889
17890      // These changes will propagate to the other compiler components
17891      var knownHelpers = this.options.knownHelpers;
17892      this.options.knownHelpers = {
17893        'helperMissing': true,
17894        'blockHelperMissing': true,
17895        'each': true,
17896        'if': true,
17897        'unless': true,
17898        'with': true,
17899        'log': true,
17900        'lookup': true
17901      };
17902      if (knownHelpers) {
17903        for (var name in knownHelpers) {
17904          this.options.knownHelpers[name] = knownHelpers[name];
17905        }
17906      }
17907
17908      return this.accept(program);
17909    },
17910
17911    accept: function(node) {
17912      return this[node.type](node);
17913    },
17914
17915    program: function(program) {
17916      var statements = program.statements;
17917
17918      for(var i=0, l=statements.length; i<l; i++) {
17919        this.accept(statements[i]);
17920      }
17921      this.isSimple = l === 1;
17922
17923      this.depths.list = this.depths.list.sort(function(a, b) {
17924        return a - b;
17925      });
17926
17927      return this;
17928    },
17929
17930    compileProgram: function(program) {
17931      var result = new this.compiler().compile(program, this.options);
17932      var guid = this.guid++, depth;
17933
17934      this.usePartial = this.usePartial || result.usePartial;
17935
17936      this.children[guid] = result;
17937
17938      for(var i=0, l=result.depths.list.length; i<l; i++) {
17939        depth = result.depths.list[i];
17940
17941        if(depth < 2) { continue; }
17942        else { this.addDepth(depth - 1); }
17943      }
17944
17945      return guid;
17946    },
17947
17948    block: function(block) {
17949      var mustache = block.mustache,
17950          program = block.program,
17951          inverse = block.inverse;
17952
17953      if (program) {
17954        program = this.compileProgram(program);
17955      }
17956
17957      if (inverse) {
17958        inverse = this.compileProgram(inverse);
17959      }
17960
17961      var sexpr = mustache.sexpr;
17962      var type = this.classifySexpr(sexpr);
17963
17964      if (type === "helper") {
17965        this.helperSexpr(sexpr, program, inverse);
17966      } else if (type === "simple") {
17967        this.simpleSexpr(sexpr);
17968
17969        // now that the simple mustache is resolved, we need to
17970        // evaluate it by executing `blockHelperMissing`
17971        this.opcode('pushProgram', program);
17972        this.opcode('pushProgram', inverse);
17973        this.opcode('emptyHash');
17974        this.opcode('blockValue', sexpr.id.original);
17975      } else {
17976        this.ambiguousSexpr(sexpr, program, inverse);
17977
17978        // now that the simple mustache is resolved, we need to
17979        // evaluate it by executing `blockHelperMissing`
17980        this.opcode('pushProgram', program);
17981        this.opcode('pushProgram', inverse);
17982        this.opcode('emptyHash');
17983        this.opcode('ambiguousBlockValue');
17984      }
17985
17986      this.opcode('append');
17987    },
17988
17989    hash: function(hash) {
17990      var pairs = hash.pairs, i, l;
17991
17992      this.opcode('pushHash');
17993
17994      for(i=0, l=pairs.length; i<l; i++) {
17995        this.pushParam(pairs[i][1]);
17996      }
17997      while(i--) {
17998        this.opcode('assignToHash', pairs[i][0]);
17999      }
18000      this.opcode('popHash');
18001    },
18002
18003    partial: function(partial) {
18004      var partialName = partial.partialName;
18005      this.usePartial = true;
18006
18007      if (partial.hash) {
18008        this.accept(partial.hash);
18009      } else {
18010        this.opcode('push', 'undefined');
18011      }
18012
18013      if (partial.context) {
18014        this.accept(partial.context);
18015      } else {
18016        this.opcode('getContext', 0);
18017        this.opcode('pushContext');
18018      }
18019
18020      this.opcode('invokePartial', partialName.name, partial.indent || '');
18021      this.opcode('append');
18022    },
18023
18024    content: function(content) {
18025      if (content.string) {
18026        this.opcode('appendContent', content.string);
18027      }
18028    },
18029
18030    mustache: function(mustache) {
18031      this.sexpr(mustache.sexpr);
18032
18033      if(mustache.escaped && !this.options.noEscape) {
18034        this.opcode('appendEscaped');
18035      } else {
18036        this.opcode('append');
18037      }
18038    },
18039
18040    ambiguousSexpr: function(sexpr, program, inverse) {
18041      var id = sexpr.id,
18042          name = id.parts[0],
18043          isBlock = program != null || inverse != null;
18044
18045      this.opcode('getContext', id.depth);
18046
18047      this.opcode('pushProgram', program);
18048      this.opcode('pushProgram', inverse);
18049
18050      this.ID(id);
18051
18052      this.opcode('invokeAmbiguous', name, isBlock);
18053    },
18054
18055    simpleSexpr: function(sexpr) {
18056      var id = sexpr.id;
18057
18058      if (id.type === 'DATA') {
18059        this.DATA(id);
18060      } else if (id.parts.length) {
18061        this.ID(id);
18062      } else {
18063        // Simplified ID for `this`
18064        this.addDepth(id.depth);
18065        this.opcode('getContext', id.depth);
18066        this.opcode('pushContext');
18067      }
18068
18069      this.opcode('resolvePossibleLambda');
18070    },
18071
18072    helperSexpr: function(sexpr, program, inverse) {
18073      var params = this.setupFullMustacheParams(sexpr, program, inverse),
18074          id = sexpr.id,
18075          name = id.parts[0];
18076
18077      if (this.options.knownHelpers[name]) {
18078        this.opcode('invokeKnownHelper', params.length, name);
18079      } else if (this.options.knownHelpersOnly) {
18080        throw new Exception("You specified knownHelpersOnly, but used the unknown helper " + name, sexpr);
18081      } else {
18082        id.falsy = true;
18083
18084        this.ID(id);
18085        this.opcode('invokeHelper', params.length, id.original, id.isSimple);
18086      }
18087    },
18088
18089    sexpr: function(sexpr) {
18090      var type = this.classifySexpr(sexpr);
18091
18092      if (type === "simple") {
18093        this.simpleSexpr(sexpr);
18094      } else if (type === "helper") {
18095        this.helperSexpr(sexpr);
18096      } else {
18097        this.ambiguousSexpr(sexpr);
18098      }
18099    },
18100
18101    ID: function(id) {
18102      this.addDepth(id.depth);
18103      this.opcode('getContext', id.depth);
18104
18105      var name = id.parts[0];
18106      if (!name) {
18107        // Context reference, i.e. `{{foo .}}` or `{{foo ..}}`
18108        this.opcode('pushContext');
18109      } else {
18110        this.opcode('lookupOnContext', id.parts, id.falsy, id.isScoped);
18111      }
18112    },
18113
18114    DATA: function(data) {
18115      this.options.data = true;
18116      this.opcode('lookupData', data.id.depth, data.id.parts);
18117    },
18118
18119    STRING: function(string) {
18120      this.opcode('pushString', string.string);
18121    },
18122
18123    NUMBER: function(number) {
18124      this.opcode('pushLiteral', number.number);
18125    },
18126
18127    BOOLEAN: function(bool) {
18128      this.opcode('pushLiteral', bool.bool);
18129    },
18130
18131    comment: function() {},
18132
18133    // HELPERS
18134    opcode: function(name) {
18135      this.opcodes.push({ opcode: name, args: slice.call(arguments, 1) });
18136    },
18137
18138    addDepth: function(depth) {
18139      if(depth === 0) { return; }
18140
18141      if(!this.depths[depth]) {
18142        this.depths[depth] = true;
18143        this.depths.list.push(depth);
18144      }
18145    },
18146
18147    classifySexpr: function(sexpr) {
18148      var isHelper   = sexpr.isHelper;
18149      var isEligible = sexpr.eligibleHelper;
18150      var options    = this.options;
18151
18152      // if ambiguous, we can possibly resolve the ambiguity now
18153      // An eligible helper is one that does not have a complex path, i.e. `this.foo`, `../foo` etc.
18154      if (isEligible && !isHelper) {
18155        var name = sexpr.id.parts[0];
18156
18157        if (options.knownHelpers[name]) {
18158          isHelper = true;
18159        } else if (options.knownHelpersOnly) {
18160          isEligible = false;
18161        }
18162      }
18163
18164      if (isHelper) { return "helper"; }
18165      else if (isEligible) { return "ambiguous"; }
18166      else { return "simple"; }
18167    },
18168
18169    pushParams: function(params) {
18170      for(var i=0, l=params.length; i<l; i++) {
18171        this.pushParam(params[i]);
18172      }
18173    },
18174
18175    pushParam: function(val) {
18176      if (this.stringParams) {
18177        if(val.depth) {
18178          this.addDepth(val.depth);
18179        }
18180        this.opcode('getContext', val.depth || 0);
18181        this.opcode('pushStringParam', val.stringModeValue, val.type);
18182
18183        if (val.type === 'sexpr') {
18184          // Subexpressions get evaluated and passed in
18185          // in string params mode.
18186          this.sexpr(val);
18187        }
18188      } else {
18189        if (this.trackIds) {
18190          this.opcode('pushId', val.type, val.idName || val.stringModeValue);
18191        }
18192        this.accept(val);
18193      }
18194    },
18195
18196    setupFullMustacheParams: function(sexpr, program, inverse) {
18197      var params = sexpr.params;
18198      this.pushParams(params);
18199
18200      this.opcode('pushProgram', program);
18201      this.opcode('pushProgram', inverse);
18202
18203      if (sexpr.hash) {
18204        this.hash(sexpr.hash);
18205      } else {
18206        this.opcode('emptyHash');
18207      }
18208
18209      return params;
18210    }
18211  };
18212
18213  function precompile(input, options, env) {
18214    if (input == null || (typeof input !== 'string' && input.constructor !== env.AST.ProgramNode)) {
18215      throw new Exception("You must pass a string or Handlebars AST to Handlebars.precompile. You passed " + input);
18216    }
18217
18218    options = options || {};
18219    if (!('data' in options)) {
18220      options.data = true;
18221    }
18222    if (options.compat) {
18223      options.useDepths = true;
18224    }
18225
18226    var ast = env.parse(input);
18227    var environment = new env.Compiler().compile(ast, options);
18228    return new env.JavaScriptCompiler().compile(environment, options);
18229  }
18230
18231  __exports__.precompile = precompile;function compile(input, options, env) {
18232    if (input == null || (typeof input !== 'string' && input.constructor !== env.AST.ProgramNode)) {
18233      throw new Exception("You must pass a string or Handlebars AST to Handlebars.compile. You passed " + input);
18234    }
18235
18236    options = options || {};
18237
18238    if (!('data' in options)) {
18239      options.data = true;
18240    }
18241    if (options.compat) {
18242      options.useDepths = true;
18243    }
18244
18245    var compiled;
18246
18247    function compileInput() {
18248      var ast = env.parse(input);
18249      var environment = new env.Compiler().compile(ast, options);
18250      var templateSpec = new env.JavaScriptCompiler().compile(environment, options, undefined, true);
18251      return env.template(templateSpec);
18252    }
18253
18254    // Template is only compiled on first use and cached after that point.
18255    var ret = function(context, options) {
18256      if (!compiled) {
18257        compiled = compileInput();
18258      }
18259      return compiled.call(this, context, options);
18260    };
18261    ret._setup = function(options) {
18262      if (!compiled) {
18263        compiled = compileInput();
18264      }
18265      return compiled._setup(options);
18266    };
18267    ret._child = function(i, data, depths) {
18268      if (!compiled) {
18269        compiled = compileInput();
18270      }
18271      return compiled._child(i, data, depths);
18272    };
18273    return ret;
18274  }
18275
18276  __exports__.compile = compile;function argEquals(a, b) {
18277    if (a === b) {
18278      return true;
18279    }
18280
18281    if (isArray(a) && isArray(b) && a.length === b.length) {
18282      for (var i = 0; i < a.length; i++) {
18283        if (!argEquals(a[i], b[i])) {
18284          return false;
18285        }
18286      }
18287      return true;
18288    }
18289  }
18290  return __exports__;
18291})(__module5__, __module3__);
18292
18293// handlebars/compiler/javascript-compiler.js
18294var __module12__ = (function(__dependency1__, __dependency2__) {
18295  "use strict";
18296  var __exports__;
18297  var COMPILER_REVISION = __dependency1__.COMPILER_REVISION;
18298  var REVISION_CHANGES = __dependency1__.REVISION_CHANGES;
18299  var Exception = __dependency2__;
18300
18301  function Literal(value) {
18302    this.value = value;
18303  }
18304
18305  function JavaScriptCompiler() {}
18306
18307  JavaScriptCompiler.prototype = {
18308    // PUBLIC API: You can override these methods in a subclass to provide
18309    // alternative compiled forms for name lookup and buffering semantics
18310    nameLookup: function(parent, name /* , type*/) {
18311      if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) {
18312        return parent + "." + name;
18313      } else {
18314        return parent + "['" + name + "']";
18315      }
18316    },
18317    depthedLookup: function(name) {
18318      this.aliases.lookup = 'this.lookup';
18319
18320      return 'lookup(depths, "' + name + '")';
18321    },
18322
18323    compilerInfo: function() {
18324      var revision = COMPILER_REVISION,
18325          versions = REVISION_CHANGES[revision];
18326      return [revision, versions];
18327    },
18328
18329    appendToBuffer: function(string) {
18330      if (this.environment.isSimple) {
18331        return "return " + string + ";";
18332      } else {
18333        return {
18334          appendToBuffer: true,
18335          content: string,
18336          toString: function() { return "buffer += " + string + ";"; }
18337        };
18338      }
18339    },
18340
18341    initializeBuffer: function() {
18342      return this.quotedString("");
18343    },
18344
18345    namespace: "Handlebars",
18346    // END PUBLIC API
18347
18348    compile: function(environment, options, context, asObject) {
18349      this.environment = environment;
18350      this.options = options;
18351      this.stringParams = this.options.stringParams;
18352      this.trackIds = this.options.trackIds;
18353      this.precompile = !asObject;
18354
18355      this.name = this.environment.name;
18356      this.isChild = !!context;
18357      this.context = context || {
18358        programs: [],
18359        environments: []
18360      };
18361
18362      this.preamble();
18363
18364      this.stackSlot = 0;
18365      this.stackVars = [];
18366      this.aliases = {};
18367      this.registers = { list: [] };
18368      this.hashes = [];
18369      this.compileStack = [];
18370      this.inlineStack = [];
18371
18372      this.compileChildren(environment, options);
18373
18374      this.useDepths = this.useDepths || environment.depths.list.length || this.options.compat;
18375
18376      var opcodes = environment.opcodes,
18377          opcode,
18378          i,
18379          l;
18380
18381      for (i = 0, l = opcodes.length; i < l; i++) {
18382        opcode = opcodes[i];
18383
18384        this[opcode.opcode].apply(this, opcode.args);
18385      }
18386
18387      // Flush any trailing content that might be pending.
18388      this.pushSource('');
18389
18390      /* istanbul ignore next */
18391      if (this.stackSlot || this.inlineStack.length || this.compileStack.length) {
18392        throw new Exception('Compile completed with content left on stack');
18393      }
18394
18395      var fn = this.createFunctionContext(asObject);
18396      if (!this.isChild) {
18397        var ret = {
18398          compiler: this.compilerInfo(),
18399          main: fn
18400        };
18401        var programs = this.context.programs;
18402        for (i = 0, l = programs.length; i < l; i++) {
18403          if (programs[i]) {
18404            ret[i] = programs[i];
18405          }
18406        }
18407
18408        if (this.environment.usePartial) {
18409          ret.usePartial = true;
18410        }
18411        if (this.options.data) {
18412          ret.useData = true;
18413        }
18414        if (this.useDepths) {
18415          ret.useDepths = true;
18416        }
18417        if (this.options.compat) {
18418          ret.compat = true;
18419        }
18420
18421        if (!asObject) {
18422          ret.compiler = JSON.stringify(ret.compiler);
18423          ret = this.objectLiteral(ret);
18424        }
18425
18426        return ret;
18427      } else {
18428        return fn;
18429      }
18430    },
18431
18432    preamble: function() {
18433      // track the last context pushed into place to allow skipping the
18434      // getContext opcode when it would be a noop
18435      this.lastContext = 0;
18436      this.source = [];
18437    },
18438
18439    createFunctionContext: function(asObject) {
18440      var varDeclarations = '';
18441
18442      var locals = this.stackVars.concat(this.registers.list);
18443      if(locals.length > 0) {
18444        varDeclarations += ", " + locals.join(", ");
18445      }
18446
18447      // Generate minimizer alias mappings
18448      for (var alias in this.aliases) {
18449        if (this.aliases.hasOwnProperty(alias)) {
18450          varDeclarations += ', ' + alias + '=' + this.aliases[alias];
18451        }
18452      }
18453
18454      var params = ["depth0", "helpers", "partials", "data"];
18455
18456      if (this.useDepths) {
18457        params.push('depths');
18458      }
18459
18460      // Perform a second pass over the output to merge content when possible
18461      var source = this.mergeSource(varDeclarations);
18462
18463      if (asObject) {
18464        params.push(source);
18465
18466        return Function.apply(this, params);
18467      } else {
18468        return 'function(' + params.join(',') + ') {\n  ' + source + '}';
18469      }
18470    },
18471    mergeSource: function(varDeclarations) {
18472      var source = '',
18473          buffer,
18474          appendOnly = !this.forceBuffer,
18475          appendFirst;
18476
18477      for (var i = 0, len = this.source.length; i < len; i++) {
18478        var line = this.source[i];
18479        if (line.appendToBuffer) {
18480          if (buffer) {
18481            buffer = buffer + '\n    + ' + line.content;
18482          } else {
18483            buffer = line.content;
18484          }
18485        } else {
18486          if (buffer) {
18487            if (!source) {
18488              appendFirst = true;
18489              source = buffer + ';\n  ';
18490            } else {
18491              source += 'buffer += ' + buffer + ';\n  ';
18492            }
18493            buffer = undefined;
18494          }
18495          source += line + '\n  ';
18496
18497          if (!this.environment.isSimple) {
18498            appendOnly = false;
18499          }
18500        }
18501      }
18502
18503      if (appendOnly) {
18504        if (buffer || !source) {
18505          source += 'return ' + (buffer || '""') + ';\n';
18506        }
18507      } else {
18508        varDeclarations += ", buffer = " + (appendFirst ? '' : this.initializeBuffer());
18509        if (buffer) {
18510          source += 'return buffer + ' + buffer + ';\n';
18511        } else {
18512          source += 'return buffer;\n';
18513        }
18514      }
18515
18516      if (varDeclarations) {
18517        source = 'var ' + varDeclarations.substring(2) + (appendFirst ? '' : ';\n  ') + source;
18518      }
18519
18520      return source;
18521    },
18522
18523    // [blockValue]
18524    //
18525    // On stack, before: hash, inverse, program, value
18526    // On stack, after: return value of blockHelperMissing
18527    //
18528    // The purpose of this opcode is to take a block of the form
18529    // `{{#this.foo}}...{{/this.foo}}`, resolve the value of `foo`, and
18530    // replace it on the stack with the result of properly
18531    // invoking blockHelperMissing.
18532    blockValue: function(name) {
18533      this.aliases.blockHelperMissing = 'helpers.blockHelperMissing';
18534
18535      var params = [this.contextName(0)];
18536      this.setupParams(name, 0, params);
18537
18538      var blockName = this.popStack();
18539      params.splice(1, 0, blockName);
18540
18541      this.push('blockHelperMissing.call(' + params.join(', ') + ')');
18542    },
18543
18544    // [ambiguousBlockValue]
18545    //
18546    // On stack, before: hash, inverse, program, value
18547    // Compiler value, before: lastHelper=value of last found helper, if any
18548    // On stack, after, if no lastHelper: same as [blockValue]
18549    // On stack, after, if lastHelper: value
18550    ambiguousBlockValue: function() {
18551      this.aliases.blockHelperMissing = 'helpers.blockHelperMissing';
18552
18553      // We're being a bit cheeky and reusing the options value from the prior exec
18554      var params = [this.contextName(0)];
18555      this.setupParams('', 0, params, true);
18556
18557      this.flushInline();
18558
18559      var current = this.topStack();
18560      params.splice(1, 0, current);
18561
18562      this.pushSource("if (!" + this.lastHelper + ") { " + current + " = blockHelperMissing.call(" + params.join(", ") + "); }");
18563    },
18564
18565    // [appendContent]
18566    //
18567    // On stack, before: ...
18568    // On stack, after: ...
18569    //
18570    // Appends the string value of `content` to the current buffer
18571    appendContent: function(content) {
18572      if (this.pendingContent) {
18573        content = this.pendingContent + content;
18574      }
18575
18576      this.pendingContent = content;
18577    },
18578
18579    // [append]
18580    //
18581    // On stack, before: value, ...
18582    // On stack, after: ...
18583    //
18584    // Coerces `value` to a String and appends it to the current buffer.
18585    //
18586    // If `value` is truthy, or 0, it is coerced into a string and appended
18587    // Otherwise, the empty string is appended
18588    append: function() {
18589      // Force anything that is inlined onto the stack so we don't have duplication
18590      // when we examine local
18591      this.flushInline();
18592      var local = this.popStack();
18593      this.pushSource('if (' + local + ' != null) { ' + this.appendToBuffer(local) + ' }');
18594      if (this.environment.isSimple) {
18595        this.pushSource("else { " + this.appendToBuffer("''") + " }");
18596      }
18597    },
18598
18599    // [appendEscaped]
18600    //
18601    // On stack, before: value, ...
18602    // On stack, after: ...
18603    //
18604    // Escape `value` and append it to the buffer
18605    appendEscaped: function() {
18606      this.aliases.escapeExpression = 'this.escapeExpression';
18607
18608      this.pushSource(this.appendToBuffer("escapeExpression(" + this.popStack() + ")"));
18609    },
18610
18611    // [getContext]
18612    //
18613    // On stack, before: ...
18614    // On stack, after: ...
18615    // Compiler value, after: lastContext=depth
18616    //
18617    // Set the value of the `lastContext` compiler value to the depth
18618    getContext: function(depth) {
18619      this.lastContext = depth;
18620    },
18621
18622    // [pushContext]
18623    //
18624    // On stack, before: ...
18625    // On stack, after: currentContext, ...
18626    //
18627    // Pushes the value of the current context onto the stack.
18628    pushContext: function() {
18629      this.pushStackLiteral(this.contextName(this.lastContext));
18630    },
18631
18632    // [lookupOnContext]
18633    //
18634    // On stack, before: ...
18635    // On stack, after: currentContext[name], ...
18636    //
18637    // Looks up the value of `name` on the current context and pushes
18638    // it onto the stack.
18639    lookupOnContext: function(parts, falsy, scoped) {
18640      /*jshint -W083 */
18641      var i = 0,
18642          len = parts.length;
18643
18644      if (!scoped && this.options.compat && !this.lastContext) {
18645        // The depthed query is expected to handle the undefined logic for the root level that
18646        // is implemented below, so we evaluate that directly in compat mode
18647        this.push(this.depthedLookup(parts[i++]));
18648      } else {
18649        this.pushContext();
18650      }
18651
18652      for (; i < len; i++) {
18653        this.replaceStack(function(current) {
18654          var lookup = this.nameLookup(current, parts[i], 'context');
18655          // We want to ensure that zero and false are handled properly if the context (falsy flag)
18656          // needs to have the special handling for these values.
18657          if (!falsy) {
18658            return ' != null ? ' + lookup + ' : ' + current;
18659          } else {
18660            // Otherwise we can use generic falsy handling
18661            return ' && ' + lookup;
18662          }
18663        });
18664      }
18665    },
18666
18667    // [lookupData]
18668    //
18669    // On stack, before: ...
18670    // On stack, after: data, ...
18671    //
18672    // Push the data lookup operator
18673    lookupData: function(depth, parts) {
18674      /*jshint -W083 */
18675      if (!depth) {
18676        this.pushStackLiteral('data');
18677      } else {
18678        this.pushStackLiteral('this.data(data, ' + depth + ')');
18679      }
18680
18681      var len = parts.length;
18682      for (var i = 0; i < len; i++) {
18683        this.replaceStack(function(current) {
18684          return ' && ' + this.nameLookup(current, parts[i], 'data');
18685        });
18686      }
18687    },
18688
18689    // [resolvePossibleLambda]
18690    //
18691    // On stack, before: value, ...
18692    // On stack, after: resolved value, ...
18693    //
18694    // If the `value` is a lambda, replace it on the stack by
18695    // the return value of the lambda
18696    resolvePossibleLambda: function() {
18697      this.aliases.lambda = 'this.lambda';
18698
18699      this.push('lambda(' + this.popStack() + ', ' + this.contextName(0) + ')');
18700    },
18701
18702    // [pushStringParam]
18703    //
18704    // On stack, before: ...
18705    // On stack, after: string, currentContext, ...
18706    //
18707    // This opcode is designed for use in string mode, which
18708    // provides the string value of a parameter along with its
18709    // depth rather than resolving it immediately.
18710    pushStringParam: function(string, type) {
18711      this.pushContext();
18712      this.pushString(type);
18713
18714      // If it's a subexpression, the string result
18715      // will be pushed after this opcode.
18716      if (type !== 'sexpr') {
18717        if (typeof string === 'string') {
18718          this.pushString(string);
18719        } else {
18720          this.pushStackLiteral(string);
18721        }
18722      }
18723    },
18724
18725    emptyHash: function() {
18726      this.pushStackLiteral('{}');
18727
18728      if (this.trackIds) {
18729        this.push('{}'); // hashIds
18730      }
18731      if (this.stringParams) {
18732        this.push('{}'); // hashContexts
18733        this.push('{}'); // hashTypes
18734      }
18735    },
18736    pushHash: function() {
18737      if (this.hash) {
18738        this.hashes.push(this.hash);
18739      }
18740      this.hash = {values: [], types: [], contexts: [], ids: []};
18741    },
18742    popHash: function() {
18743      var hash = this.hash;
18744      this.hash = this.hashes.pop();
18745
18746      if (this.trackIds) {
18747        this.push('{' + hash.ids.join(',') + '}');
18748      }
18749      if (this.stringParams) {
18750        this.push('{' + hash.contexts.join(',') + '}');
18751        this.push('{' + hash.types.join(',') + '}');
18752      }
18753
18754      this.push('{\n    ' + hash.values.join(',\n    ') + '\n  }');
18755    },
18756
18757    // [pushString]
18758    //
18759    // On stack, before: ...
18760    // On stack, after: quotedString(string), ...
18761    //
18762    // Push a quoted version of `string` onto the stack
18763    pushString: function(string) {
18764      this.pushStackLiteral(this.quotedString(string));
18765    },
18766
18767    // [push]
18768    //
18769    // On stack, before: ...
18770    // On stack, after: expr, ...
18771    //
18772    // Push an expression onto the stack
18773    push: function(expr) {
18774      this.inlineStack.push(expr);
18775      return expr;
18776    },
18777
18778    // [pushLiteral]
18779    //
18780    // On stack, before: ...
18781    // On stack, after: value, ...
18782    //
18783    // Pushes a value onto the stack. This operation prevents
18784    // the compiler from creating a temporary variable to hold
18785    // it.
18786    pushLiteral: function(value) {
18787      this.pushStackLiteral(value);
18788    },
18789
18790    // [pushProgram]
18791    //
18792    // On stack, before: ...
18793    // On stack, after: program(guid), ...
18794    //
18795    // Push a program expression onto the stack. This takes
18796    // a compile-time guid and converts it into a runtime-accessible
18797    // expression.
18798    pushProgram: function(guid) {
18799      if (guid != null) {
18800        this.pushStackLiteral(this.programExpression(guid));
18801      } else {
18802        this.pushStackLiteral(null);
18803      }
18804    },
18805
18806    // [invokeHelper]
18807    //
18808    // On stack, before: hash, inverse, program, params..., ...
18809    // On stack, after: result of helper invocation
18810    //
18811    // Pops off the helper's parameters, invokes the helper,
18812    // and pushes the helper's return value onto the stack.
18813    //
18814    // If the helper is not found, `helperMissing` is called.
18815    invokeHelper: function(paramSize, name, isSimple) {
18816      this.aliases.helperMissing = 'helpers.helperMissing';
18817
18818      var nonHelper = this.popStack();
18819      var helper = this.setupHelper(paramSize, name);
18820
18821      var lookup = (isSimple ? helper.name + ' || ' : '') + nonHelper + ' || helperMissing';
18822      this.push('((' + lookup + ').call(' + helper.callParams + '))');
18823    },
18824
18825    // [invokeKnownHelper]
18826    //
18827    // On stack, before: hash, inverse, program, params..., ...
18828    // On stack, after: result of helper invocation
18829    //
18830    // This operation is used when the helper is known to exist,
18831    // so a `helperMissing` fallback is not required.
18832    invokeKnownHelper: function(paramSize, name) {
18833      var helper = this.setupHelper(paramSize, name);
18834      this.push(helper.name + ".call(" + helper.callParams + ")");
18835    },
18836
18837    // [invokeAmbiguous]
18838    //
18839    // On stack, before: hash, inverse, program, params..., ...
18840    // On stack, after: result of disambiguation
18841    //
18842    // This operation is used when an expression like `{{foo}}`
18843    // is provided, but we don't know at compile-time whether it
18844    // is a helper or a path.
18845    //
18846    // This operation emits more code than the other options,
18847    // and can be avoided by passing the `knownHelpers` and
18848    // `knownHelpersOnly` flags at compile-time.
18849    invokeAmbiguous: function(name, helperCall) {
18850      this.aliases.functionType = '"function"';
18851      this.aliases.helperMissing = 'helpers.helperMissing';
18852      this.useRegister('helper');
18853
18854      var nonHelper = this.popStack();
18855
18856      this.emptyHash();
18857      var helper = this.setupHelper(0, name, helperCall);
18858
18859      var helperName = this.lastHelper = this.nameLookup('helpers', name, 'helper');
18860
18861      this.push(
18862        '((helper = (helper = ' + helperName + ' || ' + nonHelper + ') != null ? helper : helperMissing'
18863          + (helper.paramsInit ? '),(' + helper.paramsInit : '') + '),'
18864        + '(typeof helper === functionType ? helper.call(' + helper.callParams + ') 
18864: helper))');
18865    },
18866
18867    // [invokePartial]
18868    //
18869    // On stack, before: context, ...
18870    // On stack after: result of partial invocation
18871    //
18872    // This operation pops off a context, invokes a partial with that context,
18873    // and pushes the result of the invocation back.
18874    invokePartial: function(name, indent) {
18875      var params = [this.nameLookup('partials', name, 'partial'), "'" + indent + "'", "'" + name + "'", this.popStack(), this.popStack(), "helpers", "partials"];
18876
18877      if (this.options.data) {
18878        params.push("data");
18879      } else if (this.options.compat) {
18880        params.push('undefined');
18881      }
18882      if (this.options.compat) {
18883        params.push('depths');
18884      }
18885
18886      this.push("this.invokePartial(" + params.join(", ") + ")");
18887    },
18888
18889    // [assignToHash]
18890    //
18891    // On stack, before: value, ..., hash, ...
18892    // On stack, after: ..., hash, ...
18893    //
18894    // Pops a value off the stack and assigns it to the current hash
18895    assignToHash: function(key) {
18896      var value = this.popStack(),
18897          context,
18898          type,
18899          id;
18900
18901      if (this.trackIds) {
18902        id = this.popStack();
18903      }
18904      if (this.stringParams) {
18905        type = this.popStack();
18906        context = this.popStack();
18907      }
18908
18909      var hash = this.hash;
18910      if (context) {
18911        hash.contexts.push("'" + key + "': " + context);
18912      }
18913      if (type) {
18914        hash.types.push("'" + key + "': " + type);
18915      }
18916      if (id) {
18917        hash.ids.push("'" + key + "': " + id);
18918      }
18919      hash.values.push("'" + key + "': (" + value + ")");
18920    },
18921
18922    pushId: function(type, name) {
18923      if (type === 'ID' || type === 'DATA') {
18924        this.pushString(name);
18925      } else if (type === 'sexpr') {
18926        this.pushStackLiteral('true');
18927      } else {
18928        this.pushStackLiteral('null');
18929      }
18930    },
18931
18932    // HELPERS
18933
18934    compiler: JavaScriptCompiler,
18935
18936    compileChildren: function(environment, options) {
18937      var children = environment.children, child, compiler;
18938
18939      for(var i=0, l=children.length; i<l; i++) {
18940        child = children[i];
18941        compiler = new this.compiler();
18942
18943        var index = this.matchExistingProgram(child);
18944
18945        if (index == null) {
18946          this.context.programs.push('');     // Placeholder to prevent name conflicts for nested children
18947          index = this.context.programs.length;
18948          child.index = index;
18949          child.name = 'program' + index;
18950          this.context.programs[index] = compiler.compile(child, options, this.context, !this.precompile);
18951          this.context.environments[index] = child;
18952
18953          this.useDepths = this.useDepths || compiler.useDepths;
18954        } else {
18955          child.index = index;
18956          child.name = 'program' + index;
18957        }
18958      }
18959    },
18960    matchExistingProgram: function(child) {
18961      for (var i = 0, len = this.context.environments.length; i < len; i++) {
18962        var environment = this.context.environments[i];
18963        if (environment && environment.equals(child)) {
18964          return i;
18965        }
18966      }
18967    },
18968
18969    programExpression: function(guid) {
18970      var child = this.environment.children[guid],
18971          depths = child.depths.list,
18972          useDepths = this.useDepths,
18973          depth;
18974
18975      var programParams = [child.index, 'data'];
18976
18977      if (useDepths) {
18978        programParams.push('depths');
18979      }
18980
18981      return 'this.program(' + programParams.join(', ') + ')';
18982    },
18983
18984    useRegister: function(name) {
18985      if(!this.registers[name]) {
18986        this.registers[name] = true;
18987        this.registers.list.push(name);
18988      }
18989    },
18990
18991    pushStackLiteral: function(item) {
18992      return this.push(new Literal(item));
18993    },
18994
18995    pushSource: function(source) {
18996      if (this.pendingContent) {
18997        this.source.push(this.appendToBuffer(this.quotedString(this.pendingContent)));
18998        this.pendingContent = undefined;
18999      }
19000
19001      if (source) {
19002        this.source.push(source);
19003      }
19004    },
19005
19006    pushStack: function(item) {
19007      this.flushInline();
19008
19009      var stack = this.incrStack();
19010      this.pushSource(stack + " = " + item + ";");
19011      this.compileStack.push(stack);
19012      return stack;
19013    },
19014
19015    replaceStack: function(callback) {
19016      var prefix = '',
19017          inline = this.isInline(),
19018          stack,
19019          createdStack,
19020          usedLiteral;
19021
19022      /* istanbul ignore next */
19023      if (!this.isInline()) {
19024        throw new Exception('replaceStack on non-inline');
19025      }
19026
19027      // We want to merge the inline statement into the replacement statement via ','
19028      var top = this.popStack(true);
19029
19030      if (top instanceof Literal) {
19031        // Literals do not need to be inlined
19032        prefix = stack = top.value;
19033        usedLiteral = true;
19034      } else {
19035        // Get or create the current stack name for use by the inline
19036        createdStack = !this.stackSlot;
19037        var name = !createdStack ? this.topStackName() : this.incrStack();
19038
19039        prefix = '(' + this.push(name) + ' = ' + top + ')';
19040        stack = this.topStack();
19041      }
19042
19043      var item = callback.call(this, stack);
19044
19045      if (!usedLiteral) {
19046        this.popStack();
19047      }
19048      if (createdStack) {
19049        this.stackSlot--;
19050      }
19051      this.push('(' + prefix + item + ')');
19052    },
19053
19054    incrStack: function() {
19055      this.stackSlot++;
19056      if(this.stackSlot > this.stackVars.length) { this.stackVars.push("stack" + this.stackSlot); }
19057      return this.topStackName();
19058    },
19059    topStackName: function() {
19060      return "stack" + this.stackSlot;
19061    },
19062    flushInline: function() {
19063      var inlineStack = this.inlineStack;
19064      if (inlineStack.length) {
19065        this.inlineStack = [];
19066        for (var i = 0, len = inlineStack.length; i < len; i++) {
19067          var entry = inlineStack[i];
19068          if (entry instanceof Literal) {
19069            this.compileStack.push(entry);
19070          } else {
19071            this.pushStack(entry);
19072          }
19073        }
19074      }
19075    },
19076    isInline: function() {
19077      return this.inlineStack.length;
19078    },
19079
19080    popStack: function(wrapped) {
19081      var inline = this.isInline(),
19082          item = (inline ? this.inlineStack : this.compileStack).pop();
19083
19084      if (!wrapped && (item instanceof Literal)) {
19085        return item.value;
19086      } else {
19087        if (!inline) {
19088          /* istanbul ignore next */
19089          if (!this.stackSlot) {
19090            throw new Exception('Invalid stack pop');
19091          }
19092          this.stackSlot--;
19093        }
19094        return item;
19095      }
19096    },
19097
19098    topStack: function() {
19099      var stack = (this.isInline() ? this.inlineStack : this.compileStack),
19100          item = stack[stack.length - 1];
19101
19102      if (item instanceof Literal) {
19103        return item.value;
19104      } else {
19105        return item;
19106      }
19107    },
19108
19109    contextName: function(context) {
19110      if (this.useDepths && context) {
19111        return 'depths[' + context + ']';
19112      } else {
19113        return 'depth' + context;
19114      }
19115    },
19116
19117    quotedString: function(str) {
19118      return '"' + str
19119        .replace(/\\/g, '\\\\')
19120        .replace(/"/g, '\\"')
19121        .replace(/\n/g, '\\n')
19122        .replace(/\r/g, '\\r')
19123        .replace(/\u2028/g, '\\u2028')   // Per Ecma-262 7.3 + 7.8.4
19124        .replace(/\u2029/g, '\\u2029') + '"';
19125    },
19126
19127    objectLiteral: function(obj) {
19128      var pairs = [];
19129
19130      for (var key in obj) {
19131        if (obj.hasOwnProperty(key)) {
19132          pairs.push(this.quotedString(key) + ':' + obj[key]);
19133        }
19134      }
19135
19136      return '{' + pairs.join(',') + '}';
19137    },
19138
19139    setupHelper: function(paramSize, name, blockHelper) {
19140      var params = [],
19141          paramsInit = this.setupParams(name, paramSize, params, blockHelper);
19142      var foundHelper = this.nameLookup('helpers', name, 'helper');
19143
19144      return {
19145        params: params,
19146        paramsInit: paramsInit,
19147        name: foundHelper,
19148        callParams: [this.contextName(0)].concat(params).join(", ")
19149      };
19150    },
19151
19152    setupOptions: function(helper, paramSize, params) {
19153      var options = {}, contexts = [], types = [], ids = [], param, inverse, program;
19154
19155      options.name = this.quotedString(helper);
19156      options.hash = this.popStack();
19157
19158      if (this.trackIds) {
19159        options.hashIds = this.popStack();
19160      }
19161      if (this.stringParams) {
19162        options.hashTypes = this.popStack();
19163        options.hashContexts = this.popStack();
19164      }
19165
19166      inverse = this.popStack();
19167      program = this.popStack();
19168
19169      // Avoid setting fn and inverse if neither are set. This allows
19170      // helpers to do a check for `if (options.fn)`
19171      if (program || inverse) {
19172        if (!program) {
19173          program = 'this.noop';
19174        }
19175
19176        if (!inverse) {
19177          inverse = 'this.noop';
19178        }
19179
19180        options.fn = program;
19181        options.inverse = inverse;
19182      }
19183
19184      // The parameters go on to the stack in order (making sure that they are evaluated in order)
19185      // so we need to pop them off the stack in reverse order
19186      var i = paramSize;
19187      while (i--) {
19188        param = this.popStack();
19189        params[i] = param;
19190
19191        if (this.trackIds) {
19192          ids[i] = this.popStack();
19193        }
19194        if (this.stringParams) {
19195          types[i] = this.popStack();
19196          contexts[i] = this.popStack();
19197        }
19198      }
19199
19200      if (this.trackIds) {
19201        options.ids = "[" + ids.join(",") + "]";
19202      }
19203      if (this.stringParams) {
19204        options.types = "[" + types.join(",") + "]";
19205        options.contexts = "[" + contexts.join(",") + "]";
19206      }
19207
19208      if (this.options.data) {
19209        options.data = "data";
19210      }
19211
19212      return options;
19213    },
19214
19215    // the params and contexts arguments are passed in arrays
19216    // to fill in
19217    setupParams: function(helperName, paramSize, params, useRegister) {
19218      var options = this.objectLiteral(this.setupOptions(helperName, paramSize, params));
19219
19220      if (useRegister) {
19221        this.useRegister('options');
19222        params.push('options');
19223        return 'options=' + options;
19224      } else {
19225        params.push(options);
19226        return '';
19227      }
19228    }
19229  };
19230
19231  var reservedWords = (
19232    "break else new var" +
19233    " case finally return void" +
19234    " catch for switch while" +
19235    " continue function this with" +
19236    " default if throw" +
19237    " delete in try" +
19238    " do instanceof typeof" +
19239    " abstract enum int short" +
19240    " boolean export interface static" +
19241    " byte extends long super" +
19242    " char final native synchronized" +
19243    " class float package throws" +
19244    " const goto private transient" +
19245    " debugger implements protected volatile" +
19246    " double import public let yield"
19247  ).split(" ");
19248
19249  var compilerWords = JavaScriptCompiler.RESERVED_WORDS = {};
19250
19251  for(var i=0, l=reservedWords.length; i<l; i++) {
19252    compilerWords[reservedWords[i]] = true;
19253  }
19254
19255  JavaScriptCompiler.isValidJavaScriptVariableName = function(name) {
19256    return !JavaScriptCompiler.RESERVED_WORDS[name] && /^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(name);
19257  };
19258
19259  __exports__ = JavaScriptCompiler;
19260  return __exports__;
19261})(__module2__, __module5__);
19262
19263// handlebars.js
19264var __module0__ = (function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__) {
19265  "use strict";
19266  var __exports__;
19267  /*globals Handlebars: true */
19268  var Handlebars = __dependency1__;
19269
19270  // Compiler imports
19271  var AST = __dependency2__;
19272  var Parser = __dependency3__.parser;
19273  var parse = __dependency3__.parse;
19274  var Compiler = __dependency4__.Compiler;
19275  var compile = __dependency4__.compile;
19276  var precompile = __dependency4__.precompile;
19277  var JavaScriptCompiler = __dependency5__;
19278
19279  var _create = Handlebars.create;
19280  var create = function() {
19281    var hb = _create();
19282
19283    hb.compile = function(input, options) {
19284      return compile(input, options, hb);
19285    };
19286    hb.precompile = function (input, options) {
19287      return precompile(input, options, hb);
19288    };
19289
19290    hb.AST = AST;
19291    hb.Compiler = Compiler;
19292    hb.JavaScriptCompiler = JavaScriptCompiler;
19293    hb.Parser = Parser;
19294    hb.parse = parse;
19295
19296    return hb;
19297  };
19298
19299  Handlebars = create();
19300  Handlebars.create = create;
19301
19302  Handlebars['default'] = Handlebars;
19303
19304  __exports__ = Handlebars;
19305  return __exports__;
19306})(__module1__, __module7__, __module8__, __module11__, __module12__);
19307
19308  return __module0__;
19309}));
19310
19311/*!
19312 * typeahead.js 0.10.5
19313 * https://github.com/twitter/typeahead.js
19314 * Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT
19315 */
19316
19317(function($) {
19318    var _ = function() {
19319        "use strict";
19320        return {
19321            isMsie: function() {
19322                return /(msie|trident)/i.test(navigator.userAgent) ? navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2] : false;
vendor: 1,592 bytes, lines 19323-19367
19323            },
19324            isBlankString: function(str) {
19325                return !str || /^\s*$/.test(str);
19326            },
19327            escapeRegExChars: function(str) {
19328                return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
19329            },
19330            isString: function(obj) {
19331                return typeof obj === "string";
19332            },
19333            isNumber: function(obj) {
19334                return typeof obj === "number";
19335            },
19336            isArray: $.isArray,
19337            isFunction: $.isFunction,
19338            isObject: $.isPlainObject,
19339            isUndefined: function(obj) {
19340                return typeof obj === "undefined";
19341            },
19342            toStr: function toStr(s) {
19343                return _.isUndefined(s) || s === null ? "" : s + "";
19344            },
19345            bind: $.proxy,
19346            each: function(collection, cb) {
19347                $.each(collection, reverseArgs);
19348                function reverseArgs(index, value) {
19349                    return cb(value, index);
19350                }
19351            },
19352            map: $.map,
19353            filter: $.grep,
19354            every: function(obj, test) {
19355                var result = true;
19356                if (!obj) {
19357                    return result;
19358                }
19359                $.each(obj, function(key, val) {
19360                    if (!(result = test.call(null, val, key, obj))) {
19361                        return false;
19362                    }
19363                });
19364                return !!result;
19365            },
19366            some: function(obj, test) {
19367                var result = false;
19368                if (!obj) {
19369                    return result;
19370                }
19371                $.each(obj, function(key, val) {
19372                    if (result = test.call(null, val, key, obj)) {
19373                        return false;
19374                    }
19375                });
19376                return !!result;
19377            },
19378            mixin: $.extend,
19379            getUniqueId: function() {
19380                var counter = 0;
19381                return function() {
19382                    return counter++;
19383                };
19384            }(),
19385            templatify: function templatify(obj) {
19386                return $.isFunction(obj) ? obj : template;
19387                function template() {
19388                    return String(obj);
19389                }
19390            },
19391            defer: function(fn) {
19392                setTimeout(fn, 0);
19393            },
19394            debounce: function(func, wait, immediate) {
19395                var timeout, result;
19396                return function() {
19397                    var context = this, args = arguments, later, callNow;
19398                    later = function() {
19399                        timeout = null;
19400                        if (!immediate) {
19401                            result = func.apply(context, args);
19402                        }
19403                    };
19404                    callNow = immediate && !timeout;
19405                    clearTimeout(timeout);
19406                    timeout = setTimeout(later, wait);
19407                    if (callNow) {
19408                        result = func.apply(context, args);
19409                    }
19410                    return result;
19411                };
19412            },
19413            throttle: function(func, wait) {
19414                var context, args, timeout, result, previous, later;
19415                previous = 0;
19416                later = function() {
19417                    previous = new Date();
19418                    timeout = null;
19419                    result = func.apply(context, args);
19420                };
19421                return function() {
19422                    var now = new Date(), remaining = wait - (now - previous);
19423                    context = this;
19424                    args = arguments;
19425                    if (remaining <= 0) {
19426                        clearTimeout(timeout);
19427                        timeout = null;
19428                        previous = now;
19429                        result = func.apply(context, args);
19430                    } else if (!timeout) {
19431                        timeout = setTimeout(later, remaining);
19432                    }
19433                    return result;
19434                };
19435            },
19436            noop: function() {}
19437        };
19438    }();
19439    var html = function() {
19440        return {
19441            wrapper: '<span class="twitter-typeahead"></span>',
19442            dropdown: '<span class="tt-dropdown-menu"></span>',
19443            dataset: '<div class="tt-dataset-%CLASS%"></div>',
19444            suggestions: '<span class="tt-suggestions"></span>',
19445            suggestion: '<div class="tt-suggestion"></div>'
19446        };
19447    }();
19448    var css = function() {
19449        "use strict";
19450        var css = {
19451            wrapper: {
19452                position: "relative",
19453                display: "inline-block"
19454            },
19455            hint: {
19456                position: "absolute",
19457                top: "0",
19458                left: "0",
19459                borderColor: "transparent",
19460                boxShadow: "none",
19461                opacity: "1"
19462            },
19463            input: {
19464                position: "relative",
19465                verticalAlign: "top",
19466                backgroundColor: "transparent"
19467            },
19468            inputWithNoHint: {
19469                position: "relative",
19470                verticalAlign: "top"
19471            },
19472            dropdown: {
19473                position: "absolute",
19474                top: "100%",
19475                left: "0",
19476                zIndex: "100",
19477                display: "none"
19478            },
19479            suggestions: {
19480                display: "block"
19481            },
19482            suggestion: {
19483                whiteSpace: "nowrap",
19484                cursor: "pointer"
19485            },
19486            suggestionChild: {
19487                whiteSpace: "normal"
19488            },
19489            ltr: {
19490                left: "0",
19491                right: "auto"
19492            },
19493            rtl: {
19494                left: "auto",
19495                right: " 0"
19496            }
19497        };
19498        if (_.isMsie()) {
19499            _.mixin(css.input, {
19500                backgroundImage: "url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)"
19501            });
19502        }
19503        if (_.isMsie() && _.isMsie() <= 7) {
19504            _.mixin(css.input, {
19505                marginTop: "-1px"
19506            });
19507        }
19508        return css;
19509    }();
19510    var EventBus = function() {
19511        "use strict";
19512        var namespace = "typeahead:";
19513        function EventBus(o) {
19514            if (!o || !o.el) {
19515                $.error("EventBus initialized without el");
19516            }
19517            this.$el = $(o.el);
19518        }
19519        _.mixin(EventBus.prototype, {
19520            trigger: function(type) {
19521                var args = [].slice.call(arguments, 1);
19522                this.$el.trigger(namespace + type, args);
19523            }
19524        });
19525        return EventBus;
19526    }();
19527    var EventEmitter = function() {
19528        "use strict";
19529        var splitter = /\s+/, nextTick = getNextTick();
19530        return {
19531            onSync: onSync,
19532            onAsync: onAsync,
vendor: 6,364 bytes, lines 19533-19698
19533            off: off,
19534            trigger: trigger
19535        };
19536        function on(method, types, cb, context) {
19537            var type;
19538            if (!cb) {
19539                return this;
19540            }
19541            types = types.split(splitter);
19542            cb = context ? bindContext(cb, context) : cb;
19543            this._callbacks = this._callbacks || {};
19544            while (type = types.shift()) {
19545                this._callbacks[type] = this._callbacks[type] || {
19546                    sync: [],
19547                    async: []
19548                };
19549                this._callbacks[type][method].push(cb);
19550            }
19551            return this;
19552        }
19553        function onAsync(types, cb, context) {
19554            return on.call(this, "async", types, cb, context);
19555        }
19556        function onSync(types, cb, context) {
19557            return on.call(this, "sync", types, cb, context);
19558        }
19559        function off(types) {
19560            var type;
19561            if (!this._callbacks) {
19562                return this;
19563            }
19564            types = types.split(splitter);
19565            while (type = types.shift()) {
19566                delete this._callbacks[type];
19567            }
19568            return this;
19569        }
19570        function trigger(types) {
19571            var type, callbacks, args, syncFlush, asyncFlush;
19572            if (!this._callbacks) {
19573                return this;
19574            }
19575            types = types.split(splitter);
19576            args = [].slice.call(arguments, 1);
19577            while ((type = types.shift()) && (callbacks = this._callbacks[type])) {
19578                syncFlush = getFlush(callbacks.sync, this, [ type ].concat(args));
19579                asyncFlush = getFlush(callbacks.async, this, [ type ].concat(args));
19580                syncFlush() && nextTick(asyncFlush);
19581            }
19582            return this;
19583        }
19584        function getFlush(callbacks, context, args) {
19585            return flush;
19586            function flush() {
19587                var cancelled;
19588                for (var i = 0, len = callbacks.length; !cancelled && i < len; i += 1) {
19589                    cancelled = callbacks[i].apply(context, args) === false;
19590                }
19591                return !cancelled;
19592            }
19593        }
19594        function getNextTick() {
19595            var nextTickFn;
19596            if (window.setImmediate) {
19597                nextTickFn = function nextTickSetImmediate(fn) {
19598                    setImmediate(function() {
19599                        fn();
19600                    });
19601                };
19602            } else {
19603                nextTickFn = function nextTickSetTimeout(fn) {
19604                    setTimeout(function() {
19605                        fn();
19606                    }, 0);
19607                };
19608            }
19609            return nextTickFn;
19610        }
19611        function bindContext(fn, context) {
19612            return fn.bind ? fn.bind(context) : function() {
19613                fn.apply(context, [].slice.call(arguments, 0));
19614            };
19615        }
19616    }();
19617    var highlight = function(doc) {
19618        "use strict";
19619        var defaults = {
19620            node: null,
19621            pattern: null,
19622            tagName: "strong",
19623            className: null,
19624            wordsOnly: false,
19625            caseSensitive: false
19626        };
19627        return function hightlight(o) {
19628            var regex;
19629            o = _.mixin({}, defaults, o);
19630            if (!o.node || !o.pattern) {
19631                return;
19632            }
19633            o.pattern = _.isArray(o.pattern) ? o.pattern : [ o.pattern ];
19634            regex = getRegex(o.pattern, o.caseSensitive, o.wordsOnly);
19635            traverse(o.node, hightlightTextNode);
19636            function hightlightTextNode(textNode) {
19637                var match, patternNode, wrapperNode;
19638                if (match = regex.exec(textNode.data)) {
19639                    wrapperNode = doc.createElement(o.tagName);
19640                    o.className && (wrapperNode.className = o.className);
19641                    patternNode = textNode.splitText(match.index);
19642                    patternNode.splitText(match[0].length);
19643                    wrapperNode.appendChild(patternNode.cloneNode(true));
19644                    textNode.parentNode.replaceChild(wrapperNode, patternNode);
19645                }
19646                return !!match;
19647            }
19648            function traverse(el, hightlightTextNode) {
19649                var childNode, TEXT_NODE_TYPE = 3;
19650                for (var i = 0; i < el.childNodes.length; i++) {
19651                    childNode = el.childNodes[i];
19652                    if (childNode.nodeType === TEXT_NODE_TYPE) {
19653                        i += hightlightTextNode(childNode) ? 1 : 0;
19654                    } else {
19655                        traverse(childNode, hightlightTextNode);
19656                    }
19657                }
19658            }
19659        };
19660        function getRegex(patterns, caseSensitive, wordsOnly) {
19661            var escapedPatterns = [], regexStr;
19662            for (var i = 0, len = patterns.length; i < len; i++) {
19663                escapedPatterns.push(_.escapeRegExChars(patterns[i]));
19664            }
19665            regexStr = wordsOnly ? "\\b(" + escapedPatterns.join("|") + ")\\b" : "(" + escapedPatterns.join("|") + ")";
19666            return caseSensitive ? new RegExp(regexStr) : new RegExp(regexStr, "i");
19667        }
19668    }(window.document);
19669    var Input = function() {
19670        "use strict";
19671        var specialKeyCodeMap;
19672        specialKeyCodeMap = {
19673            9: "tab",
19674            27: "esc",
19675            37: "left",
19676            39: "right",
19677            13: "enter",
19678            38: "up",
19679            40: "down"
19680        };
19681        function Input(o) {
19682            var that = this, onBlur, onFocus, onKeydown, onInput;
19683            o = o || {};
19684            if (!o.input) {
19685                $.error("input is missing");
19686            }
19687            onBlur = _.bind(this._onBlur, this);
19688            onFocus = _.bind(this._onFocus, this);
19689            onKeydown = _.bind(this._onKeydown, this);
19690            onInput = _.bind(this._onInput, this);
19691            this.$hint = $(o.hint);
19692            this.$input = $(o.input).on("blur.tt", onBlur).on("focus.tt", onFocus).on("keydown.tt", onKeydown);
19693            if (this.$hint.length === 0) {
19694                this.setHint = this.getHint = this.clearHint = this.clearHintIfInvalid = _.noop;
19695            }
19696            if (!_.isMsie()) {
19697                this.$input.on("input.tt", onInput);
19698            } else {
vendor: 1,932 bytes, lines 19699-19745
19699                this.$input.on("keydown.tt keypress.tt cut.tt paste.tt", function($e) {
19700                    if (specialKeyCodeMap[$e.which || $e.keyCode]) {
19701                        return;
19702                    }
19703                    _.defer(_.bind(that._onInput, that, $e));
19704                });
19705            }
19706            this.query = this.$input.val();
19707            this.$overflowHelper = buildOverflowHelper(this.$input);
19708        }
19709        Input.normalizeQuery = function(str) {
19710            return (str || "").replace(/^\s*/g, "").replace(/\s{2,}/g, " ");
19711        };
19712        _.mixin(Input.prototype, EventEmitter, {
19713            _onBlur: function onBlur() {
19714                this.resetInputValue();
19715                this.trigger("blurred");
19716            },
19717            _onFocus: function onFocus() {
19718                this.trigger("focused");
19719            },
19720            _onKeydown: function onKeydown($e) {
19721                var keyName = specialKeyCodeMap[$e.which || $e.keyCode];
19722                this._managePreventDefault(keyName, $e);
19723                if (keyName && this._shouldTrigger(keyName, $e)) {
19724                    this.trigger(keyName + "Keyed", $e);
19725                }
19726            },
19727            _onInput: function onInput() {
19728                this._checkInputValue();
19729            },
19730            _managePreventDefault: function managePreventDefault(keyName, $e) {
19731                var preventDefault, hintValue, inputValue;
19732                switch (keyName) {
19733                  case "tab":
19734                    hintValue = this.getHint();
19735                    inputValue = this.getInputValue();
19736                    preventDefault = hintValue && hintValue !== inputValue && !withModifier($e);
19737                    break;
19738
19739                  case "up":
19740                  case "down":
19741                    preventDefault = !withModifier($e);
19742                    break;
19743
19744                  default:
19745                    preventDefault = false;
19746                }
19747                preventDefault && $e.preventDefault();
19748            },
19749            _shouldTrigger: function shouldTrigger(keyName, $e) {
19750                var trigger;
19751                switch (keyName) {
19752                  case "tab":
19753                    trigger = !withModifier($e);
19754                    break;
19755
19756                  default:
19757                    trigger = true;
19758                }
19759                return trigger;
19760            },
19761            _checkInputValue: function checkInputValue() {
19762                var inputValue, areEquivalent, hasDifferentWhitespace;
19763                inputValue = this.getInputValue();
19764                areEquivalent = areQueriesEquivalent(inputValue, this.query);
19765                hasDifferentWhitespace = areEquivalent ? this.query.length !== inputValue.length : false;
19766                this.query = inputValue;
19767                if (!areEquivalent) {
19768                    this.trigger("queryChanged", this.query);
19769                } else if (hasDifferentWhitespace) {
19770                    this.trigger("whitespaceChanged", this.query);
19771                }
19772            },
19773            focus: function focus() {
19774                this.$input.focus();
19775            },
19776            blur: function blur() {
19777                this.$input.blur();
19778            },
19779            getQuery: function getQuery() {
19780                return this.query;
19781            },
19782            setQuery: function setQuery(query) {
19783                this.query = query;
19784            },
19785            getInputValue: function getInputValue() {
19786                return this.$input.val();
19787            },
19788            setInputValue: function setInputValue(value, silent) {
19789                this.$input.val(value);
19790                silent ? this.clearHint() : this._checkInputValue();
19791            },
19792            resetInputValue: function resetInputValue() {
19793                this.setInputValue(this.query, true);
19794            },
19795            getHint: function getHint() {
19796                return this.$hint.val();
19797            },
19798            setHint: function setHint(value) {
19799                this.$hint.val(value);
19800            },
19801            clearHint: function clearHint() {
19802                this.setHint("");
19803            },
19804            clearHintIfInvalid: function clearHintIfInvalid() {
19805                var val, hint, valIsPrefixOfHint, isValid;
19806                val = this.getInputValue();
19807                hint = this.getHint();
19808                valIsPrefixOfHint = val !== hint && hint.indexOf(val) === 0;
19809                isValid = val !== "" && valIsPrefixOfHint && !this.hasOverflow();
19810                !isValid && this.clearHint();
19811            },
19812            getLanguageDirection: function getLanguageDirection() {
19813                return (this.$input.css("direction") || "ltr").toLowerCase();
19814            },
19815            hasOverflow: function hasOverflow() {
19816                var constraint = this.$input.width() - 2;
19817                this.$overflowHelper.text(this.getInputValue());
19818                return this.$overflowHelper.width() >= constraint;
19819            },
19820            isCursorAtEnd: function() {
19821                var valueLength, selectionStart, range;
19822                valueLength = this.$input.val().length;
19823                selectionStart = this.$input[0].selectionStart;
19824                if (_.isNumber(selectionStart)) {
19825                    return selectionStart === valueLength;
19826                } else if (document.selection) {
19827                    range = document.selection.createRange();
19828                    range.moveStart("character", -valueLength);
19829                    return valueLength === range.text.length;
19830                }
19831                return true;
19832            },
19833            destroy: function destroy() {
19834                this.$hint.off(".tt");
19835                this.$input.off(".tt");
19836                this.$hint = this.$input = this.$overflowHelper = null;
19837            }
19838        });
19839        return Input;
19840        function buildOverflowHelper($input) {
19841            return $('<pre aria-hidden="true"></pre>').css({
19842                position: "absolute",
19843                visibility: "hidden",
19844                whiteSpace: "pre",
19845                fontFamily: $input.css("font-family"),
19846                fontSize: $input.css("font-size"),
19847                fontStyle: $input.css("font-style"),
19848                fontVariant: $input.css("font-variant"),
19849                fontWeight: $input.css("font-weight"),
19850                wordSpacing: $input.css("word-spacing"),
19851                letterSpacing: $input.css("letter-spacing"),
19852                textIndent: $input.css("text-indent"),
19853                textRendering: $input.css("text-rendering"),
19854                textTransform: $input.css("text-transform")
19855            }).insertAfter($input);
19856        }
19857        function areQueriesEquivalent(a, b) {
19858            return Input.normalizeQuery(a) === Input.normalizeQuery(b);
19859        }
19860        function withModifier($e) {
19861            return $e.altKey || $e.ctrlKey || $e.metaKey || $e.shiftKey;
19862        }
19863    }();
19864    var Dataset = function() {
19865        "use strict";
19866        var datasetKey = "ttDataset", valueKey = "ttValue", datumKey = "ttDatum";
19867        function Dataset(o) {
19868            o = o || {};
19869            o.templates = o.templates || {};
19870            if (!o.source) {
19871                $.error("missing source");
19872            }
19873            if (o.name && !isValidName(o.name)) {
19874                $.error("invalid dataset name: " + o.name);
19875            }
19876            this.query = null;
19877            this.highlight = !!o.highlight;
19878            this.name = o.name || _.getUniqueId();
19879            this.source = o.source;
19880            this.displayFn = getDisplayFn(o.display || o.displayKey);
19881            this.templates = getTemplates(o.templates, this.displayFn);
19882            this.$el = $(html.dataset.replace("%CLASS%", this.name));
19883        }
19884        Dataset.extractDatasetName = function extractDatasetName(el) {
19885            return $(el).data(datasetKey);
19886        };
19887        Dataset.extractValue = function extractDatum(el) {
19888            return $(el).data(valueKey);
19889        };
19890        Dataset.extractDatum = function extractDatum(el) {
19891            return $(el).data(datumKey);
19892        };
19893        _.mixin(Dataset.prototype, EventEmitter, {
19894            _render: function render(query, suggestions) {
19895                if (!this.$el) {
19896                    return;
19897                }
19898                var that = this, hasSuggestions;
19899                this.$el.empty();
19900                hasSuggestions = suggestions && suggestions.length;
19901                if (!hasSuggestions && this.templates.empty) {
19902                    this.$el.html(getEmptyHtml()).prepend(that.templates.header ? getHeaderHtml() : null).append(that.templates.footer ? getFooterHtml() : null);
19903                } else if (hasSuggestions) {
19904                    this.$el.html(getSuggestionsHtml()).prepend(that.templates.header ? getHeaderHtml() : null).append(that.templates.footer ? getFooterHtml() : null);
19905                }
19906                this.trigger("rendered");
19907                function getEmptyHtml() {
19908                    return that.templates.empty({
19909                        query: query,
19910                        isEmpty: true
19911                    });
19912                }
19913                function getSuggestionsHtml() {
19914                    var $suggestions, nodes;
19915                    $suggestions = $(html.suggestions).css(css.suggestions);
19916                    nodes = _.map(suggestions, getSuggestionNode);
19917                    $suggestions.append.apply($suggestions, nodes);
19918                    that.highlight && highlight({
19919                        className: "tt-highlight",
19920                        node: $suggestions[0],
19921                        pattern: query
19922                    });
19923                    return $suggestions;
19924                    function getSuggestionNode(suggestion) {
19925                        var $el;
19926                        $el = $(html.suggestion).append(that.templates.suggestion(suggestion)).data(datasetKey, that.name).data(valueKey, that.displayFn(suggestion)).data(datumKey, suggestion);
19927                        $el.children().each(function() {
19928                            $(this).css(css.suggestionChild);
19929                        });
19930                        return $el;
19931                    }
19932                }
19933                function getHeaderHtml() {
19934                    return that.templates.header({
19935                        query: query,
19936                        isEmpty: !hasSuggestions
19937                    });
19938                }
19939                function getFooterHtml() {
19940                    return that.templates.footer({
19941                        query: query,
19942                        isEmpty: !hasSuggestions
19943                    });
19944                }
19945            },
19946            getRoot: function getRoot() {
19947                return this.$el;
19948            },
19949            update: function update(query) {
19950                var that = this;
19951                this.query = query;
19952                this.canceled = false;
19953                this.source(query, render);
19954                function render(suggestions) {
19955                    if (!that.canceled && query === that.query) {
19956                        that._render(query, suggestions);
19957                    }
19958                }
19959            },
19960            cancel: function cancel() {
19961                this.canceled = true;
19962            },
19963            clear: function clear() {
19964                this.cancel();
19965                this.$el.empty();
19966                this.trigger("rendered");
19967            },
19968            isEmpty: function isEmpty() {
19969                return this.$el.is(":empty");
19970            },
19971            destroy: function destroy() {
19972                this.$el = null;
19973            }
19974        });
19975        return Dataset;
19976        function getDisplayFn(display) {
19977            display = display || "value";
19978            return _.isFunction(display) ? display : displayFn;
19979            function displayFn(obj) {
19980                return obj[display];
19981            }
19982        }
19983        function getTemplates(templates, displayFn) {
19984            return {
19985                empty: templates.empty && _.templatify(templates.empty),
19986                header: templates.header && _.templatify(templates.header),
19987                footer: templates.footer && _.templatify(templates.footer),
19988                suggestion: templates.suggestion || suggestionTemplate
19989            };
19990            function suggestionTemplate(context) {
19991                return "<p>" + displayFn(context) + "</p>";
19992            }
19993        }
19994        function isValidName(str) {
19995            return /^[_a-zA-Z0-9-]+$/.test(str);
19996        }
19997    }();
19998    var Dropdown = function() {
19999        "use strict";
20000        function Dropdown(o) {
20001            var that = this, onSuggestionClick, onSuggestionMouseEnter, onSuggestionMouseLeave;
20002            o = o || {};
20003            if (!o.menu) {
20004                $.error("menu is required");
20005            }
20006            this.isOpen = false;
20007            this.isEmpty = true;
20008            this.datasets = _.map(o.datasets, initializeDataset);
20009            onSuggestionClick = _.bind(this._onSuggestionClick, this);
20010            onSuggestionMouseEnter = _.bind(this._onSuggestionMouseEnter, this);
20011            onSuggestionMouseLeave = _.bind(this._onSuggestionMouseLeave, this);
20012            this.$menu = $(o.menu).on("click.tt", ".tt-suggestion", onSuggestionClick).on("mouseenter.tt", ".tt-suggestion", onSuggestionMouseEnter).on("mouseleave.tt", ".tt-suggestion", onSuggestionMouseLeave);
20013            _.each(this.datasets, function(dataset) {
20014                that.$menu.append(dataset.getRoot());
20015                dataset.onSync("rendered", that._onRendered, that);
20016            });
20017        }
20018        _.mixin(Dropdown.prototype, EventEmitter, {
20019            _onSuggestionClick: function onSuggestionClick($e) {
20020                this.trigger("suggestionClicked", $($e.currentTarget));
20021            },
20022            _onSuggestionMouseEnter: function onSuggestionMouseEnter($e) {
20023                this._removeCursor();
20024                this._setCursor($($e.currentTarget), true);
20025            },
20026            _onSuggestionMouseLeave: function onSuggestionMouseLeave() {
20027                this._removeCursor();
20028            },
20029            _onRendered: function onRendered() {
20030                this.isEmpty = _.every(this.datasets, isDatasetEmpty);
20031                this.isEmpty ? this._hide() : this.isOpen && this._show();
20032                this.trigger("datasetRendered");
20033                function isDatasetEmpty(dataset) {
20034                    return dataset.isEmpty();
20035                }
20036            },
20037            _hide: function() {
20038                this.$menu.hide();
20039            },
20040            _show: function() {
20041                this.$menu.css("display", "block");
20042            },
20043            _getSuggestions: function getSuggestions() {
20044                return this.$menu.find(".tt-suggestion");
20045            },
20046            _getCursor: function getCursor() {
20047                return this.$menu.find(".tt-cursor").first();
20048            },
20049            _setCursor: function setCursor($el, silent) {
20050                $el.first().addClass("tt-cursor");
20051                !silent && this.trigger("cursorMoved");
20052            },
20053            _removeCursor: function removeCursor() {
20054                this._getCursor().removeClass("tt-cursor");
20055            },
20056            _moveCursor: function moveCursor(increment) {
20057                var $suggestions, $oldCursor, newCursorIndex, $newCursor;
20058                if (!this.isOpen) {
20059                    return;
20060                }
20061                $oldCursor = this._getCursor();
20062                $suggestions = this._getSuggestions();
20063                this._removeCursor();
20064                newCursorIndex = $suggestions.index($oldCursor) + increment;
20065                newCursorIndex = (newCursorIndex + 1) % ($suggestions.length + 1) - 1;
20066                if (newCursorIndex === -1) {
20067                    this.trigger("cursorRemoved");
20068                    return;
20069                } else if (newCursorIndex < -1) {
20070                    newCursorIndex = $suggestions.length - 1;
20071                }
20072                this._setCursor($newCursor = $suggestions.eq(newCursorIndex));
20073                this._ensureVisible($newCursor);
20074            },
20075            _ensureVisible: function ensureVisible($el) {
20076                var elTop, elBottom, menuScrollTop, menuHeight;
20077                elTop = $el.position().top;
20078                elBottom = elTop + $el.outerHeight(true);
20079                menuScrollTop = this.$menu.scrollTop();
20080                menuHeight = this.$menu.height() + parseInt(this.$menu.css("paddingTop"), 10) + parseInt(this.$menu.css("paddingBottom"), 10);
20081                if (elTop < 0) {
20082                    this.$menu.scrollTop(menuScrollTop + elTop);
20083                } else if (menuHeight < elBottom) {
20084                    this.$menu.scrollTop(menuScrollTop + (elBottom - menuHeight));
20085                }
20086            },
20087            close: function close() {
20088                if (this.isOpen) {
20089                    this.isOpen = false;
20090                    this._removeCursor();
20091                    this._hide();
20092                    this.trigger("closed");
20093                }
20094            },
20095            open: function open() {
20096                if (!this.isOpen) {
20097                    this.isOpen = true;
20098                    !this.isEmpty && this._show();
20099                    this.trigger("opened");
20100                }
20101            },
20102            setLanguageDirection: function setLanguageDirection(dir) {
20103                this.$menu.css(dir === "ltr" ? css.ltr : css.rtl);
20104            },
20105            moveCursorUp: function moveCursorUp() {
20106                this._moveCursor(-1);
20107            },
20108            moveCursorDown: function moveCursorDown() {
20109                this._moveCursor(+1);
20110            },
20111            getDatumForSuggestion: function getDatumForSuggestion($el) {
20112                var datum = null;
20113                if ($el.length) {
20114                    datum = {
20115                        raw: Dataset.extractDatum($el),
20116                        value: Dataset.extractValue($el),
20117                        datasetName: Dataset.extractDatasetName($el)
20118                    };
20119                }
20120                return datum;
20121            },
20122            getDatumForCursor: function getDatumForCursor() {
20123                return this.getDatumForSuggestion(this._getCursor().first());
20124            },
20125            getDatumForTopSuggestion: function getDatumForTopSuggestion() {
20126                return this.getDatumForSuggestion(this._getSuggestions().first());
20127            },
20128            update: function update(query) {
20129                _.each(this.datasets, updateDataset);
20130                function updateDataset(dataset) {
20131                    dataset.update(query);
20132                }
20133            },
20134            empty: function empty() {
20135                _.each(this.datasets, clearDataset);
20136                this.isEmpty = true;
20137                function clearDataset(dataset) {
20138                    dataset.clear();
20139                }
20140            },
20141            isVisible: function isVisible() {
20142                return this.isOpen && !this.isEmpty;
20143            },
20144            destroy: function destroy() {
20145                this.$menu.off(".tt");
20146                this.$menu = null;
20147                _.each(this.datasets, destroyDataset);
20148                function destroyDataset(dataset) {
20149                    dataset.destroy();
20150                }
20151            }
20152        });
20153        return Dropdown;
20154        function initializeDataset(oDataset) {
20155            return new Dataset(oDataset);
20156        }
20157    }();
20158    var Typeahead = function() {
20159        "use strict";
20160        var attrsKey = "ttAttrs";
20161        function Typeahead(o) {
20162            var $menu, $input, $hint;
20163            o = o || {};
20164            if (!o.input) {
20165                $.error("missing input");
20166            }
20167            this.isActivated = false;
20168            this.autoselect = !!o.autoselect;
20169            this.minLength = _.isNumber(o.minLength) ? o.minLength : 1;
20170            this.$node = buildDom(o.input, o.withHint);
20171            $menu = this.$node.find(".tt-dropdown-menu");
20172            $input = this.$node.find(".tt-input");
20173            $hint = this.$node.find(".tt-hint");
20174            $input.on("blur.tt", function($e) {
20175                var active, isActive, hasActive;
20176                active = document.activeElement;
20177                isActive = $menu.is(active);
20178                hasActive = $menu.has(active).length > 0;
20179                if (_.isMsie() && (isActive || hasActive)) {
20180                    $e.preventDefault();
20181                    $e.stopImmediatePropagation();
20182                    _.defer(function() {
20183                        $input.focus();
20184                    });
20185                }
20186            });
20187            $menu.on("mousedown.tt", function($e) {
20188                $e.preventDefault();
20189            });
20190            this.eventBus = o.eventBus || new EventBus({
20191                el: $input
20192            });
20193            this.dropdown = new Dropdown({
20194                menu: $menu,
20195                datasets: o.datasets
20196            }).onSync("suggestionClicked", this._onSuggestionClicked, this).onSync("cursorMoved", this._onCursorMoved, this).onSync("cursorRemoved", this._onCursorRemoved, this).onSync("opened", this._onOpened, this).onSync("closed", this._onClosed, this).onAsync("datasetRendered", this._onDatasetRendered, this);
20197            this.input = new Input({
20198                input: $input,
20199                hint: $hint
20200            }).onSync("focused", this._onFocused, this).onSync("blurred", this._onBlurred, this).onSync("enterKeyed", this._onEnterKeyed, this).onSync("tabKeyed", this._onTabKeyed, this).onSync("escKeyed", this._onEscKeyed, this).onSync("upKeyed", this._onUpKeyed, this).onSync("downKeyed", this._onDownKeyed, this).onSync("leftKeyed", this._onLeftKeyed, this).onSync("rightKeyed", this._onRightKeyed, this).onSync("queryChanged", this._onQueryChanged, this).onSync("whitespaceChanged", this._onWhitespaceChanged, this);
20201            this._setLanguageDirection();
20202        }
20203        _.mixin(Typeahead.prototype, {
20204            _onSuggestionClicked: function onSuggestionClicked(type, $el) {
20205                var datum;
20206                if (datum = this.dropdown.getDatumForSuggestion($el)) {
20207                    this._select(datum);
20208                }
20209            },
20210            _onCursorMoved: function onCursorMoved() {
20211                var datum = this.dropdown.getDatumForCursor();
20212                this.input.setInputValue(datum.value, true);
20213                this.eventBus.trigger("cursorchanged", datum.raw, datum.datasetName);
20214            },
20215            _onCursorRemoved: function onCursorRemoved() {
20216                this.input.resetInputValue();
20217                this._updateHint();
20218            },
20219            _onDatasetRendered: function onDatasetRendered() {
20220                this._updateHint();
20221            },
20222            _onOpened: function onOpened() {
20223                this._updateHint();
20224                this.eventBus.trigger("opened");
20225            },
20226            _onClosed: function onClosed() {
20227                this.input.clearHint();
20228                this.eventBus.trigger("closed");
20229            },
20230            _onFocused: function onFocused() {
20231                this.isActivated = true;
20232                this.dropdown.open();
20233            },
20234            _onBlurred: function onBlurred() {
20235                this.isActivated = false;
20236                this.dropdown.empty();
20237                this.dropdown.close();
20238            },
20239            _onEnterKeyed: function onEnterKeyed(type, $e) {
20240                var cursorDatum, topSuggestionDatum;
20241                cursorDatum = this.dropdown.getDatumForCursor();
20242                topSuggestionDatum = this.dropdown.getDatumForTopSuggestion();
20243                if (cursorDatum) {
20244                    this._select(cursorDatum);
20245                    $e.preventDefault();
20246                } else if (this.autoselect && topSuggestionDatum) {
20247                    this._select(topSuggestionDatum);
20248                    $e.preventDefault();
20249                }
20250            },
20251            _onTabKeyed: function onTabKeyed(type, $e) {
20252                var datum;
20253                if (datum = this.dropdown.getDatumForCursor()) {
20254                    this._select(datum);
20255                    $e.preventDefault();
20256                } else {
20257                    this._autocomplete(true);
20258                }
20259            },
20260            _onEscKeyed: function onEscKeyed() {
20261                this.dropdown.close();
20262                this.input.resetInputValue();
20263            },
20264            _onUpKeyed: function onUpKeyed() {
20265                var query = this.input.getQuery();
20266                this.dropdown.isEmpty && query.length >= this.minLength ? this.dropdown.update(query) : this.dropdown.moveCursorUp();
20267                this.dropdown.open();
20268            },
20269            _onDownKeyed: function onDownKeyed() {
20270                var query = this.input.getQuery();
20271                this.dropdown.isEmpty && query.length >= this.minLength ? this.dropdown.update(query) : this.dropdown.moveCursorDown();
20272                this.dropdown.open();
20273            },
20274            _onLeftKeyed: function onLeftKeyed() {
20275                this.dir === "rtl" && this._autocomplete();
20276            },
20277            _onRightKeyed: function onRightKeyed() {
20278                this.dir === "ltr" && this._autocomplete();
20279            },
20280            _onQueryChanged: function onQueryChanged(e, query) {
20281                this.input.clearHintIfInvalid();
20282                query.length >= this.minLength ? this.dropdown.update(query) : this.dropdown.empty();
20283                this.dropdown.open();
20284                this._setLanguageDirection();
20285            },
20286            _onWhitespaceChanged: function onWhitespaceChanged() {
20287                this._updateHint();
20288                this.dropdown.open();
20289            },
20290            _setLanguageDirection: function setLanguageDirection() {
20291                var dir;
20292                if (this.dir !== (dir = this.input.getLanguageDirection())) {
20293                    this.dir = dir;
20294                    this.$node.css("direction", dir);
20295                    this.dropdown.setLanguageDirection(dir);
20296                }
20297            },
20298            _updateHint: function updateHint() {
20299                var datum, val, query, escapedQuery, frontMatchRegEx, match;
20300                datum = this.dropdown.getDatumForTopSuggestion();
20301                if (datum && this.dropdown.isVisible() && !this.input.hasOverflow()) {
20302                    val = this.input.getInputValue();
20303                    query = Input.normalizeQuery(val);
20304                    escapedQuery = _.escapeRegExChars(query);
20305                    frontMatchRegEx = new RegExp("^(?:" + escapedQuery + ")(.+$)", "i");
20306                    match = frontMatchRegEx.exec(datum.value);
20307                    match ? this.input.setHint(val + match[1]) : this.input.clearHint();
20308                } else {
20309                    this.input.clearHint();
20310                }
20311            },
20312            _autocomplete: function autocomplete(laxCursor) {
20313                var hint, query, isCursorAtEnd, datum;
20314                hint = this.input.getHint();
20315                query = this.input.getQuery();
20316                isCursorAtEnd = laxCursor || this.input.isCursorAtEnd();
20317                if (hint && query !== hint && isCursorAtEnd) {
20318                    datum = this.dropdown.getDatumForTopSuggestion();
20319                    datum && this.input.setInputValue(datum.value);
20320                    this.eventBus.trigger("autocompleted", datum.raw, datum.datasetName);
20321                }
20322            },
20323            _select: function select(datum) {
20324                this.input.setQuery(datum.value);
20325                this.input.setInputValue(datum.value, true);
20326                this._setLanguageDirection();
20327                this.eventBus.trigger("selected", datum.raw, datum.datasetName);
20328                this.dropdown.close();
20329                _.defer(_.bind(this.dropdown.empty, this.dropdown));
20330            },
20331            open: function open() {
20332                this.dropdown.open();
20333            },
20334            close: function close() {
20335                this.dropdown.close();
20336            },
20337            setVal: function setVal(val) {
20338                val = _.toStr(val);
20339                if (this.isActivated) {
20340                    this.input.setInputValue(val);
20341                } else {
20342                    this.input.setQuery(val);
20343                    this.input.setInputValue(val, true);
20344                }
20345                this._setLanguageDirection();
20346            },
20347            getVal: function getVal() {
20348                return this.input.getQuery();
20349            },
20350            destroy: function destroy() {
20351                this.input.destroy();
20352                this.dropdown.destroy();
20353                destroyDomStructure(this.$node);
20354                this.$node = null;
20355            }
20356        });
20357        return Typeahead;
20358        function buildDom(input, withHint) {
20359            var $input, $wrapper, $dropdown, $hint;
20360            $input = $(input);
20361            $wrapper = $(html.wrapper).css(css.wrapper);
20362            $dropdown = $(html.dropdown).css(css.dropdown);
20363            $hint = $input.clone().css(css.hint).css(getBackgroun
20363dStyles($input));
20364            $hint.val("").removeData().addClass("tt-hint").removeAttr("id name placeholder required").prop("readonly", true).attr({
20365                autocomplete: "off",
20366                spellcheck: "false",
20367                tabindex: -1
20368            });
20369            $input.data(attrsKey, {
20370                dir: $input.attr("dir"),
20371                autocomplete: $input.attr("autocomplete"),
20372                spellcheck: $input.attr("spellcheck"),
20373                style: $input.attr("style")
20374            });
20375            $input.addClass("tt-input").attr({
20376                autocomplete: "off",
20377                spellcheck: false
20378            }).css(withHint ? css.input : css.inputWithNoHint);
20379            try {
20380                !$input.attr("dir") && $input.attr("dir", "auto");
20381            } catch (e) {}
20382            return $input.wrap($wrapper).parent().prepend(withHint ? $hint : null).append($dropdown);
20383        }
20384        function getBackgroundStyles($el) {
20385            return {
20386                backgroundAttachment: $el.css("background-attachment"),
20387                backgroundClip: $el.css("background-clip"),
20388                backgroundColor: $el.css("background-color"),
20389                backgroundImage: $el.css("background-image"),
20390                backgroundOrigin: $el.css("background-origin"),
20391                backgroundPosition: $el.css("background-position"),
20392                backgroundRepeat: $el.css("background-repeat"),
20393                backgroundSize: $el.css("background-size")
20394            };
20395        }
20396        function destroyDomStructure($node) {
20397            var $input = $node.find(".tt-input");
20398            _.each($input.data(attrsKey), function(val, key) {
20399                _.isUndefined(val) ? $input.removeAttr(key) : $input.attr(key, val);
20400            });
20401            $input.detach().removeData(attrsKey).removeClass("tt-input").insertAfter($node);
20402            $node.remove();
20403        }
20404    }();
20405    (function() {
20406        "use strict";
20407        var old, typeaheadKey, methods;
20408        old = $.fn.typeahead;
20409        typeaheadKey = "ttTypeahead";
20410        methods = {
20411            initialize: function initialize(o, datasets) {
20412                datasets = _.isArray(datasets) ? datasets : [].slice.call(arguments, 1);
20413                o = o || {};
20414                return this.each(attach);
20415                function attach() {
20416                    var $input = $(this), eventBus, typeahead;
20417                    _.each(datasets, function(d) {
20418                        d.highlight = !!o.highlight;
20419                    });
20420                    typeahead = new Typeahead({
20421                        input: $input,
20422                        eventBus: eventBus = new EventBus({
20423                            el: $input
20424                        }),
20425                        withHint: _.isUndefined(o.hint) ? true : !!o.hint,
20426                        minLength: o.minLength,
20427                        autoselect: o.autoselect,
20428                        datasets: datasets
20429                    });
20430                    $input.data(typeaheadKey, typeahead);
20431                }
20432            },
20433            open: function open() {
20434                return this.each(openTypeahead);
20435                function openTypeahead() {
20436                    var $input = $(this), typeahead;
20437                    if (typeahead = $input.data(typeaheadKey)) {
20438                        typeahead.open();
20439                    }
20440                }
20441            },
20442            close: function close() {
20443                return this.each(closeTypeahead);
20444                function closeTypeahead() {
20445                    var $input = $(this), typeahead;
20446                    if (typeahead = $input.data(typeaheadKey)) {
20447                        typeahead.close();
20448                    }
20449                }
20450            },
20451            val: function val(newVal) {
20452                return !arguments.length ? getVal(this.first()) : this.each(setVal);
20453                function setVal() {
20454                    var $input = $(this), typeahead;
20455                    if (typeahead = $input.data(typeaheadKey)) {
20456                        typeahead.setVal(newVal);
20457                    }
20458                }
20459                function getVal($input) {
20460                    var typeahead, query;
20461                    if (typeahead = $input.data(typeaheadKey)) {
20462                        query = typeahead.getVal();
20463                    }
20464                    return query;
20465                }
20466            },
20467            destroy: function destroy() {
20468                return this.each(unattach);
20469                function unattach() {
20470                    var $input = $(this), typeahead;
20471                    if (typeahead = $input.data(typeaheadKey)) {
20472                        typeahead.destroy();
20473                        $input.removeData(typeaheadKey);
20474                    }
20475                }
20476            }
20477        };
20478        $.fn.typeahead = function(method) {
20479            var tts;
20480            if (methods[method] && method !== "initialize") {
20481                tts = this.filter(function() {
20482                    return !!$(this).data(typeaheadKey);
20483                });
20484                return methods[method].apply(tts, [].slice.call(arguments, 1));
20485            } else {
20486                return methods.initialize.apply(this, arguments);
20487            }
20488        };
20489        $.fn.typeahead.noConflict = function noConflict() {
20490            $.fn.typeahead = old;
20491            return this;
20492        };
20493    })();
20494})(window.jQuery);
20495/*!
20496 * headroom.js v0.7.0 - Give your page some headroom. Hide your header until you need it
20497 * Copyright (c) 2014 Nick Williams - http://wicky.nillia.ms/headroom.js
20498 * License: MIT
20499 */
20500
20501(function(window, document) {
20502
20503  'use strict';
20504
20505  /* exported features */
20506
20507  var features = {
20508    bind : !!(function(){}.bind),
20509    classList : 'classList' in document.documentElement,
20510    rAF : !!(window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame)
20511  };
20512  window.requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame;
20513
20514  /**
20515   * Handles debouncing of events via requestAnimationFrame
20516   * @see http://www.html5rocks.com/en/tutorials/speed/animations/
20517   * @param {Function} callback The callback to handle whichever event
20518   */
20519  function Debouncer (callback) {
20520    this.callback = callback;
20521    this.ticking = false;
20522  }
20523  Debouncer.prototype = {
20524    constructor : Debouncer,
20525
20526    /**
20527     * dispatches the event to the supplied callback
20528     * @private
20529     */
20530    update : function() {
20531      this.callback && this.callback();
20532      this.ticking = false;
20533    },
20534
20535    /**
20536     * ensures events don't get stacked
20537     * @private
20538     */
20539    requestTick : function() {
20540      if(!this.ticking) {
20541        requestAnimationFrame(this.rafCallback || (this.rafCallback = this.update.bind(this)));
20542        this.ticking = true;
20543      }
20544    },
20545
20546    /**
20547     * Attach this as the event listeners
20548     */
20549    handleEvent : function() {
20550      this.requestTick();
20551    }
20552  };
20553  /**
20554   * Check if object is part of the DOM
20555   * @constructor
20556   * @param {Object} obj element to check
20557   */
20558  function isDOMElement(obj) {
20559    return obj && typeof window !== 'undefined' && (obj === window || obj.nodeType);
20560  }
20561
20562  /**
20563   * Helper function for extending objects
20564   */
20565  function extend (object /*, objectN ... */) {
20566    if(arguments.length <= 0) {
20567      throw new Error('Missing arguments in extend function');
20568    }
20569
20570    var result = object || {},
20571        key,
20572        i;
20573
20574    for (i = 1; i < arguments.length; i++) {
20575      var replacement = arguments[i] || {};
20576
20577      for (key in replacement) {
20578        // Recurse into object except if the object is a DOM element
20579        if(typeof result[key] === 'object' && ! isDOMElement(result[key])) {
20580          result[key] = extend(result[key], replacement[key]);
20581        }
20582        else {
20583          result[key] = result[key] || replacement[key];
20584        }
20585      }
20586    }
20587
20588    return result;
20589  }
20590
20591  /**
20592   * Helper function for normalizing tolerance option to object format
20593   */
20594  function normalizeTolerance (t) {
20595    return t === Object(t) ? t : { down : t, up : t };
20596  }
20597
20598  /**
20599   * UI enhancement for fixed headers.
20600   * Hides header when scrolling down
20601   * Shows header when scrolling up
20602   * @constructor
20603   * @param {DOMElement} elem the header element
20604   * @param {Object} options options for the widget
20605   */
20606  function Headroom (elem, options) {
20607    options = extend(options, Headroom.options);
20608
20609    this.lastKnownScrollY = 0;
20610    this.elem             = elem;
20611    this.debouncer        = new Debouncer(this.update.bind(this));
20612    this.tolerance        = normalizeTolerance(options.tolerance);
20613    this.classes          = options.classes;
20614    this.offset           = options.offset;
20615    this.scroller         = options.scroller;
20616    this.initialised      = false;
20617    this.onPin            = options.onPin;
20618    this.onUnpin          = options.onUnpin;
20619    this.onTop            = options.onTop;
20620    this.onNotTop         = options.onNotTop;
20621  }
20622  Headroom.prototype = {
20623    constructor : Headroom,
20624
20625    /**
20626     * Initialises the widget
20627     */
20628    init : function() {
20629      if(!Headroom.cutsTheMustard) {
20630        return;
20631      }
20632
20633      this.elem.classList.add(this.classes.initial);
20634
20635      // defer event registration to handle browser
20636      // potentially restoring previous scroll position
20637      setTimeout(this.attachEvent.bind(this), 100);
20638
20639      return this;
20640    },
20641
20642    /**
20643     * Unattaches events and removes any classes that were added
20644     */
20645    destroy : function() {
20646      var classes = this.classes;
20647
20648      this.initialised = false;
20649      this.elem.classList.remove(classes.unpinned, classes.pinned, classes.top, classes.initial);
20650      this.scroller.removeEventListener('scroll', this.debouncer, false);
20651    },
20652
20653    /**
20654     * Attaches the scroll event
20655     * @private
20656     */
20657    attachEvent : function() {
20658      if(!this.initialised){
20659        this.lastKnownScrollY = this.getScrollY();
20660        this.initialised = true;
20661        this.scroller.addEventListener('scroll', this.debouncer, false);
20662
20663        this.debouncer.handleEvent();
20664      }
20665    },
20666
20667    /**
20668     * Unpins the header if it's currently pinned
20669     */
20670    unpin : function() {
20671      var classList = this.elem.classList,
20672        classes = this.classes;
20673
20674      if(classList.contains(classes.pinned) || !classList.contains(classes.unpinned)) {
20675        classList.add(classes.unpinned);
20676        classList.remove(classes.pinned);
20677        this.onUnpin && this.onUnpin.call(this);
20678      }
20679    },
20680
20681    /**
20682     * Pins the header if it's currently unpinned
20683     */
20684    pin : function() {
20685      var classList = this.elem.classList,
20686        classes = this.classes;
20687
20688      if(classList.contains(classes.unpinned)) {
20689        classList.remove(classes.unpinned);
20690        classList.add(classes.pinned);
20691        this.onPin && this.onPin.call(this);
20692      }
20693    },
20694
20695    /**
20696     * Handles the top states
20697     */
20698    top : function() {
20699      var classList = this.elem.classList,
20700        classes = this.classes;
20701
20702      if(!classList.contains(classes.top)) {
20703        classList.add(classes.top);
20704        classList.remove(classes.notTop);
20705        this.onTop && this.onTop.call(this);
20706      }
20707    },
20708
20709    /**
20710     * Handles the not top state
20711     */
20712    notTop : function() {
20713      var classList = this.elem.classList,
20714        classes = this.classes;
20715
20716      if(!classList.contains(classes.notTop)) {
20717        classList.add(classes.notTop);
20718        classList.remove(classes.top);
20719        this.onNotTop && this.onNotTop.call(this);
20720      }
20721    },
20722
20723    /**
20724     * Gets the Y scroll position
20725     * @see https://developer.mozilla.org/en-US/docs/Web/API/Window.scrollY
20726     * @return {Number} pixels the page has scrolled along the Y-axis
20727     */
20728    getScrollY : function() {
20729      return (this.scroller.pageYOffset !== undefined)
20730        ? this.scroller.pageYOffset
20731        : (this.scroller.scrollTop !== undefined)
20732          ? this.scroller.scrollTop
20733          : (document.documentElement || document.body.parentNode || document.body).scrollTop;
20734    },
20735
20736    /**
20737     * Gets the height of the viewport
20738     * @see http://andylangton.co.uk/blog/development/get-viewport-size-width-and-height-javascript
20739     * @return {int} the height of the viewport in pixels
20740     */
20741    getViewportHeight : function () {
20742      return window.innerHeight
20743        || document.documentElement.clientHeight
20744        || document.body.clientHeight;
20745    },
20746
20747    /**
20748     * Gets the height of the document
20749     * @see http://james.padolsey.com/javascript/get-document-height-cross-browser/
20750     * @return {int} the height of the document in pixels
20751     */
20752    getDocumentHeight : function () {
20753      var body = document.body,
20754        documentElement = document.documentElement;
20755
20756      return Math.max(
20757        body.scrollHeight, documentElement.scrollHeight,
20758        body.offsetHeight, documentElement.offsetHeight,
20759        body.clientHeight, documentElement.clientHeight
20760      );
20761    },
20762
20763    /**
20764     * Gets the height of the DOM element
20765     * @param  {Object}  elm the element to calculate the height of which
20766     * @return {int}     the height of the element in pixels
20767     */
20768    getElementHeight : function (elm) {
20769      return Math.max(
20770        elm.scrollHeight,
20771        elm.offsetHeight,
20772        elm.clientHeight
20773      );
20774    },
20775
20776    /**
20777     * Gets the height of the scroller element
20778     * @return {int} the height of the scroller element in pixels
20779     */
20780    getScrollerHeight : function () {
20781      return (this.scroller === window || this.scroller === document.body)
20782        ? this.getDocumentHeight()
20783        : this.getElementHeight(this.scroller);
20784    },
20785
20786    /**
20787     * determines if the scroll position is outside of document boundaries
20788     * @param  {int}  currentScrollY the current y scroll position
20789     * @return {bool} true if out of bounds, false otherwise
20790     */
20791    isOutOfBounds : function (currentScrollY) {
20792      var pastTop  = currentScrollY < 0,
20793        pastBottom = currentScrollY + this.getViewportHeight() > this.getScrollerHeight();
20794
20795      return pastTop || pastBottom;
20796    },
20797
20798    /**
20799     * determines if the tolerance has been exceeded
20800     * @param  {int} currentScrollY the current scroll y position
20801     * @return {bool} true if tolerance exceeded, false otherwise
20802     */
20803    toleranceExceeded : function (currentScrollY, direction) {
20804      return Math.abs(currentScrollY-this.lastKnownScrollY) >= this.tolerance[direction];
20805    },
20806
20807    /**
20808     * determine if it is appropriate to unpin
20809     * @param  {int} currentScrollY the current y scroll position
20810     * @param  {bool} toleranceExceeded has the tolerance been exceeded?
20811     * @return {bool} true if should unpin, false otherwise
20812     */
20813    shouldUnpin : function (currentScrollY, toleranceExceeded) {
20814      var scrollingDown = currentScrollY > this.lastKnownScrollY,
20815        pastOffset = currentScrollY >= this.offset;
20816
20817      return scrollingDown && pastOffset && toleranceExceeded;
20818    },
20819
20820    /**
20821     * determine if it is appropriate to pin
20822     * @param  {int} currentScrollY the current y scroll position
20823     * @param  {bool} toleranceExceeded has the tolerance been exceeded?
20824     * @return {bool} true if should pin, false otherwise
20825     */
20826    shouldPin : function (currentScrollY, toleranceExceeded) {
20827      var scrollingUp  = currentScrollY < this.lastKnownScrollY,
20828        pastOffset = currentScrollY <= this.offset;
20829
20830      return (scrollingUp && toleranceExceeded) || pastOffset;
20831    },
20832
20833    /**
20834     * Handles updating the state of the widget
20835     */
20836    update : function() {
20837      var currentScrollY  = this.getScrollY(),
20838        scrollDirection = currentScrollY > this.lastKnownScrollY ? 'down' : 'up',
20839        toleranceExceeded = this.toleranceExceeded(currentScrollY, scrollDirection);
20840
20841      if(this.isOutOfBounds(currentScrollY)) { // Ignore bouncy scrolling in OSX
20842        return;
20843      }
20844
20845      if (currentScrollY <= this.offset ) {
20846        this.top();
20847      } else {
20848        this.notTop();
20849      }
20850
20851      if(this.shouldUnpin(currentScrollY, toleranceExceeded)) {
20852        this.unpin();
20853      }
20854      else if(this.shouldPin(currentScrollY, toleranceExceeded)) {
20855        this.pin();
20856      }
20857
20858      this.lastKnownScrollY = currentScrollY;
20859    }
20860  };
20861  /**
20862   * Default options
20863   * @type {Object}
20864   */
20865  Headroom.options = {
20866    tolerance : {
20867      up : 0,
20868      down : 0
20869    },
20870    offset : 0,
20871    scroller: window,
20872    classes : {
20873      pinned : 'headroom--pinned',
20874      unpinned : 'headroom--unpinned',
20875      top : 'headroom--top',
20876      notTop : 'headroom--not-top',
20877      initial : 'headroom'
20878    }
20879  };
20880  Headroom.cutsTheMustard = typeof features !== 'undefined' && features.rAF && features.bind && features.classList;
20881
20882  window.Headroom = Headroom;
20883
20884}(window, document));
20885
20886/*!
20887 * headroom.js v0.7.0 - Give your page some headroom. Hide your header until you need it
20888 * Copyright (c) 2014 Nick Williams - http://wicky.nillia.ms/headroom.js
20889 * License: MIT
20890 */
20891
20892(function($) {
20893
20894  if(!$) {
20895    return;
20896  }
20897
20898  ////////////
20899  // Plugin //
20900  ////////////
20901
20902  $.fn.headroom = function(option) {
20903    return this.each(function() {
20904      var $this   = $(this),
20905        data      = $this.data('headroom'),
20906        options   = typeof option === 'object' && option;
20907
20908      options = $.extend(true, {}, Headroom.options, options);
20909
20910      if (!data) {
20911        data = new Headroom(this, options);
20912        data.init();
20913        $this.data('headroom', data);
20914      }
20915      if (typeof option === 'string') {
20916        data[option]();
20917      }
20918    });
20919  };
20920
20921  //////////////
20922  // Data API //
20923  //////////////
20924
20925  $('[data-headroom]').each(function() {
20926    var $this = $(this);
20927    $this.headroom($this.data());
20928  });
20929
20930}(window.Zepto || window.jQuery));
20931/*!
20932 * jQuery Cookie Plugin v1.4.1
20933 * https://github.com/carhartl/jquery-cookie
20934 *
20935 * Copyright 2013 Klaus Hartl
20936 * Released under the MIT license
20937 */
20938(function (factory) {
20939	if (typeof define === 'function' && define.amd) {
20940		// AMD
20941		define(['jquery'], factory);
20942	} else if (typeof exports === 'object') {
20943		// CommonJS
20944		factory(require('jquery'));
20945	} else {
20946		// Browser globals
20947		factory(jQuery);
20948	}
20949}(function ($) {
20950
20951	var pluses = /\+/g;
20952
20953	function encode(s) {
20954		return config.raw ? s : encodeURIComponent(s);
20955	}
20956
20957	function decode(s) {
20958		return config.raw ? s : decodeURIComponent(s);
20959	}
20960
20961	function stringifyCookieValue(value) {
20962		return encode(config.json ? JSON.stringify(value) : String(value));
20963	}
20964
20965	function parseCookieValue(s) {
20966		if (s.indexOf('"') === 0) {
20967			// This is a quoted cookie as according to RFC2068, unescape...
20968			s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\');
20969		}
20970
20971		try {
20972			// Replace server-side written pluses with spaces.
20973			// If we can't decode the cookie, ignore it, it's unusable.
20974			// If we can't parse the cookie, ignore it, it's unusable.
20975			s = decodeURIComponent(s.replace(pluses, ' '));
20976			return config.json ? JSON.parse(s) : s;
20977		} catch(e) {}
20978	}
20979
20980	function read(s, converter) {
20981		var value = config.raw ? s : parseCookieValue(s);
20982		return $.isFunction(converter) ? converter(value) : value;
20983	}
20984
20985	var config = $.cookie = function (key, value, options) {
20986
20987		// Write
20988
20989		if (value !== undefined && !$.isFunction(value)) {
20990			options = $.extend({}, config.defaults, options);
20991
20992			if (typeof options.expires === 'number') {
20993				var days = options.expires, t = options.expires = new Date();
20994				t.setTime(+t + days * 864e+5);
20995			}
20996
20997			return (document.cookie = [
20998				encode(key), '=', stringifyCookieValue(value),
20999				options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
21000				options.path    ? '; path=' + options.path : '',
21001				options.domain  ? '; domain=' + options.domain : '',
21002				options.secure  ? '; secure' : ''
21003			].join(''));
21004		}
21005
21006		// Read
21007
21008		var result = key ? undefined : {};
21009
21010		// To prevent the for loop in the first place assign an empty array
21011		// in case there are no cookies at all. Also prevents odd result when
21012		// calling $.cookie().
21013		var cookies = document.cookie ? document.cookie.split('; ') : [];
21014
21015		for (var i = 0, l = cookies.length; i < l; i++) {
21016			var parts = cookies[i].split('=');
21017			var name = decode(parts.shift());
21018			var cookie = parts.join('=');
21019
21020			if (key && key === name) {
21021				// If second argument (value) is a function it's a converter...
21022				result = read(cookie, value);
21023				break;
21024			}
21025
21026			// Prevent storing a cookie that we couldn't decode.
21027			if (!key && (cookie = read(cookie)) !== undefined) {
21028				result[name] = cookie;
21029			}
21030		}
21031
21032		return result;
21033	};
21034
21035	config.defaults = {};
21036
21037	$.removeCookie = function (key, options) {
21038		if ($.cookie(key) === undefined) {
21039			return false;
21040		}
21041
21042		// Must not alter options, thus extending a fresh object...
21043		$.cookie(key, '', $.extend({}, options, { expires: -1 }));
21044		return !$.cookie(key);
21045	};
21046
21047}));
21048
21049function getContentLanguage() {
21050  return ( $("html[lang]").length > 0 ) ? $('html').attr('lang') : 'de';
21051};
21052
21053// replace header and navigation
21054$(document).ready(function(){
21055
21056  $.ajaxPrefilter(function( options, originalOptions, jqXHR ) {
21057    if ( options.dataType == 'script' || originalOptions.dataType == 'script' ) {
21058      options.cache = true;
21059    }
21060  });
21061
21062  window.syncObjects = {
21063    'de': [{
21064        'remoteSnippetURL': "//www.bme.de/remote/footer/?no_cache=1&type=456",
21065        'targetSelector': '.footer-wrapper',
21066        'expirationDelta': 600000, // 86396875
21067        'localStorageItem': 'footer_html_de',
21068        'localStorageExpirationItem': 'footer_cache_date_de',
21069        'callback': swapped_navigation
21070      },
21071      {
21072        'remoteSnippetURL': "//www.bme.de/remote/navigation/?no_cache=1&type=456",
21073        'targetSelector': '#replaceable-navigation',
21074        'expirationDelta': 600000,
21075        'localStorageItem': 'navigation_html_de',
21076        'localStorageExpirationItem': 'navigation_cache_date_de',
21077        'callback': swapped_navigation
21078      },
21079      {
21080        'remoteSnippetURL': "//shop.bme.de/de/shopping_cart?locale=de",
21081        'targetSelector': '#shopping-cart-nav-item',
21082        'expirationDelta': -1,
21083        'localStorageItem': 'navigation_cart_de',
21084        'localStorageExpirationItem': 'navigation_cart_cache_delta_de',
21085        'callback': swapped_navigation
21086      }
21087    ],
21088    'en': [{
21089        'remoteSnippetURL': "//www.bme.de/remote/footer-en/?no_cache=1&type=456",
21090        'targetSelector': '.footer-wrapper',
21091        'expirationDelta': 600000,
21092        'localStorageItem': 'footer_html_en',
21093        'localStorageExpirationItem': 'footer_cache_date_en',
21094        'callback': swapped_navigation
21095      },
21096      {
21097        'remoteSnippetURL': "//www.bme.de/remote/navigation-en/?no_cache=1&type=456",
21098        'targetSelector': '#replaceable-navigation',
21099        'expirationDelta': 600000,
21100        'localStorageItem': 'navigation_html_en',
21101        'localStorageExpirationItem': 'navigation_cache_date_en',
21102        'callback': swapped_navigation
21103      },
21104      {
21105        'remoteSnippetURL': "//shop.bme.de/de/shopping_cart?locale=en",
21106        'targetSelector': '#shopping-cart-nav-item',
21107        'expirationDelta': -1,
21108        'localStorageItem': 'navigation_cart_en',
21109        'localStorageExpirationItem': 'navigation_cart_cache_delta_en',
21110        'callback': swapped_navigation
21111      }
21112    ]
21113  };
21114
21115  window.syncFactory = (new SyncHTMLPartials);
21116  window.syncFactory.sync(window.syncObjects);
21117});
21118
21119var SyncHTMLPartials = function(){
21120  SyncHTMLPartials.prototype.sync = function(syncObjects) {
21121    for (var i = syncObjects[getContentLanguage().toLowerCase()].length - 1; i >= 0; i--) {
21122      var snippet, syncobject = syncObjects[getContentLanguage().toLowerCase()][i];
21123
21124      if ($(syncobject.targetSelector).length === 0 || $(syncobject.targetSelector).attr('data-no-remote-sync')) {
21125        continue;
21126      }
21127
21128      if (snippet = this.loadFromCache(syncobject)) {
21129        // If the navigation is cached, swap it.
21130        this.swapHTML(snippet, syncobject.targetSelector, syncobject.callback);
21131      } else {
21132        // If not, perform an ajax request.
21133        this.retrieveHTML(this, syncobject);
21134      }
21135    }
21136  };
21137  SyncHTMLPartials.prototype.retrieveHTML = function(klass, syncobject) {
21138    var syncobjectid = window.syncObjects[getContentLanguage().toLowerCase()].indexOf(syncobject);
21139    var script_url = syncobject.remoteSnippetURL;
21140
21141    var script = document.createElement('script');
21142    script.type = 'text/javascript';
21143    script.id = 'syncobject_' + syncobjectid;
21144    script.src = script_url + '&callback=window.syncFactory.processHTML&syncobjectid=' + syncobjectid;
21145
21146    if ($('head').find(script.id).length > 0) {
21147      $('head').find(script.id).replaceWith(script);
21148    } else {
21149      $('head').append(script);
21150    }
21151  };
21152  SyncHTMLPartials.prototype.processHTML = function(syncobjectID, data) {
21153    syncobject = window.syncObjects[getContentLanguage().toLowerCase()][syncobjectID];
21154
21155    // The expiration date is based on the current time (in ticks) + the specified delta
21156    localStorage.setItem(syncobject.localStorageExpirationItem, (new Date).valueOf() + syncobject.expirationDelta );
21157    localStorage.setItem(syncobject.localStorageItem, data);
21158    (new SyncHTMLPartials).swapHTML(data, syncobject.targetSelector, syncobject.callback);
21159  };
21160  SyncHTMLPartials.prototype.swapHTML = function(htmlPartial, targetSelector, callback) {
21161    $( targetSelector ).html( htmlPartial );
21162
21163    $('a', $(targetSelector)).attr("target", ""); // BME only!
21164
21165    if (callback !== undefined && typeof callback == 'function') callback();
21166  };
21167  SyncHTMLPartials.prototype.loadFromCache = function(syncobject) {
21168    var result = localStorage.getItem( syncobject.localStorageItem );
21169    var not_expired = ( localStorage.getItem(syncobject.localStorageExpirationItem) > (new Date).valueOf() );
21170    return (not_expired && result != "undefined" && !!result && result != "" && result !== undefined) ? result : false;
21171  };
21172};
21173
21174function environment_switch(production, development) {
21175  $body = $("body");
21176  $html = $("html");
21177  env = production;
21178
21179  if ($body.data("environment") === "development" || $html.data("environment") === "development") {
21180    env = development;
21181  }
21182
21183  return env;
21184}
21185
21186(function($) {
21187  $.yuniqueSSO = function(element, options) {
21188    var defaults = {
21189      idp_template: 'me',
21190      idp_host: 'https://regionen.bme.de',
21191      idp_path: '',
21192      sp_user_id: '',
21193      sp_hash: '',
21194      sp_name: '',
21195      poll_interval: 30000,
21196      uuid: '' + Math.floor(Math.random()*20),
21197      locale: getContentLanguage() || 'de'
21198    };
21199
21200    var plugin = this;
21201    plugin.settings = {};
21202
21203    var $element = $(element),
21204         element = element;
21205
21206    plugin.init = function() {
21207      plugin.settings = $.extend({}, defaults, options);
21208
21209      window['yuniqueSSO_' + plugin.settings.uuid] = {};
21210      window['yuniqueSSO_' + plugin.settings.uuid].current_state = 0;
21211      window['yuniqueSSO_' + plugin.settings.uuid].ssoCallback = function (state, data, redirect) {
21212        if (window['yuniqueSSO_' + plugin.settings.uuid].current_state !== state) {
21213          if (state == 200 || state == 401) {
21214            $element.html(data);
21215          } else {
21216            document.location.href = redirect.replace('&amp;', '&');
21217          }
21218          window['yuniqueSSO_' + plugin.settings.uuid].current_state = state;
21219        }
21220      };
21221
21222      window['yuniqueSSO_' + plugin.settings.uuid].jsonpInclude = function() {
21223        var script = document.createElement('script');
21224        script.type = 'text/javascript';
21225        script.id = 'yuniqueSSO_' + plugin.settings.uuid;
21226        script.src = plugin.settings.idp_host +
21227                     '/account/' + plugin.settings.idp_template + '.js' +
21228                     '?sp_user_id=' + plugin.settings.sp_user_id +
21229                     '&sp_callback=window.yuniqueSSO_' + plugin.settings.uuid +
21230                     '.ssoCallback&sp_name=' + plugin.settings.sp_name +
21231                     '&sp_hash=' + plugin.settings.sp_hash +
21232                     '&locale=' + plugin.settings.locale +
21233                     '&sp_return_uri=' + encodeURIComponent($(location).attr('pathname') + $(location).attr('search')) +
21234                     '&sp_thash=' + new Date().getTime();
21235
21236        if ($('head').find('#yuniqueSSO_' + plugin.settings.uuid).length > 0) {
21237          $('head').find('#yuniqueSSO_' + plugin.settings.uuid).replaceWith(script);
21238        } else {
21239          $('head').append(script);
21240        }
21241      };
21242
21243      window['yuniqueSSO_' + plugin.settings.uuid].jsonpInclude();
21244      if (plugin.settings.poll_interval >= 0) {
21245        window.setInterval(
21246          window['yuniqueSSO_' + plugin.settings.uuid].jsonpInclude,
21247          plugin.settings.poll_interval
21248        );
21249      }
21250    };
21251
21252    plugin.init();
21253  };
21254
21255  $.fn.yuniqueSSO = function(options) {
21256    return this.each(function() {
21257      if (undefined === $(this).data('yuniqueSSO')) {
21258        var plugin = new $.yuniqueSSO(this, options);
21259        $(this).data('yuniqueSSO', plugin);
21260      }
21261    });
21262  };
21263})(jQuery);
21264
21265if (window.infopool_url === undefined) {
21266  if (document.location.host.indexOf("bme.de") != -1) { window.infopool_url = '//suche.bme.de'; }
21267  else { window.infopool_url = '//bme-search.staging.yum.de'; }
21268}
21269
21270function bindSearch() {
21271  $('#header-search-tablet-form').attr('action', window.infopool_url);
21272  $('#header-search-tablet-form input').attr('name', 'q');
21273  $('#header-search-tablet-form').append('<input type="hidden" name="lang" value="' + getContentLanguage() + '">');
21274
21275  var globalSearch = new Bloodhound({
21276    datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
21277    queryTokenizer: Bloodhound.tokenizers.whitespace,
21278    limit: 100,
21279    remote: {
21280      url: window.infopool_url + '/search.jsonp?q=%QUERY&lang=' + getContentLanguage() + '&callback=?',
21281      dataType: 'jsonp',
21282      filter: function(list) {
21283        return $.map(list.results, function(result) {
21284          result.title = result.title.replace(/(&quot;|&amp;quot;)/g, "\"");
21285          result.pub_date = (result.pub_date != undefined) ? result.pub_date : null;
21286          if (result.is_group !== true) {
21287            result.categories = result.category.split(",").join(" / ").replace(/(&quot;|&amp;quot;)/g, "\"").replace(/&amp;/g, "&");
21288          }
21289          return result;
21290        });
21291      }
21292    }
21293  });
21294
21295  globalSearch.initialize();
21296
21297  $('#header-search-tablet-form input[name="q"]').typeahead({
21298    highlight: true,
21299    minLength: 3
21300  }, {
21301    name: 'best-pictures',
21302    displayKey: 'query',
21303    source: globalSearch.ttAdapter(),
21304    templates: {
21305      empty: [
21306        '<div class="tt-suggestions"><div class="tt-suggestion text-center tt-suggestion-no-results">',
21307        (getContentLanguage() == 'en' ? 'No results found.' : 'Keine Suchergebnisse gefunden.'),
21308        '</div></div>'
21309      ].join('\n'),
21310      suggestion: Handlebars.compile('{{#if is_group}}<a href="{{link}}" class="search-results-group-title">    <h3>{{title}} <i class="icon-dfb icon-sm"></i></h3></a>{{else}}<a href="{{link}}" class="search-result-link">    <h6>{{#if pub_date}}{{pub_date}}{{/if}}{{#if categories}} / {{categories}}{{/if}}</h6><h4 class="list-group-item-heading">{{title}}</h4></a>{{/if}}')
21311    }
21312  }).on('typeahead:selected', function(event, selection) {
21313    window.location.href = selection.link;
21314    $('#header-search-tablet-form input').typeahead('close');
21315  }).off('blur');
21316
21317  $(document).click(function(event) {
21318    if ($(event.target).attr('class') !== 'tt-input') $('#header-search-tablet-form input').typeahead('close');
21319  });
21320}
21321
21322$(document).ready(function() {
21323  bindSearch();
21324});
21325
21326/*
21327Copyright 2012 Igor Vaynberg
21328
21329Version: 3.4.8 Timestamp: Thu May  1 09:50:32 EDT 2014
21330
21331This software is licensed under the Apache License, Version 2.0 (the "Apache License") or the GNU
21332General Public License version 2 (the "GPL License"). You may choose either license to govern your
21333use of this software only upon the condition that you accept all of the terms of either the Apache
21334License or the GPL License.
21335
21336You may obtain a copy of the Apache License and the GPL License at:
21337
21338    http://www.apache.org/licenses/LICENSE-2.0
21339    http://www.gnu.org/licenses/gpl-2.0.html
21340
21341Unless required by applicable law or agreed to in writing, softw
21341are distributed under the
21342Apache License or the GPL License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
21343CONDITIONS OF ANY KIND, either express or implied. See the Apache License and the GPL License for
21344the specific language governing permissions and limitations under the Apache License and the GPL License.
21345*/
21346
21347(function ($) {
21348    if(typeof $.fn.each2 == "undefined") {
21349        $.extend($.fn, {
21350            /*
21351            * 4-10 times faster .each replacement
21352            * use it carefully, as it overrides jQuery context of element on each iteration
21353            */
21354            each2 : function (c) {
21355                var j = $([0]), i = -1, l = this.length;
21356                while (
21357                    ++i < l
21358                    && (j.context = j[0] = this[i])
21359                    && c.call(j[0], i, j) !== false //"this"=DOM, i=index, j=jQuery object
21360                );
21361                return this;
21362            }
21363        });
21364    }
21365})(jQuery);
21366
21367(function ($, undefined) {
21368    "use strict";
21369    /*global document, window, jQuery, console */
21370
21371    if (window.Select2 !== undefined) {
21372        return;
21373    }
21374
21375    var KEY, AbstractSelect2, SingleSelect2, MultiSelect2, nextUid, sizer,
21376        lastMousePosition={x:0,y:0}, $document, scrollBarDimensions,
21377
21378    KEY = {
21379        TAB: 9,
21380        ENTER: 13,
21381        ESC: 27,
21382        SPACE: 32,
21383        LEFT: 37,
21384        UP: 38,
21385        RIGHT: 39,
21386        DOWN: 40,
21387        SHIFT: 16,
21388        CTRL: 17,
21389        ALT: 18,
21390        PAGE_UP: 33,
21391        PAGE_DOWN: 34,
21392        HOME: 36,
21393        END: 35,
21394        BACKSPACE: 8,
21395        DELETE: 46,
21396        isArrow: function (k) {
21397            k = k.which ? k.which : k;
21398            switch (k) {
21399            case KEY.LEFT:
21400            case KEY.RIGHT:
21401            case KEY.UP:
21402            case KEY.DOWN:
21403                return true;
21404            }
21405            return false;
21406        },
21407        isControl: function (e) {
21408            var k = e.which;
21409            switch (k) {
21410            case KEY.SHIFT:
21411            case KEY.CTRL:
21412            case KEY.ALT:
21413                return true;
21414            }
21415
21416            if (e.metaKey) return true;
21417
21418            return false;
21419        },
21420        isFunctionKey: function (k) {
21421            k = k.which ? k.which : k;
21422            return k >= 112 && k <= 123;
21423        }
21424    },
21425    MEASURE_SCROLLBAR_TEMPLATE = "<div class='select2-measure-scrollbar'></div>",
21426
21427    DIACRITICS = {"\u24B6":"A","\uFF21":"A","\u00C0":"A","\u00C1":"A","\u00C2":"A","\u1EA6":"A","\u1EA4":"A","\u1EAA":"A","\u1EA8":"A","\u00C3":"A","\u0100":"A","\u0102":"A","\u1EB0":"A","\u1EAE":"A","\u1EB4":"A","\u1EB2":"A","\u0226":"A","\u01E0":"A","\u00C4":"A","\u01DE":"A","\u1EA2":"A","\u00C5":"A","\u01FA":"A","\u01CD":"A","\u0200":"A","\u0202":"A","\u1EA0":"A","\u1EAC":"A","\u1EB6":"A","\u1E00":"A","\u0104":"A","\u023A":"A","\u2C6F":"A","\uA732":"AA","\u00C6":"AE","\u01FC":"AE","\u01E2":"AE","\uA734":"AO","\uA736":"AU","\uA738":"AV","\uA73A":"AV","\uA73C":"AY","\u24B7":"B","\uFF22":"B","\u1E02":"B","\u1E04":"B","\u1E06":"B","\u0243":"B","\u0182":"B","\u0181":"B","\u24B8":"C","\uFF23":"C","\u0106":"C","\u0108":"C","\u010A":"C","\u010C":"C","\u00C7":"C","\u1E08":"C","\u0187":"C","\u023B":"C","\uA73E":"C","\u24B9":"D","\uFF24":"D","\u1E0A":"D","\u010E":"D","\u1E0C":"D","\u1E10":"D","\u1E12":"D","\u1E0E":"D","\u0110":"D","\u018B":"D","\u018A":"D","\u0189":"D","\uA779":"D","\u01F1":"DZ","\u01C4":"DZ","\u01F2":"Dz","\u01C5":"Dz","\u24BA":"E","\uFF25":"E","\u00C8":"E","\u00C9":"E","\u00CA":"E","\u1EC0":"E","\u1EBE":"E","\u1EC4":"E","\u1EC2":"E","\u1EBC":"E","\u0112":"E","\u1E14":"E","\u1E16":"E","\u0114":"E","\u0116":"E","\u00CB":"E","\u1EBA":"E","\u011A":"E","\u0204":"E","\u0206":"E","\u1EB8":"E","\u1EC6":"E","\u0228":"E","\u1E1C":"E","\u0118":"E","\u1E18"
21427:"E","\u1E1A":"E","\u0190":"E","\u018E":"E","\u24BB":"F","\uFF26":"F","\u1E1E":"F","\u0191":"F","\uA77B":"F","\u24BC":"G","\uFF27":"G","\u01F4":"G","\u011C":"G","\u1E20":"G","\u011E":"G","\u0120":"G","\u01E6":"G","\u0122":"G","\u01E4":"G","\u0193":"G","\uA7A0":"G","\uA77D":"G","\uA77E":"G","\u24BD":"H","\uFF28":"H","\u0124":"H","\u1E22":"H","\u1E26":"H","\u021E":"H","\u1E24":"H","\u1E28":"H","\u1E2A":"H","\u0126":"H","\u2C67":"H","\u2C75":"H","\uA78D":"H","\u24BE":"I","\uFF29":"I","\u00CC":"I","\u00CD":"I","\u00CE":"I","\u0128":"I","\u012A":"I","\u012C":"I","\u0130":"I","\u00CF":"I","\u1E2E":"I","\u1EC8":"I","\u01CF":"I","\u0208":"I","\u020A":"I","\u1ECA":"I","\u012E":"I","\u1E2C":"I","\u0197":"I","\u24BF":"J","\uFF2A":"J","\u0134":"J","\u0248":"J","\u24C0":"K","\uFF2B":"K","\u1E30":"K","\u01E8":"K","\u1E32":"K","\u0136":"K","\u1E34":"K","\u0198":"K","\u2C69":"K","\uA740":"K","\uA742":"K","\uA744":"K","\uA7A2":"K","\u24C1":"L","\uFF2C":"L","\u013F":"L","\u0139":"L","\u013D":"L","\u1E36":"L","\u1E38":"L","\u013B":"L","\u1E3C":"L","\u1E3A":"L","\u0141":"L","\u023D":"L","\u2C62":"L","\u2C60":"L","\uA748":"L","\uA746":"L","\uA780":"L","\u01C7":"LJ","\u01C8":"Lj","\u24C2":"M","\uFF2D":"M","\u1E3E":"M","\u1E40":"M","\u1E42":"M","\u2C6E":"M","\u019C":"M","\u24C3":"N","\uFF2E":"N","\u01F8":"N","\u0143":"N","\u00D1":"N","\u1E44":"N","\u0147":"N","\u1E46":"N","\u0145":"N","\u1E4A":"N","\u1E48":"N","\u0220":"N","\u019D":"N","\uA790":"N","\uA7A4":"N","\u01CA":"NJ","\u01CB":"Nj","\u24C4":"O","\uFF2F":"O","\u00D2":"O","\u00D3":"O","\u00D4":"O","\u1ED2":"O","\u1ED0":"O","\u1ED6":"O","\u1ED4":"O","\u00D5":"O","\u1E4C":"O","\u022C":"O","\u1E4E":"O","\u014C":"O","\u1E50":"O","\u1E52":"O","\u014E":"O","\u022E":"O","\u0230":"O","\u00D6":"O","\u022A":"O","\u1ECE":"O","\u0150":"O","\u01D1":"O","\u020C":"O","\u020E":"O","\u01A0":"O","\u1EDC":"O","\u1EDA":"O","\u1EE0":"O","\u1EDE":"O","\u1EE2":"O","\u1ECC":"O","\u1ED8":"O","\u01EA":"O","\u01EC":"O","\u00D8":"O","\u01FE":"O","\u0186":"O","\u019F":"O","\uA74A":"O","\uA74C":"O","\u01A2":"OI","\uA74E":"OO","\u0222":"OU","\u24C5":"P","\uFF30":"P","\u1E54":"P","\u1E56":"P","\u01A4":"P","\u2C63":"P","\uA750":"P","\uA752":"P","\uA754":"P","\u24C6":"Q","\uFF31":"Q","\uA756":"Q","\uA758":"Q","\u024A":"Q","\u24C7":"R","\uFF32":"R","\u0154":"R","\u1E58":"R","\u0158":"R","\u0210":"R","\u0212":"R","\u1E5A":"R","\u1E5C":"R","\u0156":"R","\u1E5E":"R","\u024C":"R","\u2C64":"R","\uA75A":"R","\uA7A6":"R","\uA782":"R","\u24C8":"S","\uFF33":"S","\u1E9E":"S","\u015A":"S","\u1E64":"S","\u015C":"S","\u1E60":"S","\u0160":"S","\u1E66":"S","\u1E62":"S","\u1E68":"S","\u0218":"S","\u015E":"S","\u2C7E":"S","\uA7A8":"S","\uA784":"S","\u24C9":"T","\uFF34":"T","\u1E6A":"T","\u0164":"T","\u1E6C":"T","\u021A":"T","\u0162":"T","\u1E70":"T","\u1E6E":"T","\u0166":"T","\u01AC":"T","\u01AE":"T","\u023E":"T","\uA786":"T","\uA728":"TZ","\u24CA":"U","\uFF35":"U","\u00D9":"U","\u00DA":"U","\u00DB":"U","\u0168":"U","\u1E78":"U","\u016A":"U","\u1E7A":"U","\u016C":"U","\u00DC":"U","\u01DB":"U","\u01D7":"U","\u01D5":"U","\u01D9":"U","\u1EE6":"U","\u016E":"U","\u0170":"U","\u01D3":"U","\u0214":"U","\u0216":"U","\u01AF":"U","\u1EEA":"U","\u1EE8":"U","\u1EEE":"U","\u1EEC":"U","\u1EF0":"U","\u1EE4":"U","\u1E72":"U","\u0172":"U","\u1E76":"U","\u1E74":"U","\u0244":"U","\u24CB":"V","\uFF36":"V","\u1E7C":"V","\u1E7E":"V","\u01B2":"V","\uA75E":"V","\u0245":"V","\uA760":"VY","\u24CC":"W","\uFF37":"W","\u1E80":"W","\u1E82":"W","\u0174":"W","\u1E86":"W","\u1E84":"W","\u1E88":"W","\u2C72":"W","\u24CD":"X","\uFF38":"X","\u1E8A":"X","\u1E8C":"X","\u24CE":"Y","\uFF39":"Y","\u1EF2":"Y","\u00DD":"Y","\u0176":"Y","\u1EF8":"Y","\u0232":"Y","\u1E8E":"Y","\u0178":"Y","\u1EF6":"Y","\u1EF4":"Y","\u01B3":"Y","\u024E":"Y","\u1EFE":"Y","\u24CF":"Z","\uFF3A":"Z","\u0179":"Z","\u1E90":"Z","\u017B":"Z","\u017D":"Z","\u1E92":"Z","\u1E94":"Z","\u01B5":"Z","\u0224":"Z","\u2C7F":"Z","\u2C6B":"Z","\uA762":"Z","\u24D0":"a","\uFF41":"a","\u1E9A":"a","\u00E0":"a","\u00E1":"a","\u00E2":"a","\u1EA7":"a","\u1EA5":"a","\u1EAB":"a","\u1EA9":"a","\u00E3":"a","\u0101":"a","\u0103":"a","\u1EB1":"a","\u1EAF":"a","\u1EB5":"a","\u1EB3":"a","\u0227":"a","\u01E1":"a","\u00E4":"a","\u01DF":"a","\u1EA3":"a","\u00E5":"a","\u01FB":"a","\u01CE":"a","\u0201":"a","\u0203":"a","\u1EA1":"a","\u1EAD":"a","\u1EB7":"a","\u1E01":"a","\u0105":"a","\u2C65":"a","\u0250":"a","\uA733":"aa","\u00E6":"ae","\u01FD":"ae","\u01E3":"ae","\uA735":"ao","\uA737":"au","\uA739":"av","\uA73B":"av","\uA73D":"ay","\u24D1":"b","\uFF42":"b","\u1E03":"b","\u1E05":"b","\u1E07":"b","\u0180":"b","\u0183":"b","\u0253":"b","\u24D2":"c","\uFF43":"c","\u0107":"c","\u0109":"c","\u010B":"c","\u010D":"c","\u00E7":"c","\u1E09":"c","\u0188":"c","\u023C":"c","\uA73F":"c","\u2184":"c","\u24D3":"d","\uFF44":"d","\u1E0B":"d","\u010F":"d","\u1E0D":"d","\u1E11":"d","\u1E13":"d","\u1E0F":"d","\u0111":"d","\u018C":"d","\u0256":"d","\u0257":"d","\uA77A":"d","\u01F3":"dz","\u01C6":"dz","\u24D4":"e","\uFF45":"e","\u00E8":"e","\u00E9":"e","\u00EA":"e","\u1EC1":"e","\u1EBF":"e","\u1EC
214275":"e","\u1EC3":"e","\u1EBD":"e","\u0113":"e","\u1E15":"e","\u1E17":"e","\u0115":"e","\u0117":"e","\u00EB":"e","\u1EBB":"e","\u011B":"e","\u0205":"e","\u0207":"e","\u1EB9":"e","\u1EC7":"e","\u0229":"e","\u1E1D":"e","\u0119":"e","\u1E19":"e","\u1E1B":"e","\u0247":"e","\u025B":"e","\u01DD":"e","\u24D5":"f","\uFF46":"f","\u1E1F":"f","\u0192":"f","\uA77C":"f","\u24D6":"g","\uFF47":"g","\u01F5":"g","\u011D":"g","\u1E21":"g","\u011F":"g","\u0121":"g","\u01E7":"g","\u0123":"g","\u01E5":"g","\u0260":"g","\uA7A1":"g","\u1D79":"g","\uA77F":"g","\u24D7":"h","\uFF48":"h","\u0125":"h","\u1E23":"h","\u1E27":"h","\u021F":"h","\u1E25":"h","\u1E29":"h","\u1E2B":"h","\u1E96":"h","\u0127":"h","\u2C68":"h","\u2C76":"h","\u0265":"h","\u0195":"hv","\u24D8":"i","\uFF49":"i","\u00EC":"i","\u00ED":"i","\u00EE":"i","\u0129":"i","\u012B":"i","\u012D":"i","\u00EF":"i","\u1E2F":"i","\u1EC9":"i","\u01D0":"i","\u0209":"i","\u020B":"i","\u1ECB":"i","\u012F":"i","\u1E2D":"i","\u0268":"i","\u0131":"i","\u24D9":"j","\uFF4A":"j","\u0135":"j","\u01F0":"j","\u0249":"j","\u24DA":"k","\uFF4B":"k","\u1E31":"k","\u01E9":"k","\u1E33":"k","\u0137":"k","\u1E35":"k","\u0199":"k","\u2C6A":"k","\uA741":"k","\uA743":"k","\uA745":"k","\uA7A3":"k","\u24DB":"l","\uFF4C":"l","\u0140":"l","\u013A":"l","\u013E":"l","\u1E37":"l","\u1E39":"l","\u013C":"l","\u1E3D":"l","\u1E3B":"l","\u017F":"l","\u0142":"l","\u019A":"l","\u026B":"l","\u2C61":"l","\uA749":"l","\uA781":"l","\uA747":"l","\u01C9":"lj","\u24DC":"m","\uFF4D":"m","\u1E3F":"m","\u1E41":"m","\u1E43":"m","\u0271":"m","\u026F":"m","\u24DD":"n","\uFF4E":"n","\u01F9":"n","\u0144":"n","\u00F1":"n","\u1E45":"n","\u0148":"n","\u1E47":"n","\u0146":"n","\u1E4B":"n","\u1E49":"n","\u019E":"n","\u0272":"n","\u0149":"n","\uA791":"n","\uA7A5":"n","\u01CC":"nj","\u24DE":"o","\uFF4F":"o","\u00F2":"o","\u00F3":"o","\u00F4":"o","\u1ED3":"o","\u1ED1":"o","\u1ED7":"o","\u1ED5":"o","\u00F5":"o","\u1E4D":"o","\u022D":"o","\u1E4F":"o","\u014D":"o","\u1E51":"o","\u1E53":"o","\u014F":"o","\u022F":"o","\u0231":"o","\u00F6":"o","\u022B":"o","\u1ECF":"o","\u0151":"o","\u01D2":"o","\u020D":"o","\u020F":"o","\u01A1":"o","\u1EDD":"o","\u1EDB":"o","\u1EE1":"o","\u1EDF":"o","\u1EE3":"o","\u1ECD":"o","\u1ED9":"o","\u01EB":"o","\u01ED":"o","\u00F8":"o","\u01FF":"o","\u0254":"o","\uA74B":"o","\uA74D":"o","\u0275":"o","\u01A3":"oi","\u0223":"ou","\uA74F":"oo","\u24DF":"p","\uFF50":"p","\u1E55":"p","\u1E57":"p","\u01A5":"p","\u1D7D":"p","\uA751":"p","\uA753":"p","\uA755":"p","\u24E0":"q","\uFF51":"q","\u024B":"q","\uA757":"q","\uA759":"q","\u24E1":"r","\uFF52":"r","\u0155":"r","\u1E59":"r","\u0159":"r","\u0211":"r","\u0213":"r","\u1E5B":"r","\u1E5D":"r","\u0157":"r","\u1E5F":"r","\u024D":"r","\u027D":"r","\uA75B":"r","\uA7A7":"r","\uA783":"r","\u24E2":"s","\uFF53":"s","\u00DF":"s","\u015B":"s","\u1E65":"s","\u015D":"s","\u1E61":"s","\u0161":"s","\u1E67":"s","\u1E63":"s","\u1E69":"s","\u0219":"s","\u015F":"s","\u023F":"s","\uA7A9":"s","\uA785":"s","\u1E9B":"s","\u24E3":"t","\uFF54":"t","\u1E6B":"t","\u1E97":"t","\u0165":"t","\u1E6D":"t","\u021B":"t","\u0163":"t","\u1E71":"t","\u1E6F":"t","\u0167":"t","\u01AD":"t","\u0288":"t","\u2C66":"t","\uA787":"t","\uA729":"tz","\u24E4":"u","\uFF55":"u","\u00F9":"u","\u00FA":"u","\u00FB":"u","\u0169":"u","\u1E79":"u","\u016B":"u","\u1E7B":"u","\u016D":"u","\u00FC":"u","\u01DC":"u","\u01D8":"u","\u01D6":"u","\u01DA":"u","\u1EE7":"u","\u016F":"u","\u0171":"u","\u01D4":"u","\u0215":"u","\u0217":"u","\u01B0":"u","\u1EEB":"u","\u1EE9":"u","\u1EEF":"u","\u1EED":"u","\u1EF1":"u","\u1EE5":"u","\u1E73":"u","\u0173":"u","\u1E77":"u","\u1E75":"u","\u0289":"u","\u24E5":"v","\uFF56":"v","\u1E7D":"v","\u1E7F":"v","\u028B":"v","\uA75F":"v","\u028C":"v","\uA761":"vy","\u24E6":"w","\uFF57":"w","\u1E81":"w","\u1E83":"w","\u0175":"w","\u1E87":"w","\u1E85":"w","\u1E98":"w","\u1E89":"w","\u2C73":"w","\u24E7":"x","\uFF58":"x","\u1E8B":"x","\u1E8D":"x","\u24E8":"y","\uFF59":"y","\u1EF3":"y","\u00FD":"y","\u0177":"y","\u1EF9":"y","\u0233":"y","\u1E8F":"y","\u00FF":"y","\u1EF7":"y","\u1E99":"y","\u1EF5":"y","\u01B4":"y","\u024F":"y","\u1EFF":"y","\u24E9":"z","\uFF5A":"z","\u017A":"z","\u1E91":"z","\u017C":"z","\u017E":"z","\u1E93":"z","\u1E95":"z","\u01B6":"z","\u0225":"z","\u0240":"z","\u2C6C":"z","\uA763":"z"};
21428
21429    $document = $(document);
21430
21431    nextUid=(function() { var counter=1; return function() { return counter++; }; }());
21432
21433
21434    function reinsertElement(element) {
21435        var placeholder = $(document.createTextNode(''));
21436
21437        element.before(placeholder);
21438        placeholder.before(element);
21439        placeholder.remove();
21440    }
21441
21442    function stripDiacritics(str) {
21443        // Used 'uni range + named function' from http://jsperf.com/diacritics/18
21444        function match(a) {
21445            return DIACRITICS[a] || a;
21446        }
21447
21448        return str.replace(/[^\u0000-\u007E]/g, match);
21449    }
21450
21451    function indexOf(value, array) {
21452        var i = 0, l = array.length;
21453        for (; i < l; i = i + 1) {
21454            if (equal(value, array[i])) return i;
21455        }
21456        return -1;
21457    }
21458
21459    function measureScrollbar () {
21460        var $template = $( MEASURE_SCROLLBAR_TEMPLATE );
21461        $template.appendTo('body');
21462
21463        var dim = {
21464            width: $template.width() - $template[0].clientWidth,
21465            height: $template.height() - $template[0].clientHeight
21466        };
21467        $template.remove();
21468
21469        return dim;
21470    }
21471
21472    /**
21473     * Compares equality of a and b
21474     * @param a
21475     * @param b
21476     */
21477    function equal(a, b) {
21478        if (a === b) return true;
21479        if (a === undefined || b === undefined) return false;
21480        if (a === null || b === null) return false;
21481        // Check whether 'a' or 'b' is a string (primitive or object).
21482        // The concatenation of an empty string (+'') converts its argument to a string's primitive.
21483        if (a.constructor === String) return a+'' === b+''; // a+'' - in case 'a' is a String object
21484        if (b.constructor === String) return b+'' === a+''; // b+'' - in case 'b' is a String object
21485        return false;
21486    }
21487
21488    /**
21489     * Splits the string into an array of values, trimming each value. An empty array is returned for nulls or empty
21490     * strings
21491     * @param string
21492     * @param separator
21493     */
21494    function splitVal(string, separator) {
21495        var val, i, l;
21496        if (string === null || string.length < 1) return [];
21497        val = string.split(separator);
21498        for (i = 0, l = val.length; i < l; i = i + 1) val[i] = $.trim(val[i]);
21499        return val;
21500    }
21501
21502    function getSideBorderPadding(element) {
21503        return element.outerWidth(false) - element.width();
21504    }
21505
21506    function installKeyUpChangeEvent(element) {
21507        var key="keyup-change-value";
21508        element.on("keydown", function () {
21509            if ($.data(element, key) === undefined) {
21510                $.data(element, key, element.val());
21511            }
21512        });
21513        element.on("keyup", function () {
21514            var val= $.data(element, key);
21515            if (val !== undefined && element.val() !== val) {
21516                $.removeData(element, key);
21517                element.trigger("keyup-change");
21518            }
21519        });
21520    }
21521
21522    $document.on("mousemove", function (e) {
21523        lastMousePosition.x = e.pageX;
21524        lastMousePosition.y = e.pageY;
21525    });
21526
21527    /**
21528     * filters mouse events so an event is fired only if the mouse moved.
21529     *
21530     * filters out mouse events that occur when mouse is stationary but
21531     * the elements under the pointer are scrolled.
21532     */
21533    function installFilteredMouseMove(element) {
21534        element.on("mousemove", function (e) {
21535            var lastpos = lastMousePosition;
21536            if (lastpos === undefined || lastpos.x !== e.pageX || lastpos.y !== e.pageY) {
21537                $(e.target).trigger("mousemove-filtered", e);
21538            }
21539        });
21540    }
21541
21542    /**
21543     * Debounces a function. Returns a function that calls the original fn function only if no invocations have been made
21544     * within the last quietMillis milliseconds.
21545     *
21546     * @param quietMillis number of milliseconds to wait before invoking fn
21547     * @param fn function to be debounced
21548     * @param ctx object to be used as this reference within fn
21549     * @return debounced version of fn
21550     */
21551    function debounce(quietMillis, fn, ctx) {
21552        ctx = ctx || undefined;
21553        var timeout;
21554        return function () {
21555            var args = arguments;
21556            window.clearTimeout(timeout);
21557            timeout = window.setTimeout(function() {
21558                fn.apply(ctx, args);
21559            }, quietMillis);
21560        };
21561    }
21562
21563    function installDebouncedScroll(threshold, element) {
21564        var notify = debounce(threshold, function (e) { element.trigger("scroll-debounced", e);});
21565        element.on("scroll", function (e) {
21566            if (indexOf(e.target, element.get()) >= 0) notify(e);
21567        });
21568    }
21569
21570    function focus($el) {
21571        if ($el[0] === document.activeElement) return;
21572
21573        /* set the focus in a 0 timeout - that way the focus is set after the processing
21574            of the current event has finished - which seems like the only reliable way
21575            to set focus */
21576        window.setTimeout(function() {
21577            var el=$el[0], pos=$el.val().length, range;
21578
21579            $el.focus();
21580
21581            /* make sure el received focus so we do not error out when trying to manipulate the caret.
21582                sometimes modals or others listeners may steal it after its set */
21583            var isVisible = (el.offsetWidth > 0 || el.offsetHeight > 0);
21584            if (isVisible && el === document.activeElement) {
21585
21586                /* after the focus is set move the caret to the end, necessary when we val()
21587                    just before setting focus */
21588                if(el.setSelectionRange)
21589                {
21590                    el.setSelectionRange(pos, pos);
21591                }
21592                else if (el.createTextRange) {
21593                    range = el.createTextRange();
21594                    range.collapse(false);
21595                    range.select();
21596                }
21597            }
21598        }, 0);
21599    }
21600
21601    function getCursorInfo(el) {
21602        el = $(el)[0];
21603        var offset = 0;
21604        var length = 0;
21605        if ('selectionStart' in el) {
21606            offset = el.selectionStart;
21607            length = el.selectionEnd - offset;
21608        } else if ('selection' in document) {
21609            el.focus();
21610            var sel = document.selection.createRange();
21611            length = document.selection.createRange().text.length;
21612            sel.moveStart('character', -el.value.length);
21613            offset = sel.text.length - length;
21614        }
21615        return { offset: offset, length: length };
21616    }
21617
21618    function killEvent(event) {
21619        event.preventDefault();
21620        event.stopPropagation();
21621    }
21622    function killEventImmediately(event) {
21623        event.preventDefault();
21624        event.stopImmediatePropagation();
21625    }
21626
21627    function measureTextWidth(e) {
21628        if (!sizer){
21629            var style = e[0].currentStyle || window.getComputedStyle(e[0], null);
21630            sizer = $(document.createElement("div")).css({
21631                position: "absolute",
21632                left: "-10000px",
21633                top: "-10000px",
21634                display: "none",
21635                fontSize: style.fontSize,
21636                fontFamily: style.fontFamily,
21637                fontStyle: style.fontStyle,
21638                fontWeight: style.fontWeight,
21639                letterSpacing: style.letterSpacing,
21640                textTransform: style.textTransform,
21641                whiteSpace: "nowrap"
21642            });
21643            sizer.attr("class","select2-sizer");
21644            $("body").append(sizer);
21645        }
21646        sizer.text(e.val());
21647        return sizer.width();
21648    }
21649
21650    function syncCssClasses(dest, src, adapter) {
21651        var classes, replacements = [], adapted;
21652
21653        classes = dest.attr("class");
21654        if (classes) {
21655            classes = '' + classes; // for IE which returns object
21656            $(classes.split(" ")).each2(function() {
21657                if (this.indexOf("select2-") === 0) {
21658                    replacements.push(this);
21659                }
21660            });
21661        }
21662        classes = src.attr("class");
21663        if (classes) {
21664            classes = '' + classes; // for IE which returns object
21665            $(classes.split(" ")).each2(function() {
21666                if (this.indexOf("select2-") !== 0) {
21667                    adapted = adapter(this);
21668                    if (adapted) {
21669                        replacements.push(adapted);
21670                    }
21671                }
21672            });
21673        }
21674        dest.attr("class", replacements.join(" "));
21675    }
21676
21677
21678    function markMatch(text, term, markup, escapeMarkup) {
21679        var match=stripDiacritics(text.toUpperCase()).indexOf(stripDiacritics(term.toUpperCase())),
21680            tl=term.length;
21681
21682        if (match<0) {
21683            markup.push(escapeMarkup(text));
21684            return;
21685        }
21686
21687        markup.push(escapeMarkup(text.substring(0, match)));
21688        markup.push("<span class='select2-match'>");
21689        markup.push(escapeMarkup(text.substring(match, match + tl)));
21690        markup.push("</span>");
21691        markup.push(escapeMarkup(text.substring(match + tl, text.length)));
21692    }
21693
21694    function defaultEscapeMarkup(markup) {
21695        var replace_map = {
21696            '\\': '&#92;',
21697            '&': '&amp;',
21698            '<': '&lt;',
21699            '>': '&gt;',
21700            '"': '&quot;',
21701            "'": '&#39;',
21702            "/": '&#47;'
21703        };
21704
21705        return String(markup).replace(/[&<>"'\/\\]/g, function (match) {
21706            return replace_map[match];
21707        });
21708    }
21709
21710    /**
21711     * Produces an ajax-based query function
21712     *
21713     * @param options object containing configuration parameters
21714     * @param options.params parameter map for the transport ajax call, can contain such options as cache, jsonpCallback, etc. see $.ajax
21715     * @param options.transport function that will be used to execute the ajax request. must be compatible with parameters supported by $.ajax
21716     * @param options.url url for the data
21717     * @param options.data a function(searchTerm, pageNumber, context) that should return an object c
21717ontaining query string parameters for the above url.
21718     * @param options.dataType request data type: ajax, jsonp, other datatypes supported by jQuery's $.ajax function or the transport function if specified
21719     * @param options.quietMillis (optional) milliseconds to wait before making the ajaxRequest, helps debounce the ajax function if invoked too often
21720     * @param options.results a function(remoteData, pageNumber) that converts data returned form the remote request to the format expected by Select2.
21721     *      The expected format is an object containing the following keys:
21722     *      results array of objects that will be used as choices
21723     *      more (optional) boolean indicating whether there are more results available
21724     *      Example: {results:[{id:1, text:'Red'},{id:2, text:'Blue'}], more:true}
21725     */
21726    function ajax(options) {
21727        var timeout, // current scheduled but not yet executed request
21728            handler = null,
21729            quietMillis = options.quietMillis || 100,
21730            ajaxUrl = options.url,
21731            self = this;
21732
21733        return function (query) {
21734            window.clearTimeout(timeout);
21735            timeout = window.setTimeout(function () {
21736                var data = options.data, // ajax data function
21737                    url = ajaxUrl, // ajax url string or function
21738                    transport = options.transport || $.fn.select2.ajaxDefaults.transport,
21739                    // deprecated - to be removed in 4.0  - use params instead
21740                    deprecated = {
21741                        type: options.type || 'GET', // set type of request (GET or POST)
21742                        cache: options.cache || false,
21743                        jsonpCallback: options.jsonpCallback||undefined,
21744                        dataType: options.dataType||"json"
21745                    },
21746                    params = $.extend({}, $.fn.select2.ajaxDefaults.params, deprecated);
21747
21748                data = data ? data.call(self, query.term, query.page, query.context) : null;
21749                url = (typeof url === 'function') ? url.call(self, query.term, query.page, query.context) : url;
21750
21751                if (handler && typeof handler.abort === "function") { handler.abort(); }
21752
21753                if (options.params) {
21754                    if ($.isFunction(options.params)) {
21755                        $.extend(params, options.params.call(self));
21756                    } else {
21757                        $.extend(params, options.params);
21758                    }
21759                }
21760
21761                $.extend(params, {
21762                    url: url,
21763                    dataType: options.dataType,
21764                    data: data,
21765                    success: function (data) {
21766                        // TODO - replace query.page with query so users have access to term, page, etc.
21767                        var results = options.results(data, query.page);
21768                        query.callback(results);
21769                    }
21770                });
21771                handler = transport.call(self, params);
21772            }, quietMillis);
21773        };
21774    }
21775
21776    /**
21777     * Produces a query function that works with a local array
21778     *
21779     * @param options object containing configuration parameters. The options parameter can either be an array or an
21780     * object.
21781     *
21782     * If the array form is used it is assumed that it contains objects with 'id' and 'text' keys.
21783     *
21784     * If the object form is used it is assumed that it contains 'data' and 'text' keys. The 'data' key should contain
21785     * an array of objects that will be used as choices. These objects must contain at least an 'id' key. The 'text'
21786     * key can either be a String in which case it is expected that each element in the 'data' array has a key with the
21787     * value of 'text' which will be used to match choices. Alternatively, text can be a function(item) that can extract
21788     * the text.
21789     */
21790    function local(options) {
21791        var data = options, // data elements
21792            dataText,
21793            tmp,
21794            text = function (item) { return ""+item.text; }; // function used to retrieve the text portion of a data item that is matched against the search
21795
21796         if ($.isArray(data)) {
21797            tmp = data;
21798            data = { results: tmp };
21799        }
21800
21801         if ($.isFunction(data) === false) {
21802            tmp = data;
21803            data = function() { return tmp; };
21804        }
21805
21806        var dataItem = data();
21807        if (dataItem.text) {
21808            text = dataItem.text;
21809            // if text is not a function we assume it to be a key name
21810            if (!$.isFunction(text)) {
21811                dataText = dataItem.text; // we need to store this in a separate variable because in the next step data gets reset and data.text is no longer available
21812                text = function (item) { return item[dataText]; };
21813            }
21814        }
21815
21816        return function (query) {
21817            var t = query.term, filtered = { results: [] }, process;
21818            if (t === "") {
21819                query.callback(data());
21820                return;
21821            }
21822
21823            process = function(datum, collection) {
21824                var group, attr;
21825                datum = datum[0];
21826                if (datum.children) {
21827                    group = {};
21828                    for (attr in datum) {
21829                        if (datum.hasOwnProperty(attr)) group[attr]=datum[attr];
21830                    }
21831                    group.children=[];
21832                    $(datum.children).each2(function(i, childDatum) { process(childDatum, group.children); });
21833                    if (group.children.length || query.matcher(t, text(group), datum)) {
21834                        collection.push(group);
21835                    }
21836                } else {
21837                    if (query.matcher(t, text(datum), datum)) {
21838                        collection.push(datum);
21839                    }
21840                }
21841            };
21842
21843            $(data().results).each2(function(i, datum) { process(datum, filtered.results); });
21844            query.callback(filtered);
21845        };
21846    }
21847
21848    // TODO javadoc
21849    function tags(data) {
21850        var isFunc = $.isFunction(data);
21851        return function (query) {
21852            var t = query.term, filtered = {results: []};
21853            var result = isFunc ? data(query) : data;
21854            if ($.isArray(result)) {
21855                $(result).each(function () {
21856                    var isObject = this.text !== undefined,
21857                        text = isObject ? this.text : this;
21858                    if (t === "" || query.matcher(t, text)) {
21859                        filtered.results.push(isObject ? this : {id: this, text: this});
21860                    }
21861                });
21862                query.callback(filtered);
21863            }
21864        };
21865    }
21866
21867    /**
21868     * Checks if the formatter function should be used.
21869     *
21870     * Throws an error if it is not a function. Returns true if it should be used,
21871     * false if no formatting should be performed.
21872     *
21873     * @param formatter
21874     */
21875    function checkFormatter(formatter, formatterName) {
21876        if ($.isFunction(formatter)) return true;
21877        if (!formatter) return false;
21878        if (typeof(formatter) === 'string') return true;
21879        throw new Error(formatterName +" must be a string, function, or falsy value");
21880    }
21881
21882    function evaluate(val) {
21883        if ($.isFunction(val)) {
21884            var args = Array.prototype.slice.call(arguments, 1);
21885            return val.apply(null, args);
21886        }
21887        return val;
21888    }
21889
21890    function countResults(results) {
21891        var count = 0;
21892        $.each(results, function(i, item) {
21893            if (item.children) {
21894                count += countResults(item.children);
21895            } else {
21896                count++;
21897            }
21898        });
21899        return count;
21900    }
21901
21902    /**
21903     * Default tokenizer. This function uses breaks the input on substring match of any string from the
21904     * opts.tokenSeparators array and uses opts.createSearchChoice to create the choice object. Both of those
21905     * two options have to be defined in order for the tokenizer to work.
21906     *
21907     * @param input text user has typed so far or pasted into the search field
21908     * @param selection currently selected choices
21909     * @param selectCallback function(choice) callback tho add the choice to selection
21910     * @param opts select2's opts
21911     * @return undefined/null to leave the current input unchanged, or a string to change the input to the returned value
21912     */
21913    function defaultTokenizer(input, selection, selectCallback, opts) {
21914        var original = input, // store the original so we can compare and know if we need to tell the search to update its text
21915            dupe = false, // check for whether a token we extracted represents a duplicate selected choice
21916            token, // token
21917            index, // position at which the separator was found
21918            i, l, // looping variables
21919            separator; // the matched separator
21920
21921        if (!opts.createSearchChoice || !opts.tokenSeparators || opts.tokenSeparators.length < 1) return undefined;
21922
21923        while (true) {
21924            index = -1;
21925
21926            for (i = 0, l = opts.tokenSeparators.length; i < l; i++) {
21927                separator = opts.tokenSeparators[i];
21928                index = input.indexOf(separator);
21929                if (index >= 0) break;
21930            }
21931
21932            if (index < 0) break; // did not find any token separator in the input string, bail
21933
21934            token = input.substring(0, index);
21935            input = input.substring(index + separator.length);
21936
21937            if (token.length > 0) {
21938                token = opts.createSearchChoice.call(this, token, selection);
21939                if (token !== undefined && token !== null && opts.id(token) !== undefined && opts.id(token) !== null) {
21940                    dupe = false;
21941                    for (i = 0, l = selection.length; i < l; i++) {
21942                        if (equal(opts.id(token), opts.id(selection[i]))) {
21943                            dupe = true; break;
21944                        }
21945                    }
21946
21947                    if (!dupe) selectCallback(token);
21948                }
21949            }
21950        }
21951
21952        if (original!==input) return input;
21953    }
21954
21955    function cleanupJQueryElements() {
21956        var self = this;
21957
21958        Array.prototype.forEach.call(arguments, function (element) {
21959            self[element].remove();
21960            self[element] = null;
21961        });
21962    }
21963
21964    /**
21965     * Creates a new class
21966     *
21967     * @param superClass
21968     * @param methods
21969     */
21970    function clazz(SuperClass, methods) {
21971        var constructor = function () {};
21972        constructor.prototype = new SuperClass;
21973        constructor.prototype.constructor = constructor;
21974        constructor.prototype.parent = SuperClass.prototype;
21975        constructor.prototype = $.extend(constructor.prototype, methods);
21976        return constructor;
21977    }
21978
21979    AbstractSelect2 = clazz(Object, {
21980
21981        // abstract
21982        bind: function (func) {
21983            var self = this;
21984            return function () {
21985                func.apply(self, arguments);
21986            };
21987        },
21988
21989        // abstract
21990        init: function (opts) {
21991            var results, search, resultsSelector = ".select2-results";
21992
21993            // prepare options
21994            this.opts = opts = this.prepareOpts(opts);
21995
21996            this.id=opts.id;
21997
21998            // destroy if called on an existing component
21999            if (opts.element.data("select2") !== undefined &&
22000                opts.element.data("select2") !== null) {
22001                opts.element.data("select2").destroy();
22002            }
22003
22004            this.container = this.createContainer();
22005
22006            this.liveRegion = $("<span>", {
22007                    role: "status",
22008                    "aria-live": "polite"
22009                })
22010                .addClass("select2-hidden-accessible")
22011                .appendTo(document.body);
22012
22013            this.containerId="s2id_"+(opts.element.attr("id") || "autogen"+nextUid());
22014            this.containerEventName= this.containerId
22015                .replace(/([.])/g, '_')
22016                .replace(/([;&,\-\.\+\*\~':"\!\^#$%@\[\]\(\)=>\|])/g, '\\$1');
22017            this.container.attr("id", this.containerId);
22018
22019            this.container.attr("title", opts.element.attr("title"));
22020
22021            this.body = $("body");
22022
22023            syncCssClasses(this.container, this.opts.element, this.opts.adaptContainerCssClass);
22024
22025            this.container.attr("style", opts.element.attr("style"));
22026            this.container.css(evaluate(opts.containerCss));
22027            this.container.addClass(evaluate(opts.containerCssClass));
22028
22029            this.elementTabIndex = this.opts.element.attr("tabindex");
22030
22031            // swap container for the element
22032            this.opts.element
22033                .data("select2", this)
22034                .attr("tabindex", "-1")
22035                .before(this.container)
22036                .on("click.select2", killEvent); // do not leak click events
22037
22038            this.container.data("select2", this);
22039
22040            this.dropdown = this.container.find(".select2-drop");
22041
22042            syncCssClasses(this.dropdown, this.opts.element, this.opts.adaptDropdownCssClass);
22043
22044            this.dropdown.addClass(evaluate(opts.dropdownCssClass));
22045            this.dropdown.data("select2", this);
22046            this.dropdown.on("click", killEvent);
22047
22048            this.results = results = this.container.find(resultsSelector);
22049            this.search = search = this.container.find("input.select2-input");
22050
22051            this.queryCount = 0;
22052            this.resultsPage = 0;
22053            this.context = null;
22054
22055            // initialize the container
22056            this.initContainer();
22057
22058            this.container.on("click", killEvent);
22059
22060            installFilteredMouseMove(this.results);
22061
22062            this.dropdown.on("mousemove-filtered", resultsSelector, this.bind(this.highlightUnderEvent));
22063            this.dropdown.on("touchstart touchmove touchend", resultsSelector, this.bind(function (event) {
22064                this._touchEvent = true;
22065                this.highlightUnderEvent(event);
22066            }));
22067            this.dropdown.on("touchmove", resultsSelector, this.bind(this.touchMoved));
22068            this.dropdown.on("touchstart touchend", resultsSelector, this.bind(this.clearTouchMoved));
22069
22070            // Waiting for a click event on touch devices to select option and hide dropdown
22071            // otherwise click will be triggered on an underlying element
22072            this.dropdown.on('click', this.bind(function (event) {
22073                if (this._touchEvent) {
22074                    this._touchEvent = false;
22075                    this.selectHighlighted();
22076                }
22077            }));
22078
22079            installDebouncedScroll(80, this.results);
22080            this.dropdown.on("scroll-debounced", resultsSelector, this.bind(this.loadMoreIfNeeded));
22081
22082            // do not propagate change event from the search field out of the component
22083            $(this.container).on("change", ".select2-input", function(e) {e.stopPropagation();});
22084            $(this.dropdown).on("change", ".select2-input", function(e) {e.stopPropagation();});
22085
22086            // if jquery.mousewheel plugin is installed we can prevent out-of-bounds scrolling of results via mousewheel
22087            if ($.fn.mousewheel) {
22088                results.mousewheel(function (e, delta, deltaX, deltaY) {
22089                    var top = results.scrollTop();
22090                    if (deltaY > 0 && top - deltaY <= 0) {
22091                        results.scrollTop(0);
22092                        killEvent(e);
22093                    } else if (deltaY < 0 && results.get(0).scrollHeight - results.scrollTop() + deltaY <= results.height()) {
22094                        results.scrollTop(results.get(0).scrollHeight - results.height());
22095                        killEvent(e);
22096                    }
22097                });
22098            }
22099
22100            installKeyUpChangeEvent(search);
22101            search.on("keyup-change input paste", this.bind(this.updateResults));
22102            search.on("focus", function () { search.addClass("select2-focused"); });
22103            search.on("blur", function () { search.removeClass("select2-focused");});
22104
22105            this.dropdown.on("mouseup", resultsSelector, this.bind(function (e) {
22106                if ($(e.target).closest(".select2-result-selectable").length > 0) {
22107                    this.highlightUnderEvent(e);
22108                    this.selectHighlighted(e);
22109                }
22110            }));
22111
22112            // trap all mouse events from leaving the dropdown. sometimes there may be a modal that is listening
22113            // for mouse events outside of itself so it can close itself. since the dropdown is now outside the select2's
22114            // dom it will trigger the popup close, which is not what we want
22115            // focusin can cause focus wars between modals and select2 since the dropdown is outside the modal.
22116            this.dropdown.on("click mouseup mousedown touchstart touchend focusin", function (e) { e.stopPropagation(); });
22117
22118            this.nextSearchTerm = undefined;
22119
22120            if ($.isFunction(this.opts.initSelection)) {
22121                // initialize selection based on the current value of the source element
22122                this.initSelection();
22123
22124                // if the user has provided a function that can set selection based on the value of the source element
22125                // we monitor the change event on the element and trigger it, allowing for two way synchronization
22126                this.monitorSource();
22127            }
22128
22129            if (opts.maximumInputLength !== null) {
22130                this.search.attr("maxlength", opts.maximumInputLength);
22131            }
22132
22133            var disabled = opts.element.prop("disabled");
22134            if (disabled === undefined) disabled = false;
22135            this.enable(!disabled);
22136
22137            var readonly = opts.element.prop("readonly");
22138            if (readonly === undefined) readonly = false;
22139            this.readonly(readonly);
22140
22141            // Calculate size of scrollbar
22142            scrollBarDimensions = scrollBarDimensions || measureScrollbar();
22143
22144            this.autofocus = opts.element.prop("autofocus");
22145            opts.element.prop("autofocus", false);
22146            if (this.autofocus) this.focus();
22147
22148            this.search.attr("placeholder", opts.searchInputPlaceholder);
22149        },
22150
22151        // abstract
22152        destroy: function () {
22153            var element=this.opts.element, select2 = element.data("select2");
22154
22155            this.close();
22156
22157            if (this.propertyObserver) {
22158                this.propertyObserver.disconnect();
22159                this.propertyObserver = null;
22160            }
22161
22162            if (select2 !== undefined) {
22163                select2.container.remove();
22164                select2.liveRegion.remove();
22165                select2.dropdown.remove();
22166                element
22167                    .removeClass("select2-offscreen")
22168                    .removeData("select2")
22169                    .off(".select2")
22170                    .prop("autofocus", this.autofocus || false);
22171                if (this.elementTabIndex) {
22172                    element.attr({tabindex: this.elementTabIndex});
22173                } else {
22174                    element.removeAttr("tabindex");
22175                }
22176                element.show();
22177            }
22178
22179            cleanupJQueryElements.call(this,
22180                "container",
22181                "liveRegion",
22182                "dropdown",
22183                "results",
22184                "search"
22185            );
22186        },
22187
22188        // abstract
22189        optionToData: function(element) {
22190            if (element.is("option")) {
22191                return {
22192                    id:element.prop("value"),
22193                    text:element.text(),
22194                    element: element.get(),
22195                    css: element.attr("class"),
22196                    disabled: element.prop("disabled"),
22197                    locked: equal(element.attr("locked"), "locked") || equal(element.data("locked"), true)
22198                };
22199            } else if (element.is("optgroup")) {
22200                return {
22201                    text:element.attr("label"),
22202                    children:[],
22203                    element: element.get(),
22204                    css: element.attr("class")
22205                };
22206            }
22207        },
22208
22209        // abstract
22210        prepareOpts: function (opts) {
22211            var element, select, idKey, ajaxUrl, self = this;
22212
22213            element = opts.element;
22214
22215            if (element.get(0).tagName.toLowerCase() === "select") {
22216                this.select = select = opts.element;
22217            }
22218
22219            if (select) {
22220                // these options are not allowed when attached to a select because they are picked up off the element itself
22221                $.each(["id", "multiple", "ajax", "query", "createSearchChoice", "initSelection", "data", "tags"], function () {
22222                    if (this in opts) {
22223                        throw new Error("Option '" + this + "' is not allowed for Select2 when attached to a <select> element.");
22224                    }
22225                });
22226            }
22227
22228            opts = $.extend({}, {
22229                populateResults: function(container, results, query
22229) {
22230                    var populate, id=this.opts.id, liveRegion=this.liveRegion;
22231
22232                    populate=function(results, container, depth) {
22233
22234                        var i, l, result, selectable, disabled, compound, node, label, innerContainer, formatted;
22235
22236                        results = opts.sortResults(results, container, query);
22237
22238                        for (i = 0, l = results.length; i < l; i = i + 1) {
22239
22240                            result=results[i];
22241
22242                            disabled = (result.disabled === true);
22243                            selectable = (!disabled) && (id(result) !== undefined);
22244
22245                            compound=result.children && result.children.length > 0;
22246
22247                            node=$("<li></li>");
22248                            node.addClass("select2-results-dept-"+depth);
22249                            node.addClass("select2-result");
22250                            node.addClass(selectable ? "select2-result-selectable" : "select2-result-unselectable");
22251                            if (disabled) { node.addClass("select2-disabled"); }
22252                            if (compound) { node.addClass("select2-result-with-children"); }
22253                            node.addClass(self.opts.formatResultCssClass(result));
22254                            node.attr("role", "presentation");
22255
22256                            label=$(document.createElement("div"));
22257                            label.addClass("select2-result-label");
22258                            label.attr("id", "select2-result-label-" + nextUid());
22259                            label.attr("role", "option");
22260
22261                            formatted=opts.formatResult(result, label, query, self.opts.escapeMarkup);
22262                            if (formatted!==undefined) {
22263                                label.html(formatted);
22264                                node.append(label);
22265                            }
22266
22267
22268                            if (compound) {
22269
22270                                innerContainer=$("<ul></ul>");
22271                                innerContainer.addClass("select2-result-sub");
22272                                populate(result.children, innerContainer, depth+1);
22273                                node.append(innerContainer);
22274                            }
22275
22276                            node.data("select2-data", result);
22277                            container.append(node);
22278                        }
22279
22280                        liveRegion.text(opts.formatMatches(results.length));
22281                    };
22282
22283                    populate(results, container, 0);
22284                }
22285            }, $.fn.select2.defaults, opts);
22286
22287            if (typeof(opts.id) !== "function") {
22288                idKey = opts.id;
22289                opts.id = function (e) { return e[idKey]; };
22290            }
22291
22292            if ($.isArray(opts.element.data("select2Tags"))) {
22293                if ("tags" in opts) {
22294                    throw "tags specified as both an attribute 'data-select2-tags' and in options of Select2 " + opts.element.attr("id");
22295                }
22296                opts.tags=opts.element.data("select2Tags");
22297            }
22298
22299            if (select) {
22300                opts.query = this.bind(function (query) {
22301                    var data = { results: [], more: false },
22302                        term = query.term,
22303                        children, placeholderOption, process;
22304
22305                    process=function(element, collection) {
22306                        var group;
22307                        if (element.is("option")) {
22308                            if (query.matcher(term, element.text(), element)) {
22309                                collection.push(self.optionToData(element));
22310                            }
22311                        } else if (element.is("optgroup")) {
22312                            group=self.optionToData(element);
22313                            element.children().each2(function(i, elm) { process(elm, group.children); });
22314                            if (group.children.length>0) {
22315                                collection.push(group);
22316                            }
22317                        }
22318                    };
22319
22320                    children=element.children();
22321
22322                    // ignore the placeholder option if there is one
22323                    if (this.getPlaceholder() !== undefined && children.length > 0) {
22324                        placeholderOption = this.getPlaceholderOption();
22325                        if (placeholderOption) {
22326                            children=children.not(placeholderOption);
22327                        }
22328                    }
22329
22330                    children.each2(function(i, elm) { process(elm, data.results); });
22331
22332                    query.callback(data);
22333                });
22334                // this is needed because inside val() we construct choices from options and there id is hardcoded
22335                opts.id=function(e) { return e.id; };
22336            } else {
22337                if (!("query" in opts)) {
22338
22339                    if ("ajax" in opts) {
22340                        ajaxUrl = opts.element.data("ajax-url");
22341                        if (ajaxUrl && ajaxUrl.length > 0) {
22342                            opts.ajax.url = ajaxUrl;
22343                        }
22344                        opts.query = ajax.call(opts.element, opts.ajax);
22345                    } else if ("data" in opts) {
22346                        opts.query = local(opts.data);
22347                    } else if ("tags" in opts) {
22348                        opts.query = tags(opts.tags);
22349                        if (opts.createSearchChoice === undefined) {
22350                            opts.createSearchChoice = function (term) { return {id: $.trim(term), text: $.trim(term)}; };
22351                        }
22352                        if (opts.initSelection === undefined) {
22353                            opts.initSelection = function (element, callback) {
22354                                var data = [];
22355                                $(splitVal(element.val(), opts.separator)).each(function () {
22356                                    var obj = { id: this, text: this },
22357                                        tags = opts.tags;
22358                                    if ($.isFunction(tags)) tags=tags();
22359                                    $(tags).each(function() { if (equal(this.id, obj.id)) { obj = this; return false; } });
22360                                    data.push(obj);
22361                                });
22362
22363                                callback(data);
22364                            };
22365                        }
22366                    }
22367                }
22368            }
22369            if (typeof(opts.query) !== "function") {
22370                throw "query function not defined for Select2 " + opts.element.attr("id");
22371            }
22372
22373            if (opts.createSearchChoicePosition === 'top') {
22374                opts.createSearchChoicePosition = function(list, item) { list.unshift(item); };
22375            }
22376            else if (opts.createSearchChoicePosition === 'bottom') {
22377                opts.createSearchChoicePosition = function(list, item) { list.push(item); };
22378            }
22379            else if (typeof(opts.createSearchChoicePosition) !== "function")  {
22380                throw "invalid createSearchChoicePosition option must be 'top', 'bottom' or a custom function";
22381            }
22382
22383            return opts;
22384        },
22385
22386        /**
22387         * Monitor the original element for changes and update select2 accordingly
22388         */
22389        // abstract
22390        monitorSource: function () {
22391            var el = this.opts.element, sync, observer;
22392
22393            el.on("change.select2", this.bind(function (e) {
22394                if (this.opts.element.data("select2-change-triggered") !== true) {
22395                    this.initSelection();
22396                }
22397            }));
22398
22399            sync = this.bind(function () {
22400
22401                // sync enabled state
22402                var disabled = el.prop("disabled");
22403                if (disabled === undefined) disabled = false;
22404                this.enable(!disabled);
22405
22406                var readonly = el.prop("readonly");
22407                if (readonly === undefined) readonly = false;
22408                this.readonly(readonly);
22409
22410                syncCssClasses(this.container, this.opts.element, this.opts.adaptContainerCssClass);
22411                this.container.addClass(evaluate(this.opts.containerCssClass));
22412
22413                syncCssClasses(this.dropdown, this.opts.element, this.opts.adaptDropdownCssClass);
22414                this.dropdown.addClass(evaluate(this.opts.dropdownCssClass));
22415
22416            });
22417
22418            // IE8-10 (IE9/10 won't fire propertyChange via attachEventListener)
22419            if (el.length && el[0].attachEvent) {
22420                el.each(function() {
22421                    this.attachEvent("onpropertychange", sync);
22422                });
22423            }
22424
22425            // safari, chrome, firefox, IE11
22426            observer = window.MutationObserver || window.WebKitMutationObserver|| window.MozMutationObserver;
22427            if (observer !== undefined) {
22428                if (this.propertyObserver) { delete this.propertyObserver; this.propertyObserver = null; }
22429                this.propertyObserver = new observer(function (mutations) {
22430                    mutations.forEach(sync);
22431                });
22432                this.propertyObserver.observe(el.get(0), { attributes:true, subtree:false });
22433            }
22434        },
22435
22436        // abstract
22437        triggerSelect: function(data) {
22438            var evt = $.Event("select2-selecting", { val: this.id(data), object: data });
22439            this.opts.element.trigger(evt);
22440            return !evt.isDefaultPrevented();
22441        },
22442
22443        /**
22444         * Triggers the change event on the source element
22445         */
22446        // abstract
22447        triggerChange: function (details) {
22448
22449            details = details || {};
22450            details= $.extend({}, details, { type: "change", val: this.val() });
22451            // prevents recursive triggering
22452            this.opts.element.data("select2-change-triggered", true);
22453            this.opts.element.trigger(details);
22454            this.opts.element.data("select2-change-triggered", false);
22455
22456            // some validation frameworks ignore the change event and listen instead to keyup, click for selects
22457            // so here we trigger the click event manually
22458            this.opts.element.click();
22459
22460            // ValidationEngine ignores the change event and listens instead to blur
22461            // so here we trigger the blur event manually if so desired
22462            if (this.opts.blurOnChange)
22463                this.opts.element.blur();
22464        },
22465
22466        //abstract
22467        isInterfaceEnabled: function()
22468        {
22469            return this.enabledInterface === true;
22470        },
22471
22472        // abstract
22473        enableInterface: function() {
22474            var enabled = this._enabled && !this._readonly,
22475                disabled = !enabled;
22476
22477            if (enabled === this.enabledInterface) return false;
22478
22479            this.container.toggleClass("select2-container-disabled", disabled);
22480            this.close();
22481            this.enabledInterface = enabled;
22482
22483            return true;
22484        },
22485
22486        // abstract
22487        enable: function(enabled) {
22488            if (enabled === undefined) enabled = true;
22489            if (this._enabled === enabled) return;
22490            this._enabled = enabled;
22491
22492            this.opts.element.prop("disabled", !enabled);
22493            this.enableInterface();
22494        },
22495
22496        // abstract
22497        disable: function() {
22498            this.enable(false);
22499        },
22500
22501        // abstract
22502        readonly: function(enabled) {
22503            if (enabled === undefined) enabled = false;
22504            if (this._readonly === enabled) return;
22505            this._readonly = enabled;
22506
22507            this.opts.element.prop("readonly", enabled);
22508            this.enableInterface();
22509        },
22510
22511        // abstract
22512        opened: function () {
22513            return this.container.hasClass("select2-dropdown-open");
22514        },
22515
22516        // abstract
22517        positionDropdown: function() {
22518            var $dropdown = this.dropdown,
22519                offset = this.container.offset(),
22520                height = this.container.outerHeight(false),
22521                width = this.container.outerWidth(false),
22522                dropHeight = $dropdown.outerHeight(false),
22523                $window = $(window),
22524                windowWidth = $window.width(),
22525                windowHeight = $window.height(),
22526                viewPortRight = $window.scrollLeft() + windowWidth,
22527                viewportBottom = $window.scrollTop() + windowHeight,
22528                dropTop = offset.top + height,
22529                dropLeft = offset.left,
22530                enoughRoomBelow = dropTop + dropHeight <= viewportBottom,
22531                enoughRoomAbove = (offset.top - dropHeight) >= $window.scrollTop(),
22532                dropWidth = $dropdown.outerWidth(false),
22533                enoughRoomOnRight = dropLeft + dropWidth <= viewPortRight,
22534                aboveNow = $dropdown.hasClass("select2-drop-above"),
22535                bodyOffset,
22536                above,
22537                changeDirection,
22538                css,
22539                resultsListNode;
22540
22541            // always prefer the current above/below alignment, unless there is not enough room
22542            if (aboveNow) {
22543                above = true;
22544                if (!enoughRoomAbove && enoughRoomBelow) {
22545                    changeDirection = true;
22546                    above = false;
22547                }
22548            } else {
22549                above = false;
22550                if (!enoughRoomBelow && enoughRoomAbove) {
22551                    changeDirection = true;
22552                    above = true;
22553                }
22554            }
22555
22556            //if we are changing direction we need to get positions when dropdown is hidden;
22557            if (changeDirection) {
22558                $dropdown.hide();
22559                offset = this.container.offset();
22560                height = this.container.outerHeight(false);
22561                width = this.container.outerWidth(false);
22562                dropHeight = $dropdown.outerHeight(false);
22563                viewPortRight = $window.scrollLeft() + windowWidth;
22564                viewportBottom = $window.scrollTop() + windowHeight;
22565                dropTop = offset.top + height;
22566                dropLeft = offset.left;
22567                dropWidth = $dropdown.outerWidth(false);
22568                enoughRoomOnRight = dropLeft + dropWidth <= viewPortRight;
22569                $dropdown.show();
22570
22571                // fix so the cursor does not move to the left within the search-textbox in IE
22572                this.focusSearch();
22573            }
22574
22575            if (this.opts.dropdownAutoWidth) {
22576                resultsListNode = $('.select2-results', $dropdown)[0];
22577                $dropdown.addClass('select2-drop-auto-width');
22578                $dropdown.css('width', '');
22579                // Add scrollbar width to dropdown if vertical scrollbar is present
22580                dropWidth = $dropdown.outerWidth(false) + (resultsListNode.scrollHeight === resultsListNode.clientHeight ? 0 : scrollBarDimensions.width);
22581                dropWidth > width ? width = dropWidth : dropWidth = width;
22582                dropHeight = $dropdown.outerHeight(false);
22583                enoughRoomOnRight = dropLeft + dropWidth <= viewPortRight;
22584            }
22585            else {
22586                this.container.removeClass('select2-drop-auto-width');
22587            }
22588
22589            //console.log("below/ droptop:", dropTop, "dropHeight", dropHeight, "sum", (dropTop+dropHeight)+" viewport bottom", viewportBottom, "enough?", enoughRoomBelow);
22590            //console.log("above/ offset.top", offset.top, "dropHeight", dropHeight, "top", (offset.top-dropHeight), "scrollTop", this.body.scrollTop(), "enough?", enoughRoomAbove);
22591
22592            // fix positioning when body has an offset and is not position: static
22593            if (this.body.css('position') !== 'static') {
22594                bodyOffset = this.body.offset();
22595                dropTop -= bodyOffset.top;
22596                dropLeft -= bodyOffset.left;
22597            }
22598
22599            if (!enoughRoomOnRight) {
22600                dropLeft = offset.left + this.container.outerWidth(false) - dropWidth;
22601            }
22602
22603            css =  {
22604                left: dropLeft,
22605                width: width
22606            };
22607
22608            if (above) {
22609                css.top = offset.top - dropHeight;
22610                css.bottom = 'auto';
22611                this.container.addClass("select2-drop-above");
22612                $dropdown.addClass("select2-drop-above");
22613            }
22614            else {
22615                css.top = dropTop;
22616                css.bottom = 'auto';
22617                this.container.removeClass("select2-drop-above");
22618                $dropdown.removeClass("select2-drop-above");
22619            }
22620            css = $.extend(css, evaluate(this.opts.dropdownCss));
22621
22622            $dropdown.css(css);
22623        },
22624
22625        // abstract
22626        shouldOpen: function() {
22627            var event;
22628
22629            if (this.opened()) return false;
22630
22631            if (this._enabled === false || this._readonly === true) return false;
22632
22633            event = $.Event("select2-opening");
22634            this.opts.element.trigger(event);
22635            return !event.isDefaultPrevented();
22636        },
22637
22638        // abstract
22639        clearDropdownAlignmentPreference: function() {
22640            // clear the classes used to figure out the preference of where the dropdown should be opened
22641            this.container.removeClass("select2-drop-above");
22642            this.dropdown.removeClass("select2-drop-above");
22643        },
22644
22645        /**
22646         * Opens the dropdown
22647         *
22648         * @return {Boolean} whether or not dropdown was opened. This method will return false if, for example,
22649         * the dropdown is already open, or if the 'open' event listener on the element called preventDefault().
22650         */
22651        // abstract
22652        open: function () {
22653
22654            if (!this.shouldOpen()) return false;
22655
22656            this.opening();
22657
22658            return true;
22659        },
22660
22661        /**
22662         * Performs the opening of the dropdown
22663         */
22664        // abstract
22665        opening: function() {
22666            var cid = this.containerEventName,
22667                scroll = "scroll." + cid,
22668                resize = "resize."+cid,
22669                orient = "orientationchange."+cid,
22670                mask;
22671
22672            this.container.addClass("select2-dropdown-open").addClass("select2-container-active");
22673
22674            this.clearDropdownAlignmentPreference();
22675
22676            if(this.dropdown[0] !== this.body.children().last()[0]) {
22677                this.dropdown.detach().appendTo(this.body);
22678            }
22679
22680            // create the dropdown mask if doesn't already exist
22681            mask = $("#select2-drop-mask");
22682            if (mask.length == 0) {
22683                mask = $(document.createElement("div"));
22684                mask.attr("id","select2-drop-mask").attr("class","select2-drop-mask");
22685                mask.hide();
22686                mask.appendTo(this.body);
22687                mask.on("mousedown touchstart click", function (e) {
22688                    // Prevent IE from generating a click event on the body
22689                    reinsertElement(mask);
22690
22691                    var dropdown = $("#select2-drop"), self;
22692                    if (dropdown.length > 0) {
22693                        self=dropdown.data("select2");
22694                        if (self.opts.selectOnBlur) {
22695                            self.selectHighlighted({noFocus: true});
22696                        }
22697                        self.close();
22698                        e.preventDefault();
22699                        e.stopPropagation();
22700                    }
22701                });
22702            }
22703
22704            // ensure the mask is always right before the dropdown
22705            if (this.dropdown.prev()[0] !== mask[0]) {
22706                this.dropdown.before(mask);
22707            }
22708
22709            // move the global id to the correct dropdown
22710            $("#select2-drop").removeAttr("id");
22711            this.dropdown.attr("id", "select2-drop");
22712
22713            // show the elements
22714            mask.show();
22715
22716            this.positionDropdown();
22717            this.dropdown.show();
22718            this.positionDropdown();
22719
22720            this.dropdown.addClass("select2-drop-active");
22721
22722            // attach listeners to events that can change the position of the container and thus require
22723            // the position of the dropdown to be updated as well so it does not come unglued from the container
22724            var that = this;
22725            this.container.parents().add(window).each(function () {
22726                $(this).on(resize+" "+scroll+" "+orient, function (e) {
22727                    if (that.opened()) that.positionDropdown();
22728                });
22729            });
22730
22731
22732        },
22733
22734        // abstract
22735        close: function () {
22736            if (!this.opened()) return;
22737
22738            var cid = this.containerEventName,
22739                scroll = "scroll." + cid,
22740                resize = "resize."+cid,
22741                orient = "orientationchange."+cid;
22742
22743            // unbind event listeners
22744            this.container.parents().add(window).each(function () { $(this).off(scroll).off(resize).off(orient); });
22745
22746            this.clearDropdownAlignmentPreference();
22747
22748            $("#select2-drop-mask").hide();
22749            this.dropdown.removeAttr("id"); // only the active dropdown has the select2-drop id
22750            this.dropdown.hide();
22751            this.container.removeClass("select2-dropdown-open").removeClass("select2-container-active");
22752            this.results.empty();
22753
22754
22755            this.clearSearch();
22756            this.search.removeClass("select2-active");
22757            this.opts.element.trigger($.Event("select2-close"));
22758        },
22759
22760        /**
22761         * Opens control, sets input value, and updates results.
22762         */
22763        // abstract
22764        externalSearch: function (term) {
22765            this.open();
22766            this.search.val(term);
22767            this.updateResults(false);
22768        },
22769
22770        // abstract
22771        clearSearch: function () {
22772
22773        },
22774
22775        //abstract
22776        getMaximumSelectionSize: function() {
22777            return evaluate(this.opts.maximumSelectionSize);
22778        },
22779
22780        // abstract
22781        ensureHighlightVisible: function () {
22782            var results = this.results, children, index, child, hb, rb, y, more;
22783
22784            index = this.highlight();
22785
22786            if (index < 0) return;
22787
22788            if (index == 0) {
22789
22790                // if the first element is highlighted scroll all the way to the top,
22791                // that way any unselectable headers above it will also be scrolled
22792                // into view
22793
22794                results.scrollTop(0);
22795                return;
22796            }
22797
22798            children = this.findHighlightableChoices().find('.select2-result-label');
22799
22800            child = $(children[index]);
22801
22802            hb = child.offset().top + child.outerHeight(true);
22803
22804            // if this is the last child lets also make sure select2-more-results is visible
22805            if (index === children.length - 1) {
22806                more = results.find("li.select2-more-results");
22807                if (more.length > 0) {
22808                    hb = more.offset().top + more.outerHeight(true);
22809                }
22810            }
22811
22812            rb = results.offset().top + results.outerHeight(true);
22813            if (hb > rb) {
22814                results.scrollTop(results.scrollTop() + (hb - rb));
22815            }
22816            y = child.offset().top - results.offset().top;
22817
22818            // make sure the top of the element is visible
22819            if (y < 0 && child.css('display') != 'none' ) {
22820                results.scrollTop(results.scrollTop() + y); // y is negative
22821            }
22822        },
22823
22824        // abstract
22825        findHighlightableChoices: function() {
22826            return this.results.find(".select2-result-selectable:not(.select2-disabled):not(.select2-selected)");
22827        },
22828
22829        // abstract
22830        moveHighlight: function (delta) {
22831            var choices = this.findHighlightableChoices(),
22832                index = this.highlight();
22833
22834            while (index > -1 && index < choices.length) {
22835                index += delta;
22836                var choice = $(choices[index]);
22837                if (choice.hasClass("select2-result-selectable") && !c
22837hoice.hasClass("select2-disabled") && !choice.hasClass("select2-selected")) {
22838                    this.highlight(index);
22839                    break;
22840                }
22841            }
22842        },
22843
22844        // abstract
22845        highlight: function (index) {
22846            var choices = this.findHighlightableChoices(),
22847                choice,
22848                data;
22849
22850            if (arguments.length === 0) {
22851                return indexOf(choices.filter(".select2-highlighted")[0], choices.get());
22852            }
22853
22854            if (index >= choices.length) index = choices.length - 1;
22855            if (index < 0) index = 0;
22856
22857            this.removeHighlight();
22858
22859            choice = $(choices[index]);
22860            choice.addClass("select2-highlighted");
22861
22862            // ensure assistive technology can determine the active choice
22863            this.search.attr("aria-activedescendant", choice.find(".select2-result-label").attr("id"));
22864
22865            this.ensureHighlightVisible();
22866
22867            this.liveRegion.text(choice.text());
22868
22869            data = choice.data("select2-data");
22870            if (data) {
22871                this.opts.element.trigger({ type: "select2-highlight", val: this.id(data), choice: data });
22872            }
22873        },
22874
22875        removeHighlight: function() {
22876            this.results.find(".select2-highlighted").removeClass("select2-highlighted");
22877        },
22878
22879        touchMoved: function() {
22880            this._touchMoved = true;
22881        },
22882
22883        clearTouchMoved: function() {
22884          this._touchMoved = false;
22885        },
22886
22887        // abstract
22888        countSelectableResults: function() {
22889            return this.findHighlightableChoices().length;
22890        },
22891
22892        // abstract
22893        highlightUnderEvent: function (event) {
22894            var el = $(event.target).closest(".select2-result-selectable");
22895            if (el.length > 0 && !el.is(".select2-highlighted")) {
22896                var choices = this.findHighlightableChoices();
22897                this.highlight(choices.index(el));
22898            } else if (el.length == 0) {
22899                // if we are over an unselectable item remove all highlights
22900                this.removeHighlight();
22901            }
22902        },
22903
22904        // abstract
22905        loadMoreIfNeeded: function () {
22906            var results = this.results,
22907                more = results.find("li.select2-more-results"),
22908                below, // pixels the element is below the scroll fold, below==0 is when the element is starting to be visible
22909                page = this.resultsPage + 1,
22910                self=this,
22911                term=this.search.val(),
22912                context=this.context;
22913
22914            if (more.length === 0) return;
22915            below = more.offset().top - results.offset().top - results.height();
22916
22917            if (below <= this.opts.loadMorePadding) {
22918                more.addClass("select2-active");
22919                this.opts.query({
22920                        element: this.opts.element,
22921                        term: term,
22922                        page: page,
22923                        context: context,
22924                        matcher: this.opts.matcher,
22925                        callback: this.bind(function (data) {
22926
22927                    // ignore a response if the select2 has been closed before it was received
22928                    if (!self.opened()) return;
22929
22930
22931                    self.opts.populateResults.call(this, results, data.results, {term: term, page: page, context:context});
22932                    self.postprocessResults(data, false, false);
22933
22934                    if (data.more===true) {
22935                        more.detach().appendTo(results).text(evaluate(self.opts.formatLoadMore, page+1));
22936                        window.setTimeout(function() { self.loadMoreIfNeeded(); }, 10);
22937                    } else {
22938                        more.remove();
22939                    }
22940                    self.positionDropdown();
22941                    self.resultsPage = page;
22942                    self.context = data.context;
22943                    this.opts.element.trigger({ type: "select2-loaded", items: data });
22944                })});
22945            }
22946        },
22947
22948        /**
22949         * Default tokenizer function which does nothing
22950         */
22951        tokenize: function() {
22952
22953        },
22954
22955        /**
22956         * @param initial whether or not this is the call to this method right after the dropdown has been opened
22957         */
22958        // abstract
22959        updateResults: function (initial) {
22960            var search = this.search,
22961                results = this.results,
22962                opts = this.opts,
22963                data,
22964                self = this,
22965                input,
22966                term = search.val(),
22967                lastTerm = $.data(this.container, "select2-last-term"),
22968                // sequence number used to drop out-of-order responses
22969                queryNumber;
22970
22971            // prevent duplicate queries against the same term
22972            if (initial !== true && lastTerm && equal(term, lastTerm)) return;
22973
22974            $.data(this.container, "select2-last-term", term);
22975
22976            // if the search is currently hidden we do not alter the results
22977            if (initial !== true && (this.showSearchInput === false || !this.opened())) {
22978                return;
22979            }
22980
22981            function postRender() {
22982                search.removeClass("select2-active");
22983                self.positionDropdown();
22984                if (results.find('.select2-no-results,.select2-selection-limit,.select2-searching').length) {
22985                    self.liveRegion.text(results.text());
22986                }
22987                else {
22988                    self.liveRegion.text(self.opts.formatMatches(results.find('.select2-result-selectable').length));
22989                }
22990            }
22991
22992            function render(html) {
22993                results.html(html);
22994                postRender();
22995            }
22996
22997            queryNumber = ++this.queryCount;
22998
22999            var maxSelSize = this.getMaximumSelectionSize();
23000            if (maxSelSize >=1) {
23001                data = this.data();
23002                if ($.isArray(data) && data.length >= maxSelSize && checkFormatter(opts.formatSelectionTooBig, "formatSelectionTooBig")) {
23003                    render("<li class='select2-selection-limit'>" + evaluate(opts.formatSelectionTooBig, maxSelSize) + "</li>");
23004                    return;
23005                }
23006            }
23007
23008            if (search.val().length < opts.minimumInputLength) {
23009                if (checkFormatter(opts.formatInputTooShort, "formatInputTooShort")) {
23010                    render("<li class='select2-no-results'>" + evaluate(opts.formatInputTooShort, search.val(), opts.minimumInputLength) + "</li>");
23011                } else {
23012                    render("");
23013                }
23014                if (initial && this.showSearch) this.showSearch(true);
23015                return;
23016            }
23017
23018            if (opts.maximumInputLength && search.val().length > opts.maximumInputLength) {
23019                if (checkFormatter(opts.formatInputTooLong, "formatInputTooLong")) {
23020                    render("<li class='select2-no-results'>" + evaluate(opts.formatInputTooLong, search.val(), opts.maximumInputLength) + "</li>");
23021                } else {
23022                    render("");
23023                }
23024                return;
23025            }
23026
23027            if (opts.formatSearching && this.findHighlightableChoices().length === 0) {
23028                render("<li class='select2-searching'>" + evaluate(opts.formatSearching) + "</li>");
23029            }
23030
23031            search.addClass("select2-active");
23032
23033            this.removeHighlight();
23034
23035            // give the tokenizer a chance to pre-process the input
23036            input = this.tokenize();
23037            if (input != undefined && input != null) {
23038                search.val(input);
23039            }
23040
23041            this.resultsPage = 1;
23042
23043            opts.query({
23044                element: opts.element,
23045                    term: search.val(),
23046                    page: this.resultsPage,
23047                    context: null,
23048                    matcher: opts.matcher,
23049                    callback: this.bind(function (data) {
23050                var def; // default choice
23051
23052                // ignore old responses
23053                if (queryNumber != this.queryCount) {
23054                  return;
23055                }
23056
23057                // ignore a response if the select2 has been closed before it was received
23058                if (!this.opened()) {
23059                    this.search.removeClass("select2-active");
23060                    return;
23061                }
23062
23063                // save context, if any
23064                this.context = (data.context===undefined) ? null : data.context;
23065                // create a default choice and prepend it to the list
23066                if (this.opts.createSearchChoice && search.val() !== "") {
23067                    def = this.opts.createSearchChoice.call(self, search.val(), data.results);
23068                    if (def !== undefined && def !== null && self.id(def) !== undefined && self.id(def) !== null) {
23069                        if ($(data.results).filter(
23070                            function () {
23071                                return equal(self.id(this), self.id(def));
23072                            }).length === 0) {
23073                            this.opts.createSearchChoicePosition(data.results, def);
23074                        }
23075                    }
23076                }
23077
23078                if (data.results.length === 0 && checkFormatter(opts.formatNoMatches, "formatNoMatches")) {
23079                    render("<li class='select2-no-results'>" + evaluate(opts.formatNoMatches, search.val()) + "</li>");
23080                    return;
23081                }
23082
23083                results.empty();
23084                self.opts.populateResults.call(this, results, data.results, {term: search.val(), page: this.resultsPage, context:null});
23085
23086                if (data.more === true && checkFormatter(opts.formatLoadMore, "formatLoadMore")) {
23087                    results.append("<li class='select2-more-results'>" + self.opts.escapeMarkup(evaluate(opts.formatLoadMore, this.resultsPage)) + "</li>");
23088                    window.setTimeout(function() { self.loadMoreIfNeeded(); }, 10);
23089                }
23090
23091                this.postprocessResults(data, initial);
23092
23093                postRender();
23094
23095                this.opts.element.trigger({ type: "select2-loaded", items: data });
23096            })});
23097        },
23098
23099        // abstract
23100        cancel: function () {
23101            this.close();
23102        },
23103
23104        // abstract
23105        blur: function () {
23106            // if selectOnBlur == true, select the currently highlighted option
23107            if (this.opts.selectOnBlur)
23108                this.selectHighlighted({noFocus: true});
23109
23110            this.close();
23111            this.container.removeClass("select2-container-active");
23112            // synonymous to .is(':focus'), which is available in jquery >= 1.6
23113            if (this.search[0] === document.activeElement) { this.search.blur(); }
23114            this.clearSearch();
23115            this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus");
23116        },
23117
23118        // abstract
23119        focusSearch: function () {
23120            focus(this.search);
23121        },
23122
23123        // abstract
23124        selectHighlighted: function (options) {
23125            if (this._touchMoved) {
23126              this.clearTouchMoved();
23127              return;
23128            }
23129            var index=this.highlight(),
23130                highlighted=this.results.find(".select2-highlighted"),
23131                data = highlighted.closest('.select2-result').data("select2-data");
23132
23133            if (data) {
23134                this.highlight(index);
23135                this.onSelect(data, options);
23136            } else if (options && options.noFocus) {
23137                this.close();
23138            }
23139        },
23140
23141        // abstract
23142        getPlaceholder: function () {
23143            var placeholderOption;
23144            return this.opts.element.attr("placeholder") ||
23145                this.opts.element.attr("data-placeholder") || // jquery 1.4 compat
23146                this.opts.element.data("placeholder") ||
23147                this.opts.placeholder ||
23148                ((placeholderOption = this.getPlaceholderOption()) !== undefined ? placeholderOption.text() : undefined);
23149        },
23150
23151        // abstract
23152        getPlaceholderOption: function() {
23153            if (this.select) {
23154                var firstOption = this.select.children('option').first();
23155                if (this.opts.placeholderOption !== undefined ) {
23156                    //Determine the placeholder option based on the specified placeholderOption setting
23157                    return (this.opts.placeholderOption === "first" && firstOption) ||
23158                           (typeof this.opts.placeholderOption === "function" && this.opts.placeholderOption(this.select));
23159                } else if ($.trim(firstOption.text()) === "" && firstOption.val() === "") {
23160                    //No explicit placeholder option specified, use the first if it's blank
23161                    return firstOption;
23162                }
23163            }
23164        },
23165
23166        /**
23167         * Get the desired width for the container element.  This is
23168         * derived first from option `width` passed to select2, then
23169         * the inline 'style' on the original element, and finally
23170         * falls back to the jQuery calculated element width.
23171         */
23172        // abstract
23173        initContainerWidth: function () {
23174            function resolveContainerWidth() {
23175                var style, attrs, matches, i, l, attr;
23176
23177                if (this.opts.width === "off") {
23178                    return null;
23179                } else if (this.opts.width === "element"){
23180                    return this.opts.element.outerWidth(false) === 0 ? 'auto' : this.opts.element.outerWidth(false) + 'px';
23181                } else if (this.opts.width === "copy" || this.opts.width === "resolve") {
23182                    // check if there is inline style on the element that contains width
23183                    style = this.opts.element.attr('style');
23184                    if (style !== undefined) {
23185                        attrs = style.split(';');
23186                        for (i = 0, l = attrs.length; i < l; i = i + 1) {
23187                            attr = attrs[i].replace(/\s/g, '');
23188                            matches = attr.match(/^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i);
23189                            if (matches !== null && matches.length >= 1)
23190                                return matches[1];
23191                        }
23192                    }
23193
23194                    if (this.opts.width === "resolve") {
23195                        // next check if css('width') can resolve a width that is percent based, this is sometimes possible
23196                        // when attached to input type=hidden or elements hidden via css
23197                        style = this.opts.element.css('width');
23198                        if (style.indexOf("%") > 0) return style;
23199
23200                        // finally, fallback on the calculated width of the element
23201                        return (this.opts.element.outerWidth(false) === 0 ? 'auto' : this.opts.element.outerWidth(false) + 'px');
23202                    }
23203
23204                    return null;
23205                } else if ($.isFunction(this.opts.width)) {
23206                    return this.opts.width();
23207                } else {
23208                    return this.opts.width;
23209               }
23210            };
23211
23212            var width = resolveContainerWidth.call(this);
23213            if (width !== null) {
23214                this.container.css("width", width);
23215            }
23216        }
23217    });
23218
23219    SingleSelect2 = clazz(AbstractSelect2, {
23220
23221        // single
23222
23223        createContainer: function () {
23224            var container = $(document.createElement("div")).attr({
23225                "class": "select2-container"
23226            }).html([
23227                "<a href='javascript:void(0)' class='select2-choice' tabindex='-1'>",
23228                "   <span class='select2-chosen'>&#160;</span><abbr class='select2-search-choice-close'></abbr>",
23229                "   <span class='select2-arrow' role='presentation'><b role='presentation'></b></span>",
23230                "</a>",
23231                "<label for='' class='select2-offscreen'></label>",
23232                "<input class='select2-focusser select2-offscreen' type='text' aria-haspopup='true' role='button' />",
23233                "<div class='select2-drop select2-display-none'>",
23234                "   <div class='select2-search'>",
23235                "       <label for='' class='select2-offscreen'></label>",
23236                "       <input type='text' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' class='select2-input' role='combobox' aria-expanded='true'",
23237                "       aria-autocomplete='list' />",
23238                "   </div>",
23239                "   <ul class='select2-results' role='listbox'>",
23240                "   </ul>",
23241                "</div>"].join(""));
23242            return container;
23243        },
23244
23245        // single
23246        enableInterface: function() {
23247            if (this.parent.enableInterface.apply(this, arguments)) {
23248                this.focusser.prop("disabled", !this.isInterfaceEnabled());
23249            }
23250        },
23251
23252        // single
23253        opening: function () {
23254            var el, range, len;
23255
23256            if (this.opts.minimumResultsForSearch >= 0) {
23257                this.showSearch(true);
23258            }
23259
23260            this.parent.opening.apply(this, arguments);
23261
23262            if (this.showSearchInput !== false) {
23263                // IE appends focusser.val() at the end of field :/ so we manually insert it at the beginning using a range
23264                // all other browsers handle this just fine
23265
23266                this.search.val(this.focusser.val());
23267            }
23268            if (this.opts.shouldFocusInput(this)) {
23269                this.search.focus();
23270                // move the cursor to the end after focussing, otherwise it will be at the beginning and
23271                // new text will appear *before* focusser.val()
23272                el = this.search.get(0);
23273                if (el.createTextRange) {
23274                    range = el.createTextRange();
23275                    range.collapse(false);
23276                    range.select();
23277                } else if (el.setSelectionRange) {
23278                    len = this.search.val().length;
23279                    el.setSelectionRange(len, len);
23280                }
23281            }
23282
23283            // initializes search's value with nextSearchTerm (if defined by user)
23284            // ignore nextSearchTerm if the dropdown is opened by the user pressing a letter
23285            if(this.search.val() === "") {
23286                if(this.nextSearchTerm != undefined){
23287                    this.search.val(this.nextSearchTerm);
23288                    this.search.select();
23289                }
23290            }
23291
23292            this.focusser.prop("disabled", true).val("");
23293            this.updateResults(true);
23294            this.opts.element.trigger($.Event("select2-open"));
23295        },
23296
23297        // single
23298        close: function () {
23299            if (!this.opened()) return;
23300            this.parent.close.apply(this, arguments);
23301
23302            this.focusser.prop("disabled", false);
23303
23304            if (this.opts.shouldFocusInput(this)) {
23305                this.focusser.focus();
23306            }
23307        },
23308
23309        // single
23310        focus: function () {
23311            if (this.opened()) {
23312                this.close();
23313            } else {
23314                this.focusser.prop("disabled", false);
23315                if (this.opts.shouldFocusInput(this)) {
23316                    this.focusser.focus();
23317                }
23318            }
23319        },
23320
23321        // single
23322        isFocused: function () {
23323            return this.container.hasClass("select2-container-active");
23324        },
23325
23326        // single
23327        cancel: function () {
23328            this.parent.cancel.apply(this, arguments);
23329            this.focusser.prop("disabled", false);
23330
23331            if (this.opts.shouldFocusInput(this)) {
23332                this.focusser.focus();
23333            }
23334        },
23335
23336        // single
23337        destroy: function() {
23338            $("label[for='" + this.focusser.attr('id') + "']")
23339                .attr('for', this.opts.element.attr("id"));
23340            this.parent.destroy.apply(this, arguments);
23341
23342            cleanupJQueryElements.call(this,
23343                "selection",
23344                "focusser"
23345            );
23346        },
23347
23348        // single
23349        initContainer: function () {
23350
23351            var selection,
23352                container = this.container,
23353                dropdown = this.dropdown,
23354                idSuffix = nextUid(),
23355                elementLabel;
23356
23357            if (this.opts.minimumResultsForSearch < 0) {
23358                this.showSearch(false);
23359            } else {
23360                this.showSearch(true);
23361            }
23362
23363            this.selection = selection = container.find(".select2-choice");
23364
23365            this.focusser = container.find(".select2-focusser");
23366
23367            // add aria associations
23368            selection.find(".select2-chosen").attr("id", "select2-chosen-"+idSuffix);
23369            this.focusser.attr("aria-labelledby", "select2-chosen-"+idSuffix);
23370            this.results.attr("id", "select2-results-"+idSuffix);
23371            this.search.attr("aria-owns", "select2-results-"+idSuffix);
23372
23373            // rewrite labels from original element to focusser
23374            this.focusser.attr("id", "s2id_autogen"+idSuffix);
23375
23376            elementLabel = $("label[for='" + this.opts.element.attr("id") + "']");
23377
23378            this.focusser.prev()
23379                .text(elementLabel.text())
23380                .attr('for', this.focusser.attr('id'));
23381
23382            // Ensure the original element retains an accessible name
23383            var originalTitle = this.opts.element.attr("title");
23384            this.opts.element.attr("title", (originalTitle || elementLabel.text()));
23385
23386            this.focusser.attr("tabindex", this.elementTabIndex);
23387
23388            // write label for search field using the label from the focusser element
23389            this.search.attr("id", this.focusser.attr('id') + '_search');
23390
23391            this.search.prev()
23392                .text($("label[for='" + this.focusser.attr('id') + "']").text())
23393                .attr('for', this.search.attr('id'));
23394
23395            this.search.on("keydown", this.bind(function (e) {
23396                if (!this.isInterfaceEnabled()) return;
23397
23398                if (e.which === KEY.PAGE_UP || e.which === KEY.PAGE_DOWN) {
23399                    // prevent the page from scrolling
23400                    killEvent(e);
23401                    return;
23402                }
23403
23404                switch (e.which) {
23405                    case KEY.UP:
23406                    case KEY.DOWN:
23407                        this.moveHighlight((e.which === KEY.UP) ? -1 : 1);
23408                        killEvent(e);
23409                        return;
23410                    case KEY.ENTER:
23411                        this.selectHighlighted();
23412                        killEvent(e);
23413                        return;
23414                    case KEY.TAB:
23415                        this.selectHighlighted({noFocus: true});
23416                        return;
23417                    case KEY.ESC:
23418                        this.cancel(e);
23419                        killEvent(e);
23420                        return;
23421                }
23422            }));
23423
23424            this.search.on("blur", this.bind(function(e) {
23425                // a workaround for chrome to keep the search field focussed when the scroll bar is used to scroll the dropdown.
23426                // without this the search field loses focus which is annoying
23427                if (document.activeElement === this.body.get(0)) {
23428                    window.setTimeout(this.bind(function() {
23429                        if (this.opened()) {
23430                            this.search.focus();
23431                        }
23432                    }), 0);
23433                }
23434            }));
23435
23436            this.focusser.on("keydown", this.bind(function (e) {
23437                if (!this.isInterfaceEnabled()) return;
23438
23439                if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) || e.which === KEY.ESC) {
23440                    return;
23441                }
23442
23443                if (this.opts.openOnEnter === false && e.which === KEY.ENTER) {
23444                    killEvent(e);
23445                    return;
23446                }
23447
23448                if (e.which == KEY.DOWN || e.which == KEY.UP
23449                    || (e.which == KEY.ENTER && this.opts.openOnEnter)) {
23450
23451                    if (e.altKey || e.ctrlKey || e.shiftKey || e.metaKey) return;
23452
23453                    this.open();
23454                    killEvent(e);
23455                    return;
23456                }
23457
23458                if (e.which == KEY.DELETE || e.which == KEY.BACKSPACE) {
23459                    if (this.opts.allowClear) {
23460                        this.clear();
23461                    }
23462                    killEvent(e);
23463                    return;
23464                }
23465            }));
23466
23467
23468            installKeyUpChangeEvent(this.focusser);
23469            this.focusser.on("keyup-change input", this.bind(function(e) {
23470                if (this.opts.minimumResultsForSearch >= 0) {
23471                    e.stopPropagation();
23472                    if (this.opened()) return;
23473                    this.open();
23474                }
23475            }));
23476
23477            selection.on("mousedown touchstart", "abbr", this.bind(function (e) {
23478                if (!this.isInterfaceEnabled()) return;
23479                this.clear();
23480                killEventImmediately(e);
23481                this.close();
23482                this.selection.focus();
23483            }));
23484
23485            selection.on("mousedown touchstart", this.bind(function (e) {
23486                // Prevent IE from generating a click event on the body
23487                reinsertElement(selection);
23488
23489                if (!this.container.hasClass("select2-container-active")) {
23490                    this.opts.element.trigger($.Event("select2-focus"));
23491                }
23492
23493                if (this.opened()) {
23494                    this.close();
23495                } else if (this.isInterfaceEnabled()) {
23496                    this.open();
23497                }
23498
23499                killEvent(e);
23500            }));
23501
23502            dropdown.on("mousedown touchstart", this.bind(function() {
23503                if (this.opts.shouldFocusInput(this)) {
23504                    this.search.focus();
23505                }
23506            }));
23507
23508            selection.on("focus", this.bind(function(e) {
23509                killEvent(e);
23510            }));
23511
23512            this.focusser.on("focus", this.bind(function(){
23513                if (!this.container.hasClass("select2-container-active")) {
23514                    this.opts.element.trigger($.Event("select2-focus"));
23515                }
23516                this.container.addClass("select2-container-active");
23517            })).on("blur", this.bind(function() {
23518                if (!this.opened()) {
23519                    this.container.removeClass("select2-container-active");
23520                    this.opts.element.trigger($.Event("select2-blur"));
23521                }
23522            }));
23523            this.search.on("focus", this.bind(function(){
23524                if (!this.container.hasClass("select2-container-active")) {
23525                    this.opts.element.trigger($.Event("select2-focus"));
23526                }
23527                this.container.addClass("select2-container-active");
23528            }));
23529
23530            this.initContainerWidth();
23531            this.opts.element.addClass("select2-offscreen");
23532            this.setPlaceholder();
23533
23534        },
23535
23536        // single
23537        clear: function(triggerChange) {
23538            var data=this.selection.data("select2-data");
23539            if (data) { // guard against queued quick consecutive clicks
23540                var evt = $.Event("select2-clearing");
23541                this.opts.element.trigger(evt);
23542                if (evt.isDefaultPrevented()) {
23543                    return;
23544                }
23545                var placeholderOption = this.getPlaceholderOption();
23546                this.opts.element.val(placeholderOption ? placeholderOption.val() : "");
23547                this.selection.find(".select2-chosen").empty();
23548                this.selection.removeData("select2-data");
23549                this.setPlaceholder();
23550
23551                if (triggerChange !== false){
23552                    this.opts.element.trigger({ type: "select2-removed", val: this.id(data), choice: data });
23553                    this.triggerChange({removed:data});
23554                }
23555            }
23556        },
23557
23558        /**
23559         * Sets selection based on source element's value
23560         */
23561        // single
23562        initSelection: function () {
23563            var selected;
23564            if (this.isPlaceholderOptionSelected()) {
23565                this.updateSelection(null);
23566                this.close();
23567                this.setPlaceholder();
23568            } else {
23569                var self = this;
23570                this.opts.initSelection.call(null, this.opts.element, function(selected){
23571                    if (selected !== undefined && selected !== null) {
23572                        self.updateSelection(selected);
23573                        self.close();
23574                        self.setPlaceholder();
23575                        self.nextSearchTerm = self.opts.nextSearchTerm(selected, self.search.val());
23576                    }
23577                });
23578            }
23579        },
23580
23581        isPlaceholderOptionSelected: function() {
23582            var placeholderOption;
23583            if (this.getPlaceholder() === undefined) return false; // no placeholder specified so no option should be considered
23584            return ((placeholderOption = this.getPlaceholderOption()) !== undefined && placeholderOption.prop("selected"))
23585                || (this.opts.element.val() === "")
23586                || (this.opts.element.val() === undefined)
23587                || (this.opts.element.val() === null);
23588        },
23589
23590        // single
23591        prepareOpts: function () {
23592            var opts = this.parent.prepareOpts.apply(this, arguments),
23593                self=this;
23594
23595            if (opts.element.get(0).tagName.toLowerCase() === "select") {
23596                // install the selection initializer
23597                opts.initSelection = function (element, callback) {
23598                    var selected = element.find("option").filter(function() { return this.selected && !this.disabled });
23599                    // a single select box always has a value, no need to null check 'selected'
23600                    callback(self.optionToData(selected));
23601                };
23602            } else if ("data" in opts) {
23603                // install default initSelection when applied to hidden input and data is local
23604                opts.initSelection = opts.initSelection || function (element, callback) {
23605                    var id = element.val();
23606                    //search in data by id, storing the actual matching item
23607                    var match = null;
23608                    opts.query({
23609                        matcher: function(term, text, el){
23610                            var is_match = equal(id, opts.id(el));
23611                            if (is_match) {
23612                                match = el;
23613                            }
23614                            return is_match;
23615                        },
23616                        callback: !$.isFunction(callback) ? $.noop : function() {
23617                            callback(match);
23618                        }
23619                    });
23620                };
23621            }
23622
23623            return opts;
23624        },
23625
23626        // single
23627        getPlaceholder: function() {
23628            // if a placeholder is specified on a single select without a valid placeholder option ignore it
23629            if (this.select) {
23630                if (this.getPlaceholderOption() === undefined) {
23631                    return undefined;
23632                }
23633            }
23634
23635            return this.parent.getPlaceholder.apply(this, arguments);
23636        },
23637
23638        // single
23639        setPlaceholder: function () {
23640            var placeholder = this.getPlaceholder();
23641
23642            if (this.isPlaceholderOptionSelected() && placeholder !== undefined) {
23643
23644                // check for a placeholder option if attached to a select
23645                if (this.select && this.getPlaceholderOption() === undefined) return;
23646
23647                this.selection.find(".select2-chosen").html(this.opts.escapeMarkup(placeholder));
23648
23649                this.selection.addClass("select2-default");
23650
23651                this.container.removeClass("select2-allowclear");
23652            }
23653        },
23654
23655        // single
23656        postprocessResults: function (data, initial, noHighlightUpdate) {
23657            var selected = 0, self = this, showSearchInput = true;
23658
23659            // find the selected element in the result list
23660
23661            this.findHighlightableChoices().each2(function (i, elm) {
23662                if (equal(self.id(elm.data("select2-data")), self.opts.element.val())) {
23663                    selected = i;
23664                    return false;
23665                }
23666            });
23667
23668            // and highlight it
23669            if (noHighlightUpdate !== false) {
23670                if (initial === true && selected >= 0) {
23671                    this.highlight(selected);
23672                } else {
23673                    this.highlight(0);
23674                }
23675            }
23676
23677            // hide the search box if this is the first we got the results and there are enough of them for search
23678
23679            if (initial === true) {
23680                var min = this.opts.minimumResultsForSearch;
23681                if (min >= 0) {
23682                    this.showSearch(countResults(data.results) >= min);
23683                }
23684            }
23685        },
23686
23687        // single
23688        showSearch: function(showSearchInput) {
23689            if (this.showSearchInput === showSearchInput) return;
23690
23691            this.showSearchInput = showSearchInput;
23692
23693            this.dropdown.find(".select2-search").toggleClass("select2-search-hidden", !showSearchInput);
23694            this.dropdown.find(".select2-search").toggleClass("select2-offscreen", !showSearchInput);
23695            //add "select2-with-searchbox" to the container if search box is shown
23696            $(this.dropdown, this.container).toggleClass("select2-with-searchbox", showSearchInput);
23697        },
23698
23699        // single
23700        onSelect: function (data, options) {
23701
23702            if (!this.triggerSelect(data)) { return; }
23703
23704            var old = this.opts.element.val(),
23705                oldData = this.data();
23706
23707            this.opts.element.val(this.id(data));
23708            this.updateSelection(data);
23709
23710            this.opts.element.trigger({ type: "select2-selected", val: this.id(data), choice: data });
23711
23712            this.nextSearchTerm = this.opts.nextSearchTerm(data, this.search.val());
23713            this.close();
23714
23715            if ((!options || !options.noFocus) && this.opts.shouldFocusInput(this)) {
23716                this.focusser.focus();
23717            }
23718
23719            if (!equal(old, this.id(data))) {
23720                this.triggerChange({ added: data, removed: oldData });
23721            }
23722        },
23723
23724        // single
23725        updateSelection: function (data) {
23726
23727            var container=this.selection.find(".select2-chosen"), formatted, cssClass;
23728
23729            this.selection.data("select2-data", data);
23730
23731            container.empty();
23732            if (data !== null) {
23733                formatted=this.opts.formatSelection(data, container, this.opts.escapeMarkup);
23734            }
23735            if (formatted !== undefined) {
23736                container.append(formatted);
23737            }
23738            cssClass=this.opts.formatSelectionCssClass(data, container);
23739            if (cssClass !== undefined) {
23740                container.addClass(cssClass);
23741            }
23742
23743            this.selection.removeClass("select2-default");
23744
23745            if (this.opts.allowClear && this.getPlaceholder() !== undefined) {
23746                this.container.addClass("select2-allowclear");
23747            }
23748        },
23749
23750        // single
23751        val: function () {
23752            var val,
23753                triggerChange = false,
23754                data = null,
23755                self = this,
23756                oldData = this.data();
23757
23758            if (arguments.length === 0) {
23759                return this.opts.element.val();
23760            }
23761
23762            val = arguments[0];
23763
23764            if (arguments.length > 1) {
23765                triggerChange = arguments[1];
23766            }
23767
23768            if (this.select) {
23769                this.select
23770                    .val(val)
23771                    .find("option").filter(function() { return this.selected }).each2(function (i, elm) {
23772                        data = self.optionToData(elm);
23773                        return false;
23774                    });
23775                this.updateSelection(data);
23776                this.setPlaceholder();
23777                if (triggerChange) {
23778                    this.triggerChange({added: data, removed:oldData});
23779                }
23780            } else {
23781                // val is an id. !val is true for [undefined,null,'',0] - 0 is legal
23782                if (!val && val !== 0) {
23783                    this.clear(triggerChange);
23784                    return;
23785                }
23786                if (this.opts.initSelection === undefined) {
23787                    throw new Error("cannot call val() if initSelection() is not defined");
23788                }
23789                this.opts.element.val(val);
23790                this.opts.initSelection(this.opts.element, function(data){
23791                    self.opts.element.val(!data ? "" : self.id(data));
23792                    self.updateSelection(data);
23793                    self.setPlaceholder();
23794                    if (triggerChange) {
23795                        self.triggerChange({added: data, removed:oldData});
23796                    }
23797                });
23798            }
23799        },
23800
23801        // single
23802        clearSearch: function () {
23803            this.search.val("");
23804            this.focusser.val("");
23805        },
23806
23807        // single
23808        data: function(value) {
23809            var data,
23810                triggerChange = false;
23811
23812            if (arguments.length === 0) {
23813                data = this.selection.data("select2-data");
23814                if (data == undefined) data = null;
23815                return data;
23816            } else {
23817                if (arguments.length > 1) {
23818                    triggerChange = arguments[1];
23819                }
23820                if (!value) {
23821                    this.clear(triggerChange);
23822                } else {
23823                    data = this.data();
23824                    this.opts.element.val(!value ? "" : this.id(value));
23825                    this.updateSelection(value);
23826                    if (triggerChange) {
23827                        this.triggerChange({added: value, removed:data});
23828                    }
23829                }
23830            }
23831        }
23832    });
23833
23834    MultiSelect2 = clazz(AbstractSelect2, {
23835
23836        // multi
23837        createContainer: function () {
23838            var container = $(document.createElement("div")).attr({
23839                "class": "select2-container select2-container-multi"
23840            }).html([
23841                "<ul class='select2-choices'>",
23842                "  <li class='select2-search-field'>",
23843                "    <label for='' class='select2-offscreen'></label>",
23844                "    <input type='text' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' class='select2-input'>",
23845                "  </li>",
23846                "</ul>",
23847                "<div class='select2-drop select2-drop-multi select2-display-none'>",
23848                "   <ul class='select2-results'>",
23849                "   </ul>",
23850                "</div>"].join(""));
23851            return container;
23852        },
23853
23854        // multi
23855        prepareOpts: function () {
23856            var opts = this.parent.prepareOpts.apply(this, arguments),
23857                self=this;
23858
23859            // TODO validate placeholder is a string if specified
23860
23861            if (opts.element.get(0).tagName.toLowerCase() === "select") {
23862                // install the selection initializer
23863                opts.initSelection = function (element, callback) {
23864
23865                    var data = [];
23866
23867                    element.find("option").filter(function() { return this.selected && !this.disabled }).each2(function (i, elm) {
23868                        data.push(self.optionToData(elm));
23869                    });
23870                    callback(data);
23871                };
23872            } else if ("data" in opts) {
23873                // install default initSelection when applied to hidden input and data is local
23874                opts.initSelection = opts.initSelection || function (element, callback) {
23875                    var ids = splitVal(element.val(), opts.separator);
23876                    //search in data by array of ids, storing matching items in a list
23877                    var matches = [];
23878                    opts.query({
23879                        matcher: function(term, text, el){
23880                            var is_match = $.grep(ids, function(id) {
23881                                return equal(id, opts.id(el));
23882                            }).length;
23883                            if (is_match) {
23884                                matches.push(el);
23885                            }
23886                            return is_match;
23887                        },
23888                        callback: !$.isFunction(callback) ? $.noop : function() {
23889                            // reorder matches based on the order they appear in the ids array because right now
23890                            // they are in the order in which they appear in data array
23891                            var ordered = [];
23892                            for (var i = 0; i < ids.length; i++) {
23893                                var id = ids[i];
23894                                for (var j = 0; j < matches.length; j++) {
23895                                    var match = matches[j];
23896                                    if (equal(id, opts.id(match))) {
23897                                        ordered.push(match);
23898                                        matches.splice(j, 1);
23899                                        break;
23900                                    }
23901                                }
23902                            }
23903                            callback(ordered);
23904                        }
23905                    });
23906                };
23907            }
23908
23909            return opts;
23910        },
23911
23912        // multi
23913        selectChoice: function (choice) {
23914
23915            var selected = this.container.find(".select2-search-choice-focus");
23916            if (selected.length && choice && choice[0] == selected[0]) {
23917
23918            } else {
23919                if (selected.length) {
23920                    this.opts.element.trigger("choice-deselected", selected);
23921                }
23922                selected.removeClass("select2-search-choice-focus");
23923                if (choice && choice.length) {
23924                    this.close();
23925                    choice.addClass("select2-search-choice-focus");
23926                    this.opts.element.trigger("choice-selected", choice);
23927                }
23928            }
23929        },
23930
23931        // multi
23932        destroy: function() {
23933            $("label[for='" + this.search.attr('id') + "']")
23934                .attr('for', this.opts.element.attr("id"));
23935            this.parent.destroy.apply(this, arguments);
23936
23937            cleanupJQueryElements.call(this,
23938                "searchContainer",
23939                "selection"
23940            );
23941        },
23942
23943        // multi
23944        initContainer: function () {
23945
23946            var selector = ".select2-choices", selection;
23947
23948            this.searchContainer = this.container.find(".select2-search-field");
23949            this.selection = selection = this.container.find(selector);
23950
23951            var _this = this;
23952            this.selection.on("click", ".select2-search-choice:not(.select2-locked)", function (e) {
23953                //killEvent(e);
23954                _this.search[0].focus();
23955                _this.selectChoice($(this));
23956            });
23957
23958            // rewrite labels from original element to focusser
23959            this.search.attr("id", "s2id_autogen"+nextUid());
23960
23961            this.search.prev()
23962                .text($("label[for='" + this.opts.element.attr("id") + "']").text())
23963                .attr('for', this.search.attr('id'));
23964
23965            this.search.on("input paste", this.bind(function() {
23966                if (!this.isInterfaceEnabled()) return;
23967                if (!this.opened()) {
23968                    this.open();
23969                }
23970            }));
23971
23972            this.search.attr("tabindex", this.elementTabIndex);
23973
23974            this.keydowns = 0;
23975            this.search.on("keydown", this.bind(function (e) {
23976                if (!this.isInterfaceEnabled()) return;
23977
23978                ++this.keydowns;
23979                var selected = selection.find(".select2-search-choice-focus");
23980                var prev = selected.prev(".select2-search-choice:not(.select2-locked)");
23981                var next = selected.next(".select2-search-choice:not(.select2-locked)");
23982                var pos = getCursorInfo(this.search);
23983
23984                if (selected.length &&
23985                    (e.which == KEY.LEFT || e.which == KEY.RIGHT || e.which == KEY.BACKSPACE || e.which == KEY.DELETE || e.which == KEY.ENTER)) {
23986                    var selectedChoice = selected;
23987                    if (e.which == KEY.LEFT && prev.length) {
23988                        selectedChoice = prev;
23989                    }
23990                    else if (e.which == KEY.RIGHT) {
23991                        selectedChoice = next.length ? next : null;
23992                    }
23993                    else if (e.which === KEY.BACKSPACE) {
23994                        if (this.unselect(selected.first())) {
23995                            this.search.width(10);
23996                            selectedChoice = prev.length ? prev : next;
23997                        }
23998                    } else if (e.which == KEY.DELETE) {
23999                        if (this.unselect(selected.first())) {
24000                            this.search.width(10);
24001                            selectedChoice = next.length ? next : null;
24002                        }
24003                    } else if (e.which == KEY.ENTER) {
24004                        selectedChoice = null;
24005                    }
24006
24007                    this.selectChoice(selectedChoice);
24008                    killEvent(e);
24009                    if (!selectedChoice || !selectedChoice.length) {
24010                        this.open();
24011                    }
24012                    return;
24013                } else if (((e.which === KEY.BACKSPACE && this.keydowns == 1)
24014                    || e.which == KEY.LEFT) && (pos.offset == 0 && !pos.length)) {
24015
24016                    this.selectChoice(selection.find(".select2-search-choice:not(.select2-locked)").last());
24017                    killEvent(e);
24018                    return;
24019                } else {
24020                    this.selectChoice(null);
24021                }
24022
24023                if (this.opened()) {
24024                    switch (e.which) {
24025                    case KEY.UP:
24026                    case KEY.DOWN:
24027                        this.moveHighlight((e.which === KEY.UP) ? -1 : 1);
24028                        killEvent(e);
24029                        return;
24030                    case KEY.ENTER:
24031                        this.selectHighlighted();
24032                        killEvent(e);
24033                        return;
24034                    case KEY.TAB:
24035                        this.selectHighlighted({noFocus:true});
24036                        this.close();
24037                        return;
24038                    case KEY.ESC:
24039                        this.cancel(e);
24040                        killEvent(e);
24041                        return;
24042                    }
24043                }
24044
24045                if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e)
24046                 || e.which === KEY.BACKSPACE || e.which === KEY.ESC) {
24047                    return;
24048                }
24049
24050                if (e.which === KEY.ENTER) {
24051                    if (this.opts.openOnEnter === false) {
24052                        return;
24053                    } else if (e.altKey || e.ctrlKey || e.shiftKey || e.metaKey) {
24054                        return;
24055                    }
24056                }
24057
24058                this.open();
24059
24060                if (e.which === KEY.PAGE_UP || e.which === KEY.PAGE_DOWN) {
24061                    // prevent the page from scrolling
24062                    killEvent(e);
24063                }
24064
24065                if (e.which === KEY.ENTER) {
24066                    // prevent form from being submitted
24067                    killEvent(e);
24068                }
24069
24070            }));
24071
24072            this.search.on("keyup", this.bind(function (e) {
24073                this.keydowns = 0;
24074                this.resizeSearch();
24075            })
24076            );
24077
24078            this.search.on("blur", this.bind(function(e) {
24079                this.container.removeClass("select2-container-active");
24080                this.search.removeClass("select2-focused");
24081                this.selectChoice(null);
24082                if (!this.opened()) this.clearSearch();
24083                e.stopImmediatePropagation();
24084                this.opts.element.trigger($.Event("select2-blur"));
24085            }));
24086
24087            this.container.on("click", selector, this.bind(function (e) {
24088                if (!this.isInterfaceEnabled()) return;
24089                if ($(e.target).closest(".select2-search-choice").length > 0) {
24090                    // clicked inside a select2 search choice, do not open
24091                    return;
24092                }
24093                this.selectChoice(null);
24094                this.clearPlaceholder();
24095                if (!this.container.hasClass("select2-container-active")) {
24096                    this.opts.element.trigger($.Event("select2-focus"));
24097                }
24098                this.open();
24099                this.focusSearch();
24100                e.preventDefault();
24101            }));
24102
24103            this.container.on("focus", selector, this.bind(function () {
24104                if (!this.isInterfaceEnabled()) return;
24105                if (!this.container.hasClass("select2-container-active")) {
24106                    this.opts.element.trigger($.Event("select2-focus"));
24107                }
24108                this.container.addClass("select2-container-active");
24109                this.dropdown.addClass("select2-drop-active");
24110                this.clearPlaceholder();
24111            }));
24112
24113            this.initContainerWidth();
24114            this.opts.element.addClass("select2-offscreen");
24115
24116            // set the placeholder if necessary
24117            this.clearSearch();
24118        },
24119
24120        // multi
24121        enableInterface: function() {
24122            if (this.parent.enableInterface.apply(this, arguments)) {
24123                this.search.prop("disabled", !this.isInterfaceEnabled());
24124            }
24125        },
24126
24127        // multi
24128        initSelection: function () {
24129            var data;
24130            if (this.opts.element.val() === "" && this.opts.element.text() === "") {
24131                this.updateSelection([]);
24132                this.close();
24133                // set the placeholder if necessary
24134                this.clearSearch();
24135            }
24136            if (this.select || this.opts.element.val() !== "") {
24137                var self = this;
24138                this.opts.initSelection.call(null, this.opts.element, function(data){
24139                    if (data !== undefined && data !== null) {
24140                        self.updateSelection(data);
24141                        self.close();
24142                        // set the placeholder if necessary
24143                        self.clearSearch();
24144                    }
24145                });
24146            }
24147        },
24148
24149        // multi
24150        clearSearch: function () {
24151            var placeholder = this.getPlaceholder(),
24152                maxWidth = this.getMaxSearchWidth();
24153
24154            if (placeholder !== undefined  && this.getVal().length === 0 && this.search.hasClass("select2-focused") === false) {
24155                this.search.val(placeholder).addClass("select2-default");
24156                // stretch the search box to full width of the container so as much of the placeholder is visible as possible
24157                // we could call this.resizeSearch(), but we do not because that requires a sizer and we do not want to create one so early because of a firefox bug, see #944
24158                this.search.width(maxWidth > 0 ? maxWidth : this.container.css("width"));
24159            } else {
24160                this.search.val("").width(10);
24161            }
24162        },
24163
24164        // multi
24165        clearPlaceholder: function () {
24166            if (this.search.hasClass("select2-default")) {
24167                this.search.val("").removeClass("select2-default");
24168            }
24169        },
24170
24171        // multi
24172        opening: function () {
24173            this.clearPlaceholder(); // should be done before super so placeholder is not used to search
24174            this.resizeSearch();
24175
24176            this.parent.opening.apply(this, arguments);
24177
24178            this.focusSearch();
24179
24180            // initializes search's value with nextSearchTerm (if defined by user)
24181            // ignore nextSearchTerm if the dropdown is opened by the user pressing a letter
24182            if(this.search.val() === "") {
24183                if(this.nextSearchTerm != undefined){
24184                    this.search.val(this.nextSearchTerm);
24185                    this.search.select();
24186                }
24187            }
24188
24189            this.updateResults(true);
24190            if (this.opts.shouldFocusInput(this)) {
24191                this.search.focus();
24192            }
24193            this.opts.element.trigger($.Event("select2-open"));
24194        },
24195
24196        // multi
24197        close: function () {
24198            if (!this.opened()) return;
24199            this.parent.close.apply(this, arguments);
24200        },
24201
24202        // multi
24203        focus: function () {
24204            this.close();
24205            this.search.focus();
24206        },
24207
24208        // multi
24209        isFocused: function () {
24210            return this.search.hasClass("select2-focused");
24211        },
24212
24213        // multi
24214        updateSelection: function (data) {
24215            var ids = [], filtered = [], self = this;
24216
24217            // filter out duplicates
24218            $(data).each(function () {
24219                if (indexOf(self.id(this), ids) < 0) {
24220                    ids.push(self.id(this));
24221                    filtered.push(this);
24222                }
24223            });
24224            data = filtered;
24225
24226            this.selection.find(".select2-search-choice").remove();
24227            $(data).each(function () {
24228                self.addSelectedChoice(this);
24229            });
24230            self.postprocessResults();
24231        },
24232
24233        // multi
24234        tokenize: function() {
24235            var input = this.search.val();
24236            input = this.opts.tokenizer.call(this, input, this.data(), this.bind(this.onSelect), this.opts);
24237            if (input != null && input != undefined) {
24238                this.search.val(input);
24239                if (input.length > 0) {
24240                    this.open();
24241                }
24242            }
24243
24244        },
24245
24246        // multi
24247        onSelect: function (data, options) {
24248
24249            if (!this.triggerSelect(data)) { return; }
24250
24251            this.addSelectedChoice(data);
24252
24253            this.opts.element.trigger({ type: "selected", val: this.id(data), choice: data });
24254
24255            // keep track of the search's value before it gets cleared
24256            this.nextSearchTerm = this.opts.nextSearchTerm(data, this.search.val());
24257
24258            this.clearSearch();
24259            this.updateResults();
24260
24261            if (this.select || !this.opts.closeOnSelect) this.postprocessResults(data, false, this.opts.closeOnSelect===true);
24262
24263            if (this.opts.closeOnSelect) {
24264                this.close();
24265                this.search.width(10);
24266            } else {
24267                if (this.countSelectableResults()>0) {
24268                    this.search.width(10);
24269                    this.resizeSearch();
24270                    if (this.getMaximumSelectionSize() > 0 && this.val().length >= this.getMaximumSelectionSize()) {
24271                        // if we reached max selection size repaint the results so choices
24272                        // are replaced with the max selection reached message
24273                        this.updateResults(true);
24274                    } else {
24275                        // initializes search's value with nextSearchTerm and update search result
24276                        if(this.nextSearchTerm != undefined){
24277                            this.search.val(this.nextSearchTerm);
24278                            this.updateResults();
24279                            this.search.select();
24280                        }
24281                    }
24282                    this.positionDropdown();
24283                } else {
24284                    // if nothing left to select close
24285                    this.close();
24286                    this.search.width(10);
24287                }
24288            }
24289
24290            // since its not possible to select an element that has already been
24291            // added we do not need to check if this is a new element before firing change
24292            this.triggerChange({ added: data });
24293
24294            if (!options || !options.noFocus)
24295                this.focusSearch();
24296        },
24297
24298        // multi
24299        cancel: function () {
24300            this.close();
24301            this.focusSearch();
24302        },
24303
24304        addSelectedChoice: function (data) {
24305            var enableChoice = !data.locked,
24306                enabledItem = $(
24307                    "<li class='select2-search-choice'>" +
24308                    "    <div></div>" +
24309                    "    <a href='#' class='select2-search-choice-close' tabindex='-1'></a>" +
24310                    "</li>"),
24311                disabledItem = $(
24312                    "<li class='select2-search-choice select2-locked'>" +
24313                    "<div></div>" +
24314                    "</li>");
24315            var choice = enableChoice ? enabledItem : disabledItem,
24316                id = this.id(data),
24317                val = this.getVal(),
24318                formatted,
24319                cssClass;
24320
24321            formatted=this.opts.formatSelection(data, choice.find("div"), this.opts.escapeMarkup);
24322            if (formatted != undefined) {
24323                choice.find("div").replaceWith("<div>"+formatted+"</div>");
24324            }
24325            cssClass=this.opts.formatSelectionCssClass(data, choice.find("div"));
24326            if (cssClass != undefined) {
24327                choice.addClass(cssClass);
24328            }
24329
24330            if(enableChoice){
24331              choice.find(".select2-search-choice-close")
24332                  .on("mousedown", killEvent)
24333                  .on("click dblclick", this.bind(function (e) {
24334                  if (!this.isInterfaceEnabled()) return;
24335
24336                  this.unselect($(e.target));
24337                  this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus");
24338                  killEvent(e);
24339                  this.close();
24340                  this.focusSearch();
24341              })).on("focus", this.bind(function () {
24342                  if (!this.isInterfaceEnabled()) return;
24343                  this.container.addClass("select2-container-active");
24344                  this.dropdown.addClass("select2-drop-active");
24345              }));
24346            }
24347
24348            choice.data("select2-data", data);
24349            choice.insertBefore(this.searchContainer);
24350
24351            val.push(id);
24352            this.setVal(val);
24353        },
24354
24355        // multi
24356        unselect: function (selected) {
24357            var val = this.getVal(),
24358                data,
24359                index;
24360            selected = selected.closest(".select2-search-choice");
24361
24362            if (selected.length === 0) {
24363                throw "Invalid argument: " + selected + ". Must be .select2-search-choice";
24364            }
24365
24366            data = selected.data("select2-data");
24367
24368            if (!data) {
24369                // prevent a race condition when the 'x' is clicked really fast repeatedly the event can be queued
24370                // and invoked on an element already removed
24371                return;
24372            }
24373
24374            var evt = $.Event("select2-removing");
24375            evt.val = this.id(data);
24376            evt.choice = data;
24377            this.opts.element.trigger(evt);
24378
24379            if (evt.isDefaultPrevented()) {
24380                return false;
24381            }
24382
24383            while((index = indexOf(this.id(data), val)) >= 0) {
24384                val.splice(index, 1);
24385                this.setVal(val);
24386                if (this.select) this.postprocessResults();
24387            }
24388
24389            selected.remove();
24390
24391            this.opts.element.trigger({ type: "select2-removed", val: this.id(data), choice: data });
24392            this.triggerChange({ removed: data });
24393
24394            return true;
24395        },
24396
24397        // multi
24398        postprocessResults: function (data, initial, noHighlightUpdate) {
24399            var val = this.getVal(),
24400                choices = this.results.find(".select2-result"),
24401                compound = this.results.find(".select2-result-with-children"),
24402                self = this;
24403
24404            choices.each2(function (i, choice) {
24405                var id = self.id(choice.data("select2-data"));
24406                if (indexOf(id, val) >= 0) {
24407                    choice.addClass("select2-selected");
24408                    // mark all children of the selected parent as selected
24409                    choice.find(".select2-result-selectable").addClass("select2-selected");
24410                }
24411            });
24412
24413            compound.each2(function(i, choice) {
24414                // hide an optgroup if it doesn't have any selectable children
24415                if (!choice.is('.select2-result-selectable')
24416                    && choice.find(".select2-result-selectable:not(.select2-selected)").length === 0) {
24417                    choice.addClass("select2-selected");
24418                }
24419            });
24420
24421            if (this.highlight() == -1 && noHighlightUpdate !== false){
24422                self.highlight(0);
24423            }
24424
24425            //If all results are chosen render formatNoMatches
24426            if(!this.opts.createSearchChoice && !choices.filter('.select2-result:not(.select2-selected)').length > 0){
24427                if(!data || data && !data.more && this.results.find(".select2-no-results").length === 0) {
24428                    if (checkFormatter(self.opts.formatNoMatches, "formatNoMatches")) {
24429                        this.results.append("<li class='select2-no-results'>" + evaluate(self.opts.formatNoMatches, self.search.val()) + "</li>");
24430                    }
24431                }
24432            }
24433
24434        },
24435
24436        // multi
24437        getMaxSearchWidth: function() {
24438            return this.selection.width() - getSideBorderPadding(this.search);
24439        },
24440
24441        // multi
24442        resizeSearch: function () {
24443            var minimumWidth, left, maxWidth, containerLeft, searchWidth,
24444                sideBorderPadding = getSideBorderPadding(this.search);
24445
24446            minimumWidth = measureTextWidth(this.search) + 10;
24447
24448            left = this.search.offset().left;
24449
24450            maxWidth = this.selection.width();
24451            containerLeft = this.selection.offset().left;
24452
24453            searchWidth = maxWidth - (left - containerLeft) - sideBorderPadding;
24454
24455            if (searchWidth < minimumWidth) {
24456                searchWidth = maxWidth - sideBorderPadding;
24457            }
24458
24459            if (searchWidth < 40) {
24460                searchWidth = maxWidth - sideBorderPadding;
24461            }
24462
24463            if (searchWidth <= 0) {
24464              searchWidth = minimumWidth;
24465            }
24466
24467            this.search.width(Math.floor(searchWidth));
24468        },
24469
24470        // multi
24471        getVal: function () {
24472            var val;
24473            if (this.select) {
24474                val = this.select.val();
24475                return val === null ? [] : val;
24476            } else {
24477                val = this.opts.element.val();
24478                return splitVal(val, this.opts.separator);
24479            }
24480        },
24481
24482        // multi
24483        setVal: function (val) {
24484            var unique;
24485            if (this.select) {
24486                this.select.val(val);
24487            } else {
24488                unique = [];
24489                // filter out duplicates
24490                $(val).each(function () {
24491                    if (indexOf(this, unique) < 0) unique.push(this);
24492                });
24493                this.opts.element.val(unique.length === 0 ? "" : unique.join(this.opts.separator));
24494            }
24495        },
24496
24497        // multi
24498        buildChangeDetails: function (old, current) {
24499            var current = current.slice(0),
24500                old = old.slice(0);
24501
24502            // remove intersection from each array
24503            for (var i = 0; i < current.length; i++) {
24504                for (var j = 0; j < old.length; j++) {
24505                    if (equal(this.opts.id(current[i]), this.opts.id(old[j]))) {
24506                        current.splice(i, 1);
24507                        if(i>0){
24508                          i--;
24509                        }
24510                        old.splice(j, 1);
24511                        j--;
24512                    }
24513                }
24514            }
24515
24516            return {added: current, removed: old};
24517        },
24518
24519
24520        // multi
24521        val: function (val, triggerChange) {
24522            var oldData, self=this;
24523
24524            if (arguments.length === 0) {
24525                return this.getVal();
24526            }
24527
24528            oldData=this.data();
24529            if (!oldData.length) oldData=[];
24530
24531            // val is an id. !val is true for [undefined,null,'',0] - 0 is legal
24532            if (!val && val !== 0) {
24533                this.opts.element.val("");
24534                this.updateSelection([]);
24535                this.clearSearch();
24536                if (triggerChange) {
24537                    this.triggerChange({added: this.data(), removed: oldData});
24538                }
24539                return;
24540            }
24541
24542            // val is a list of ids
24543            this.setVal(val);
24544
24545            if (this.select) {
24546                this.opts.initSelection(this.select, this.bind(this.updateSelection));
24547                if (triggerChange) {
24548                    this.triggerChange(this.buildChangeDetails(oldData, this.data()));
24549                }
24550            } else {
24551                if (this.opts.initSelection === undefined) {
24552                    throw new Error("val() cannot be called if initSelection() is not defined");
24553                }
24554
24555                this.opts.initSelection(this.opts.element, function(data){
24556                    var ids=$.map(data, self.id);
24557                    self.setVal(ids);
24558                    self.updateSelection(data);
24559                    self.clearSearch();
24560                    if (triggerChange) {
24561                        self.triggerChange(self.buildChangeDetails(oldData, self.data()));
24562                    }
24563                });
24564            }
24565            this.clearSearch();
24566        },
24567
24568        // multi
24569        onSortStart: function() {
24570            if (this.select) {
24571                throw new Error("Sorting of elements is not supported when attached to <select>. Attach to <input type='hidden'/> instead.");
24572            }
24573
24574            // collapse search field into 0 width so its container can be collapsed as well
24575            this.search.width(0);
24576            // hide the container
24577            this.searchContainer.hide();
24578        },
24579
24580        // multi
24581        onSortEnd:function() {
24582
24583            var val=[], self=this;
24584
24585            // show search and move it to the end of the list
24586            this.searchContainer.show();
24587            // make sure the search container is the last item in the list
24588            this.searchContainer.appendTo(this.searchContainer.parent());
24589            // since we collapsed the width in dragStarted, we resize it here
24590            this.resizeSearch();
24591
24592            // update selection
24593            this.selection.find(".select2-search-choice").each(function() {
24594                val.push(self.opts.id($(this).data("select2-data")));
24595            });
24596            this.setVal(val);
24597            this.triggerChange();
24598        },
24599
24600        // multi
24601        data: function(values, triggerChange) {
24602            var self=this, ids, old;
24603            if (arguments.length === 0) {
24604                 return this.selection
24605                     .children(".select2-search-choice")
24606                     .map(function() { return $(this).data("select2-data"); })
24607                     .get();
24608            } else {
24609                old = this.data();
24610                if (!values) { values = []; }
24611                ids = $.map(values, function(e) { return self.opts.id(e); });
24612                this.setVal(ids);
24613                this.updateSelection(values);
24614                this.clearSearch();
24615                if (triggerChange) {
24616                    this.triggerChange(this.buildChangeDetails(old, this.data()));
24617                }
24618            }
24619        }
24620    });
24621
24622    $.fn.select2 = function () {
24623
24624        var args = Array.prototype.slice.call(arguments, 0),
24625            opts,
24626            select2,
24627            method, value, multiple,
24628            allowedMethods = ["val", "destroy", "opened", "open", "close", "focu
24628s", "isFocused", "container", "dropdown", "onSortStart", "onSortEnd", "enable", "disable", "readonly", "positionDropdown", "data", "search"],
24629            valueMethods = ["opened", "isFocused", "container", "dropdown"],
24630            propertyMethods = ["val", "data"],
24631            methodsMap = { search: "externalSearch" };
24632
24633        this.each(function () {
24634            if (args.length === 0 || typeof(args[0]) === "object") {
24635                opts = args.length === 0 ? {} : $.extend({}, args[0]);
24636                opts.element = $(this);
24637
24638                if (opts.element.get(0).tagName.toLowerCase() === "select") {
24639                    multiple = opts.element.prop("multiple");
24640                } else {
24641                    multiple = opts.multiple || false;
24642                    if ("tags" in opts) {opts.multiple = multiple = true;}
24643                }
24644
24645                select2 = multiple ? new window.Select2["class"].multi() : new window.Select2["class"].single();
24646                select2.init(opts);
24647            } else if (typeof(args[0]) === "string") {
24648
24649                if (indexOf(args[0], allowedMethods) < 0) {
24650                    throw "Unknown method: " + args[0];
24651                }
24652
24653                value = undefined;
24654                select2 = $(this).data("select2");
24655                if (select2 === undefined) return;
24656
24657                method=args[0];
24658
24659                if (method === "container") {
24660                    value = select2.container;
24661                } else if (method === "dropdown") {
24662                    value = select2.dropdown;
24663                } else {
24664                    if (methodsMap[method]) method = methodsMap[method];
24665
24666                    value = select2[method].apply(select2, args.slice(1));
24667                }
24668                if (indexOf(args[0], valueMethods) >= 0
24669                    || (indexOf(args[0], propertyMethods) >= 0 && args.length == 1)) {
24670                    return false; // abort the iteration, ready to return first matched value
24671                }
24672            } else {
24673                throw "Invalid arguments to select2 plugin: " + args;
24674            }
24675        });
24676        return (value === undefined) ? this : value;
24677    };
24678
24679    // plugin defaults, accessible to users
24680    $.fn.select2.defaults = {
24681        width: "copy",
24682        loadMorePadding: 0,
24683        closeOnSelect: true,
24684        openOnEnter: true,
24685        containerCss: {},
24686        dropdownCss: {},
24687        containerCssClass: "",
24688        dropdownCssClass: "",
24689        formatResult: function(result, container, query, escapeMarkup) {
24690            var markup=[];
24691            markMatch(result.text, query.term, markup, escapeMarkup);
24692            return markup.join("");
24693        },
24694        formatSelection: function (data, container, escapeMarkup) {
24695            return data ? escapeMarkup(data.text) : undefined;
24696        },
24697        sortResults: function (results, container, query) {
24698            return results;
24699        },
24700        formatResultCssClass: function(data) {return data.css;},
24701        formatSelectionCssClass: function(data, container) {return undefined;},
24702        formatMatches: function (matches) { return matches + " results are available, use up and down arrow keys to navigate."; },
24703        formatNoMatches: function () { return "No matches found"; },
24704        formatInputTooShort: function (input, min) { var n = min - input.length; return "Please enter " + n + " or more character" + (n == 1? "" : "s"); },
24705        formatInputTooLong: function (input, max) { var n = input.length - max; return "Please delete " + n + " character" + (n == 1? "" : "s"); },
24706        formatSelectionTooBig: function (limit) { return "You can only select " + limit + " item" + (limit == 1 ? "" : "s"); },
24707        formatLoadMore: function (pageNumber) { return "Loading more results…"; },
24708        formatSearching: function () { return "Searching…"; },
24709        minimumResultsForSearch: 0,
24710        minimumInputLength: 0,
24711        maximumInputLength: null,
24712        maximumSelectionSize: 0,
24713        id: function (e) { return e == undefined ? null : e.id; },
24714        matcher: function(term, text) {
24715            return stripDiacritics(''+text).toUpperCase().indexOf(stripDiacritics(''+term).toUpperCase()) >= 0;
24716        },
24717        separator: ",",
24718        tokenSeparators: [],
24719        tokenizer: defaultTokenizer,
24720        escapeMarkup: defaultEscapeMarkup,
24721        blurOnChange: false,
24722        selectOnBlur: false,
24723        adaptContainerCssClass: function(c) { return c; },
24724        adaptDropdownCssClass: function(c) { return null; },
24725        nextSearchTerm: function(selectedObject, currentSearchTerm) { return undefined; },
24726        searchInputPlaceholder: '',
24727        createSearchChoicePosition: 'top',
24728        shouldFocusInput: function (instance) {
24729            // Attempt to detect touch devices
24730            var supportsTouchEvents = (('ontouchstart' in window) ||
24731                                       (navigator.msMaxTouchPoints > 0));
24732
24733            // Only devices which support touch events should be special cased
24734            if (!supportsTouchEvents) {
24735                return true;
24736            }
24737
24738            // Never focus the input if search is disabled
24739            if (instance.opts.minimumResultsForSearch < 0) {
24740                return false;
24741            }
24742
24743            return true;
24744        }
24745    };
24746
24747    $.fn.select2.ajaxDefaults = {
24748        transport: $.ajax,
24749        params: {
24750            type: "GET",
24751            cache: false,
24752            dataType: "json"
24753        }
24754    };
24755
24756    // exports
24757    window.Select2 = {
24758        query: {
24759            ajax: ajax,
24760            local: local,
24761            tags: tags
24762        }, util: {
24763            debounce: debounce,
24764            markMatch: markMatch,
24765            escapeMarkup: defaultEscapeMarkup,
24766            stripDiacritics: stripDiacritics
24767        }, "class": {
24768            "abstract": AbstractSelect2,
24769            "single": SingleSelect2,
24770            "multi": MultiSelect2
24771        }
24772    };
24773
24774}(jQuery));
24775
24776
24777/**
24778 * Select2 translations
24779 */
24780(function ($) {
24781  "use strict";
24782  if (getContentLanguage() === 'de') {
24783    $.extend($.fn.select2.defaults, {
24784        formatNoMatches: function () { return "Keine Übereinstimmungen gefunden"; },
24785        formatInputTooShort: function (input, min) { var n = min - input.length; return "Bitte " + n + " Zeichen mehr eingeben"; },
24786        formatInputTooLong: function (input, max) { var n = input.length - max; return "Bitte " + n + " Zeichen weniger eingeben"; },
24787        formatSelectionTooBig: function (limit) { return "Sie können nur " + limit + " Eintr" + (limit === 1 ? "ag" : "äge") + " auswählen"; },
24788        formatLoadMore: function (pageNumber) { return "Lade mehr Ergebnisse…"; },
24789        formatSearching: function () { return "Suche…"; }
24790    });
24791  }
24792})(jQuery);
24793
24794/**
24795 * Select2 bindings
24796 */
24797$(function(){
24798  window.format_select2_image = function(state) {
24799    var originalOption = state.element;
24800    if ($(originalOption).data('thumb-url')) {
24801      return "<img style='width: 30px; margin-right: 10px;' src='" + $(originalOption).data('thumb-url') + "' />" + state.text;
24802    } else {
24803      return state.text;
24804    }
24805  };
24806
24807  $('.select2-connectable').select2({
24808    formatResult: window.format_select2_image,
24809    formatSelection: window.format_select2_image,
24810    escapeMarkup: function(m) { return m; }
24811  });
24812
24813
24814  $('.select2-image-connectable').select2({
24815    placeholder: '[Auswählen]',
24816    allowClear: true,
24817    formatResult: window.format_select2_image,
24818    formatSelection: window.format_select2_image,
24819    escapeMarkup: function(m) { return m; }
24820  });
24821});
24822
24823
24824(function() {
24825  window.SocialShareButton = {
24826    openUrl: function(url) {
24827      window.open(url);
24828      return false;
24829    },
24830    share: function(el) {
24831      var get_tumblr_extra, img, site, title, tumblr_params, url;
24832      site = $(el).data('site');
24833      title = encodeURIComponent($(el).parent().data('title') || '');
24834      img = encodeURIComponent($(el).parent().data("img") || '');
24835      url = encodeURIComponent($(el).parent().data("url") || '');
24836      if (url.length === 0) {
24837        url = encodeURIComponent(location.href);
24838      }
24839      switch (site) {
24840        case "email":
24841          location.href = "mailto:?to=&subject=" + title + "&body=" + url;
24842          break;
24843        case "weibo":
24844          SocialShareButton.openUrl("http://service.weibo.com/share/share.php?url=" + url + "&type=3&pic=" + img + "&title=" + title);
24845          break;
24846        case "twitter":
24847          SocialShareButton.openUrl("https://twitter.com/home?status=" + title + ": " + url);
24848          break;
24849        case "douban":
24850          SocialShareButton.openUrl("http://shuo.douban.com/!service/share?href=" + url + "&name=" + title + "&image=" + img);
24851          break;
24852        case "facebook":
24853          SocialShareButton.openUrl("http://www.facebook.com/sharer.php?u=" + url);
24854          break;
24855        case "qq":
24856          SocialShareButton.openUrl("http://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url=" + url + "&title=" + title + "&pics=" + img);
24857          break;
24858        case "tqq":
24859          SocialShareButton.openUrl("http://share.v.t.qq.com/index.php?c=share&a=index&url=" + url + "&title=" + title + "&pic=" + img);
24860          break;
24861        case "baidu":
24862          SocialShareButton.openUrl("http://hi.baidu.com/pub/show/share?url=" + url + "&title=" + title + "&content=");
24863          break;
24864        case "kaixin001":
24865          SocialShareButton.openUrl("http://www.kaixin001.com/rest/records.php?url=" + url + "&content=" + title + "&style=11&pic=" + img);
24866          break;
24867        case "renren":
24868          SocialShareButton.openUrl("http://widget.renren.com/dialog/share?resourceUrl=" + url + "&srcUrl=" + url + "&title=" + title + "&pic=" + img + "&description=");
24869          break;
24870        case "google_plus":
24871          SocialShareButton.openUrl("https://plus.google.com/share?url=" + url);
24872          break;
24873        case "google_bookmark":
24874          SocialShareButton.openUrl("https://www.google.com/bookmarks/mark?op=edit&output=popup&bkmk=" + url + "&title=" + title);
24875          break;
24876        case "delicious":
24877          SocialShareButton.openUrl("http://www.delicious.com/save?url=" + url + "&title=" + title + "&jump=yes&pic=" + img);
24878          break;
24879        case "plurk":
24880          SocialShareButton.openUrl("http://www.plurk.com/?status=" + title + ": " + url + "&qualifier=shares");
24881          break;
24882        case "pinterest":
24883          SocialShareButton.openUrl("http://www.pinterest.com/pin/create/button/?url=" + url + "&media=" + img + "&description=" + title);
24884          break;
24885        case "tumblr":
24886          get_tumblr_extra = function(param) {
24887            var cutom_data;
24888            cutom_data = $(el).attr("data-" + param);
24889            if (cutom_data) {
24890              return encodeURIComponent(cutom_data);
24891            }
24892          };
24893          tumblr_params = function() {
24894            var params, path, quote, source;
24895            path = get_tumblr_extra('type') || 'link';
24896            params = (function() {
24897              switch (path) {
24898                case 'text':
24899                  title = get_tumblr_extra('title') || title;
24900                  return "title=" + title;
24901                case 'photo':
24902                  title = get_tumblr_extra('caption') || title;
24903                  source = get_tumblr_extra('source') || img;
24904                  return "caption=" + title + "&source=" + source;
24905                case 'quote':
24906                  quote = get_tumblr_extra('quote') || title;
24907                  source = get_tumblr_extra('source') || '';
24908                  return "quote=" + quote + "&source=" + source;
24909                default:
24910                  title = get_tumblr_extra('title') || title;
24911                  url = get_tumblr_extra('url') || url;
24912                  return "name=" + title + "&url=" + url;
24913              }
24914            })();
24915            return "/" + path + "?" + params;
24916          };
24917          SocialShareButton.openUrl("http://www.tumblr.com/share" + (tumblr_params()));
24918      }
24919      return false;
24920    }
24921  };
24922
24923}).call(this);
24924(function($, window, undefined) {
24925    "use strict";
24926
24927    //regex
24928    var rtextshadow = /(-?\d+px|(?:hsl|rgb)a?\(.+?\)|#(?:[a-fA-F0-9]{3}){1,2}|0)/g,
24929        rtextshadowsplit = /(,)(?=(?:[^\)]|\([^\)]*\))*$)/,
24930        rcolortest = /^((?:rgb|hsl)a?|#)/,
24931        rcolor = /(rgb|hsl)a?\(\s*(\d+)\s*,\s*(\d+)%?\s*,\s*(\d+)%?(?:\s*,\s*([\.\d]+))?/,
24932        rshadowsplit = /(,)(?=(?:[^\)]|\([^\)]*\))*$)/g,
24933        filter = "progid:DXImageTransform.Microsoft.",
24934        marker = '\u2063',
24935        rmarker = /\u2063/g,
24936        rbreakleft = /([\(\[\{])/g,
24937        rbreakright = /([\)\]\}%°\!\?\u2014])/g,
24938        rbreakboth = /([\-\u2013])/g,
24939        rsplit = /[\s\u2063]/,
24940        rspace = /(\s*)/g,
24941        rspaceonly = /^\s*$/,
24942        rprespace = /^(\s*)/,
24943        prefix = "ui-text-shadow";
24944    
24945    // create a plugin
24946    $.fn.textshadow = function(value, options) {
24947        if (typeof value === 'object' && !options) {
24948            options = value;
24949            value = null;
24950        }
24951        var opts = options || {},
24952            useStyle = opts.useStyle === false ? false : true,
24953            numShadows = opts.numShadows || 1,
24954            doDestroy = opts.destroy || false;
24955        
24956        // handle clearing all of the shadows
24957        if (doDestroy) {
24958            return this.each(function() {
24959                destroy(this);
24960            });
24961        }
24962
24963        // loop the found items
24964        return this.each(function() {
24965            var $elem = $(this),
24966                copySelector = '.' + prefix + '-copy',
24967                $copy;
24968            
24969            // find the copy elements
24970            $copy = $elem.find(copySelector);
24971
24972            // create them if none exist
24973            if (!$copy.length) {
24974                // create all of the elements
24975                allWords(this);
24976                $copy = $elem.find(copySelector);
24977            }
24978            if (useStyle) {
24979                applyStyles($copy, value);
24980            } else if (numShadows > 1) {
24981                $copy.filter(copySelector + '-1').each(function() {
24982                    var i = 1,
24983                        $parent = $(this.parentNode),
24984                        shadowSelector, $elem;
24985                    while (i < numShadows) {
24986                        shadowSelector = copySelector + '-' + (i + 1);
24987                        if (!$parent.find(shadowSelector).length) {
24988                            $elem = $(this.cloneNode(true))
24989                                .addClass(shadowSelector.substring(1))
24990                                .removeClass(prefix + '-copy-1');
24991                            $parent.prepend($elem);
24992                        }
24993                        i++;
24994                    }
24995                });
24996            }
24997        });
24998    };
24999
25000    
25001    //---------------------
25002    // For splitting words
25003    //---------------------
25004    // function for returning all words in an element as text nodes
25005    function allWords(elem) {
25006        $(elem).contents().each(function() {
25007            if (this.nodeType === 3 && this.data) {
25008                makeWords(this);
25009                return true;
25010            }
25011            
25012            var $elem = $(this);
25013            if (this.nodeType === 1 && (!$elem.hasClass(prefix) || !$elem.hasClass(prefix + '-original') || !$elem.hasClass(prefix + '-copy'))) {
25014                allWords(this);
25015                return true;
25016            }
25017        });
25018    }
25019    
25020    // splits text nodes
25021    function makeWords(textNode) {
25022        // Split the text in the node by space characters
25023        var split, length, spaces, node,
25024            text = textNode.nodeValue,
25025            lastIndex = 0;
25026
25027        // Skip empty nodes or nodes that are only whitespace
25028        if (!text || /^\s*$/.test(text)) {
25029            return;
25030        }
25031
25032        //correct for IE break characters
25033        //leave a strange unicode character as a marker
25034        text = text.replace(rbreakleft, marker + '$1')
25035                .replace(rbreakright, '$1' + marker)
25036                .replace(rbreakboth, marker + '$1' + marker);
25037
25038        // split the string by break characters
25039        split = text.split(rsplit);
25040        
25041        // remove our markers
25042        text = text.replace(rmarker, '');
25043
25044        // Add the original string (it gets split)
25045        var fragment = document.createDocumentFragment();
25046        
25047        // set the "last index" based on leading whitespace
25048        lastIndex = rprespace.exec(text)[1].length;
25049
25050        // loop by the splits
25051        $.each(split, function() {
25052            length = this.length;
25053
25054            // IE9 will return empty splits (consecutive spaces)
25055            if (!length) {
25056                return true;
25057            }
25058
25059            //include the trailing space characters
25060            rspace.lastIndex = lastIndex + length;
25061            spaces = rspace.exec(text);         
25062            
25063            // slice out our text
25064            // create a new node with it
25065            node = wrapWord(text.substr(lastIndex, length + spaces[1].length));
25066            if (node !== null) {
25067                fragment.appendChild(node);
25068            }
25069            lastIndex = lastIndex + length + spaces[1].length;
25070        });
25071        textNode.parentNode.replaceChild(fragment.cloneNode(true), textNode);
25072    }
25073    
25074    var shadowNode = $('<span class="' + prefix + '" />')[0],
25075        origNode = $('<span class="' + prefix + '-original" />')[0],
25076        copyNode = $('<span class="' + prefix + '-copy ' + prefix + '-copy-1" />')[0];
25077
25078    // Removes the generated elements
25079    function destroy(elem) {
25080        var $elem = $(elem);
25081
25082        $elem.find('.' + prefix + '-copy').remove();
25083        $elem.find('.' + prefix + '-original').unwrap().each(function() {
25084            $(this).replaceWith(this.childNodes);
25085        });
25086    }
25087
25088    // Wrap words in generated elements
25089    function wrapWord(text) {
25090        if (!text.length) { // IE 9
25091            return null;
25092        }
25093        var shadow = shadowNode.cloneNode(false),
25094            orig = origNode.cloneNode(false),
25095            copy = copyNode.cloneNode(false);
25096            
25097        shadow.appendChild(copy);
25098        shadow.appendChild(orig);
25099        
25100        orig.appendChild(document.createTextNode(text));
25101        copy.appendChild(document.createTextNode(text));
25102
25103        return shadow;
25104    }
25105    
25106    //---------------------
25107    // For Applying Styles
25108    //---------------------
25109    function applyStyles($copy, value) {
25110        // skip this if there's no currentStyle property
25111        if ($copy.length && !$copy[0].currentStyle) { return; }
25112
25113        // this will work in IE
25114        $copy.each(function() {
25115            var copy = this,
25116                style = value || copy.currentStyle['text-shadow'],
25117                $copy = $(copy),
25118                parent = copy.parentNode,
25119                shadows, i = 0;
25120            
25121            // ensure we have the correct style using inheritence
25122            while ((!style || style === 'none') && parent.nodeName !== 'HTML') {
25123                style = parent.currentStyle['text-shadow'];
25124                parent = parent.parentNode;
25125            }
25126            
25127            // don't apply style if we can't find one
25128            if (!style || style === 'none') {
25129                return true;
25130            }
25131            
25132            // split the style, in case of multiple shadows
25133            shadows = style.split(rtextshadowsplit);
25134
25135            // loop by the splits
25136            $.each(shadows, function() {
25137                var shadow = this;
25138
25139                if (shadow == ',') { // IE 9
25140                    return true;
25141                }
25142
25143                // parse the style
25144                var values = shadow.match(rtextshadow),
25145                    color = 'inherit',
25146                    opacity = 1,
25147                    x, y, blur, $elem;
25148
25149                // capture the values
25150
25151                // pull out the color from either the first or last position
25152                // actually remove it from the array
25153                if (rcolortest.test(values[0])) {
25154                    opacity = getAlpha(values[0]);
25155                    color = toHex(values.shift());
25156                } else if (rcolortest.test(values[values.length - 1])) {
25157                    opacity = getAlpha(values[values.length - 1]);
25158                    color = toHex(values.pop());
25159                }
25160
25161                x = parseFloat(values[0]); // TODO: handle units
25162                y = parseFloat(values[1]); // TODO: handle units
25163                blur = values[2] !== undefined ? parseFloat(values[2]) : 0; // TODO: handle units
25164                
25165                // create new shadows when multiple shadows exist
25166                if (i == 0) {
25167                    $elem = $copy;
25168                } else {
25169                    $elem = $copy.clone().prependTo($copy.parent())
25170                        .addClass(prefix + '-copy-' + (i + 1))
25171                        .removeClass(prefix + '-copy-1');
25172                }
25173
25174                // style the element
25175                $elem.css({
25176                    color: color,
25177                    left: (x - blur) + 'px',
25178                    top: (y - blur) + 'px'
25179                });
25180                
25181                // add in the filters
25182                if (opacity < 1 || blur > 0) {
25183                    $elem[0].style.filter = [
25184                        opacity < 1 ? filter + "Alpha(opacity=" + parseInt(opacity * 100, 10) + ") " : '',
25185                        blur > 0 ? filter + "Blur(pixelRadius=" + blur + ")" : ''
25186                    ].join('');
25187                }
25188                i++;
25189            });
25190        });
25191    }
25192    
25193    //---------------------
25194    // For Colors
25195    //---------------------
25196    // http://haacked.com/archive/2009/12/29/convert-rgb-to-hex.aspx
25197    function toHex(color) {
25198        // handle rgb
25199        var matches = rcolor.exec(color), rgb;
25200        
25201        // handle hsl
25202        if (matches && matches[1] === 'hsl') {
25203            rgb = hsl2rgb(matches[2], matches[3], matches[4]);
25204            matches[2] = rgb[0];
25205            matches[3] = rgb[1];
25206            matches[4] = rgb[2];
25207        }
25208        
25209        // convert to hex
25210        return matches ? '#' + (1 << 24 | matches[2] << 16 | matches[3] << 8 | matches[4]).toString(16).substr(1) : color;
25211    }
25212    
25213    function getAlpha(color) {
25214        var matches = rcolor.exec(color);
25215        if (matches) {
25216            return matches[5] !== undefined ? matches[5] : 1; 
25217        }
25218        return 1;
25219    }
25220    
25221    // http://www.codingforums.com/showthread.php?t=11156
25222    function hsl2rgb(h, s, l) {
25223        var m1, m2, hue, r, g, b;
25224        s /=100;
25225        l /= 100;
25226        if (s === 0) {
25227            r = g = b = (l * 255);
25228        } else {
25229            if (l <= 0.5) {
25230                m2 = l * (s + 1);
25231            } else {
25232                m2 = l + s - l * s;
25233            }
25234            m1 = l * 2 - m2;
25235            hue = h / 360;
25236            r = hue2rgb(m1, m2, hue + 1/3);
25237            g = hue2rgb(m1, m2, hue);
25238            b = hue2rgb(m1, m2, hue - 1/3);
25239        }
25240        return [r, g, b];
25241    }
25242    
25243    function hue2rgb(m1, m2, hue) {
25244        var v;
25245        if (hue < 0) {
25246            hue += 1;
25247        } else if (hue > 1) {
25248            hue -= 1;
25249        }
25250
25251        if (6 * hue < 1) {
25252            v = m1 + (m2 - m1) * hue * 6;
25253        } else if (2 * hue < 1) {
25254            v = m2;
25255        } else if (3 * hue < 2) {
25256            v = m1 + (m2 - m1) * (2/3 - hue) * 6;
25257        } else {
25258            v = m1;
25259        }
25260
25261        return 255 * v;
25262    }
25263})(jQuery, this);
25264window.searchbaractivity = false;
25265window.windowWidth = $(window).width();
25266window.screen_sm = 768;
25267
25268
25269// ---------------
25270
25271
25272// header utilities ux
25273
25274// let the header dropdowns open on over and do nothing on click if no-touch
25275$(document).ready(function() {
25276  // check back if this is not a touch device
25277  if($("html").hasClass("no-touch")) {
25278    apply_navbar_mouseevents(false);
25279  }
25280  fix_dropdown_form();
25281});
25282
25283
25284
25285// ---------------
25286
25287
25288// open navbar dropdowns on hover
25289function apply_navbar_mouseevents(custom_selector) {
25290
25291  if (custom_selector === false) {
25292    $selector = $("#header-container li.dropdown");
25293  } else {
25294    $selector = custom_selector;
25295  }
25296
25297  // enable dropdown hover
25298  $selector.find("a.dropdown-toggle").mouseenter(function(){
25299    $this = $(this);
25300    $dropdown = $this.parent();
25301
25302    if($dropdown.hasClass("open") === false) {
25303      $this.dropdown('toggle');
25304
25305      // focus search input
25306      if ($dropdown.hasClass("dropdown-search")) {
25307        $dropdown.find("input").focus();
25308      }
25309    }
25310  });
25311  $selector.mouseleave(function(){
25312    $this = $(this);
25313    if ($this.hasClass('dropdown-flags')) {
25314      if($this.hasClass("open") === true) {
25315        $this.find("a.dropdown-toggle").dropdown('toggle');
25316      }
25317      $this.find("a.dropdown-toggle").blur();
25318    }
25319  });
25320};
25321function close_nav_dropdowns() {
25322  $('.nav .dropdown.open').dropdown('toggle');
25323}
25324
25325function fix_dropdown_form() {
25326  $('.dropdown .dropdown-menu form, .dropdown .dropdown-menu input, .dropdown .dropdown-menu a, .dropdown .dropdown-menu .checkbox, .dropdown .dropdown-menu button').bind('click', function (e) { e.stopPropagation() });
25327};
25328function reconnect_navbar_dropdowns() {
25329  $("#header-container li.dropdown a.dropdown-toggle").dropdown();
25330  fix_dropdown_form();
25331
25332  // check back if this is not a touch device
25333  if($("html").hasClass("no-touch")) {
25334    apply_navbar_mouseevents($("#meta-nav"));
25335  }
25336};
25337
25338
25339// ---------------
25340
25341
25342function add_browser_classes(classes) {
25343  $("body").addClass(classes);
25344
25345  $.event.trigger({
25346    type: "browserClassesAdded",
25347    message: "Hello World!",
25348    time: new Date()
25349  });
25350}
25351
25352
25353// enable navigation hovering
25354function swapped_navigation() {
25355  // hover-navigation
25356  if($("html").hasClass("no-touch")) {
25357    enable_no_touch_navigation_hover();
25358  }
25359  if($("html").hasClass("touch")) {
25360    enable_touch_navigation_hover();
25361  }
25362}
25363
25364function enable_no_touch_navigation_hover() {
25365  $('#mainnavigation .navbar-nav > li').hover(function() {
25366    var $this = $(this);
25367    var nav_hover = $this.find(".navigation-hover");
25368
25369    if (nav_hover.length > 0) {
25370      if ($this.parent().hasClass('open')) {
25371        // $this.find('.navigation-hover').show();
25372        clearTimeout(window.mainNavHover);
25373        return true;
25374      }
25375      clearTimeout(window.mainNavHover);
25376      window.mainNavHover = setTimeout(function() {
25377        $this.addClass('open');
25378
25379        close_nav_dropdowns();
25380
25381        // $this.find('.navigation-hover').show();
25382      }, 400);
25383    }
25384  }, function() {
25385    var $this = $(this);
25386    clearTimeout(window.mainNavHover);
25387    // $this.find('.navigation-hover').hide();
25388  });
25389
25390  $('.navigation-hover').mouseleave(function() {
25391    $(this).closest("li").removeClass('open');
25392  });
25393  $('.navigation-hover').parent().mouseleave(function() {
25394    $(this).removeClass('open');
25395  });
25396}
25397function enable_touch_navigation_hover() {
25398  $hover_navs = $(".navigation-hover");
25399
25400  $("#mainnavigation .navbar-left > li > a").click(function(){
25401    $trigger = $(this);
25402    $nav_li = $trigger.parent();
25403    $hover_nav = $nav_li.find(".navigation-hover");
25404    hover_state = ($nav_li.hasClass("open") ? "open" : "closed");
25405    has_hover_nav = ($hover_nav.length > 0 ? true : false);
25406
25407    // close all hover navs
25408    hide_hover_navs($hover_navs);
25409
25410    // open desired hover nav
25411    if (hover_state == "closed" && has_hover_nav) {
25412      open_hover_nav(this);
25413      return false;
25414    } else {
25415      return true;
25416    }
25417  });
25418
25419  $(document).click(function(){
25420    // close all hover navs
25421    hide_hover_navs($hover_navs);
25422  });
25423}
25424
25425function open_hover_nav(trigger) {
25426  // add direct hover class to parent
25427  $(trigger).parent().addClass("open");
25428
25429  close_nav_dropdowns();
25430
25431  // show nav
25432  $(trigger).parent().find(".navigation-hover").show();
25433}
25434function hide_hover_navs(hover_navs) {
25435  hover_navs.each(function(){
25436    $this = $(this);
25437    $this.parent().removeClass("open");
25438    // $this.hide();
25439  });
25440}
25441
25442
25443
25444
25445
25446
25447// affix header
25448// $(document).ready(function() {
25449//   $skysraper = $(".bme-ad-wallpaper-wrapper .bme-ad-skyscraper"); // bme-ad-skyscraper:not(.bme-ad-wallpaper)
25450//   window.header_height = 200; //$("#header-container").first().outerHeight(true);
25451//
25452//   $('#header-container').affix({
25453//     offset: window.header_height + 100
25454//   });
25455//
25456//
25457//   $('#header-container').on('affixed.bs.affix', function () {
25458//     window.header_height = 200;
25459//     $(".page").css("margin-top", window.header_height);
25460//     $('#header-container').addClass('animated fadeInDown');
25461//   });
25462//
25463//   $('#header-container').on('affixed-top.bs.affix', function () {
25464//     $(".page").css("margin-top", 0);
25465//     $('#header-container').removeClass('animated fadeInDown');
25466//   });
25467// });
25468
25469
25470// tooltips
25471$(document).ready(function(){
25472  $('[data-toggle="tooltip"]').tooltip();
25473});
25474
25475
25476
25477// ---------------
25478
25479
25480
25481$(document).ready(function(){
25482  if($("body").data("env") == "development") {
25483    $(".nav.nav-pills.nav-stacked a, .sidebar-navigation a").each(function(){
25484      $this = $(this);
25485      href = $this.attr("href");
25486      target_url = window.location.protocol + "//" + window.location.host + href;
25487      current_url = document.URL;
25488
25489      if (current_url == target_url) {
25490        $this.toggleClass("active");
25491        $this.parent().toggleClass("active");
25492      }
25493    });
25494  }
25495});
25496
25497
25498
25499// ---------------
25500
25501
25502// start the image gallery
25503$(document).ready(function(){
25504  $(".play-image-gallery").click(function(){
25505    id = $(this).attr("data-target");
25506    if(id !== undefined) {
25507      $(id).find("a:first").click();
25508    } else {
25509      $(this).next(".teaser-listing-gallery").find("a:first").click();
25510    }
25511  });
25512});
25513
25514
25515
25516// --------------
25517
25518
25519// since bootstrap doesnt support -> just for the meta box
25520$(document).ready(function(){
25521  $('[data-parent]').click(function(){
25522    $this = $(this);
25523    parent = $this.data("parent");
25524    $parent = $(parent);
25525    target = $this.data("target");
25526    $target = $(target);
25527    $collapse_target = $this.data("collapse-target") + ".in";
25528
25529    // close all available header meta boxes
25530    $parent.find($collapse_target).each(function(){
25531      $box = $(this);
25532      $box.collapse('hide');
25533    });
25534
25535    // open the target
25536    $target.collapse('show');
25537  });
25538});
25539
25540
25541// --------------
25542
25543// ie8 textshadow
25544
25545$(document).ready(function(){
25546  if (!Modernizr.textshadow) {
25547    $('.header-branding h2').textshadow("0 1px 30px white, 0 1px 10px white, 0 1px 40px white, 0 1px 20px white");
25548  }
25549});
25550
25551
25552
25553// wrap tables within the responsive div
25554$(document).ready(function() {
25555  $(".page-content table").wrap('<div class="table-responsive"></div>');
25556});
25557
25558
25559// --------------
25560
25561
25562// headroom
25563$(document).ready(function() {
25564  window.header_height = 200;
25565
25566  $('#header-container').headroom({
25567    offset: $(".page").offset().top + 30,
25568    tolerance : {
25569      up : 0,
25570      down : 10
25571    },
25572    classes: {
25573      initial: 'headroom--initial',
25574      pinned: "headroom--pinned"
25575    },
25576    onPin: function() {
25577      $('#header-container').addClass('animated fadeInDown');
25578
25579      $('#header-container').one('animationend webkitAnimationEnd oAnimationEnd MSAnimationEnd', function(){
25580        $('#header-container').removeClass('animated fadeInDown');
25581      });
25582    },
25583    onUnpin: function() {
25584      $('#header-container').addClass('animated fadeOutUp');
25585
25586      $('#header-container').one('animationend webkitAnimationEnd oAnimationEnd MSAnimationEnd', function(){
25587        $('#header-container').removeClass('animated fadeOutUp');
25588      });
25589    },
25590    onTop: function() {
25591      $("#headroom-placeholder").remove();
25592      $('#header-container').removeClass('animated fadeInDown fadeOutUp');
25593    },
25594    onNotTop: function() {
25595      // add a placeholder to keep the scrollpoint
25596      var $div = '<div id="headroom-placeholder" style="height: ' + window.header_height + 'px;"></div>';
25597
25598      $('#header-container').before($($div));
25599
25600      // prevent animation for a small timeframe
25601      $('#header-container').addClass("disable-animations");
25602      setTimeout(function(){
25603        $('#header-container').removeClass("disable-animations");
25604      }, 700);
25605
25606      // don't pin asap
25607      $('#header-container').removeClass("headroom--pinned");
25608      setTimeout(function(){
25609        $('#header-container').removeClass("headroom--pinned");
25610      }, 50);
25611      setTimeout(function(){
25612        $('#header-container').removeClass("headroom--pinned");
25613      }, 100);
25614      setTimeout(function(){
25615        $('#header-container').removeClass("headroom--pinned");
25616      }, 150);
25617    }
25618  });
25619});
25620
25621
25622
25623
25624// feedback button
25625$(document).ready(function() {
25626  $btn = $('<a class="btn btn-feedback" href="https://app.smartsheet.com/b/form?EQBCT=7a395d139d2b4df39df8d00c86d0627c" target="_blank">Feedback</a>');
25627  path = window.location.pathname.split('/')[1]; // should be veranstaltungen
25628  subdomain = window.location.host.split('.')[0]; // should be shop
25629  breadcrumb = false
25630  if ($(".breadcrumb").length > 0) {
25631    breadcrumb = $(".breadcrumb").html().indexOf("Großveranstaltungen") !== -1;
25632  }
25633
25634  if (path == 'veranstaltungen' || subdomain == 'shop' || breadcrumb === true) {
25635    $('body').append($btn);
25636  }
25637});
25638
25639
25640// close nav dropdowns when hovering hover language icons on desktop
25641$(document).ready(function(){
25642  var $dropdown = $('.dropdown-flags');
25643  var $dropdown_menu = $dropdown.find('.dropdown-menu');
25644
25645  // close on hover if menu is relative
25646  if ($dropdown_menu.css('position') == 'relative') {
25647    $dropdown_menu.find('a').hover(function(){
25648      close_nav_dropdowns();
25649    });
25650  }
25651});
25652
25653
25654
25655// change wallpaper background color
25656$(document).ready(function(){
25657  adjust_wallpaper_styles();
25658});
25659$(window).load(function(){
25660  adjust_wallpaper_styles();
25661  setTimeout(adjust_wallpaper_styles, 1000);
25662  setTimeout(adjust_wallpaper_styles, 2000);
25663});
25664
25665function adjust_wallpaper_styles() {
25666  if (typeof p != 'undefined') {
25667    var wallpaperColor = p.backgroundColor;
25668    var sasTagId = window.sasTagId;
25669    var $wallpaperContainer = $('#' + sasTagId).first().find('.megabanner_background').first();
25670    var $banner = $("#" + window.sasTagId);
25671
25672    // apply color
25673    $wallpaperContainer.css('backgroundColor', "#" + wallpaperColor);
25674
25675    // remove style tag inserted by smartadserver
25676    var target_style_content = "background-color: #" + wallpaperColor + " !important;";
25677
25678    // add class to banner
25679    $banner.addClass('ad-wallpaper');
25680
25681    $('body').addClass('ad-has-wallpaper');
25682
25683    $('style').each(function(){
25684      var style = $(this);
25685      var style_html = style.html();
25686
25687      if (style_html.indexOf(target_style_content) >= 0) {
25688        style.remove();
25689      }
25690    })
25691  }
25692}
25693
25694
25695$(document).on("browserClassesAdded", function(){
25696
25697  $body = $("body");
25698
25699  if (!$body.hasClass("mobile") && !$body.hasClass("msie8") && !$body.hasClass("msie8")) {
25700    // get all hires images
25701    $hires = $("[data-hires]");
25702
25703    // loop through the images
25704    $hires.each(function(){
25705      $this = $(this);
25706      var hires_src = $this.data("hires");
25707      var src = $this.attr("src");
25708      var img = $this;
25709
25710      var img_call = $.ajax(hires_src)
25711      .success(function() {
25712
25713        // swap image if the hires alternative is available
25714        swap_hires_image(img, hires_src, src);
25715      });
25716    });
25717  }
25718});
25719
25720function swap_hires_image(element, hires_src, src) {
25721  $(element).attr("src", null);
25722  $(element).attr("src", hires_src);
25723  $(element).attr("data-original-src", src);
25724}
25725

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