PageSourceSearch

https://domains.box.co.il/assets/js/bundle.js?m=m10036

js box.co.il collected 2026-10-07 20:33:47 UTC 1,173,387 bytes, 39,301 lines download raw bytes

1/*!
2 * jQuery JavaScript Library v2.2.2
3 * http://jquery.com/
4 *
5 * Includes Sizzle.js
6 * http://sizzlejs.com/
7 *
8 * Copyright jQuery Foundation and other contributors
9 * Released under the MIT license
10 * http://jquery.org/license
11 *
12 * Date: 2016-03-17T17:51Z
13 */
14
15(function( global, factory ) {
16
17	if ( typeof module === "object" && typeof module.exports === "object" ) {
18		// For CommonJS and CommonJS-like environments where a proper `window`
19		// is present, execute the factory and get jQuery.
20		// For environments that do not have a `window` with a `document`
21		// (such as Node.js), expose a factory as module.exports.
22		// This accentuates the need for the creation of a real `window`.
23		// e.g. var jQuery = require("jquery")(window);
24		// See ticket #14549 for more info.
25		module.exports = global.document ?
26			factory( global, true ) :
27			function( w ) {
28				if ( !w.document ) {
29					throw new Error( "jQuery requires a window with a document" );
30				}
31				return factory( w );
32			};
33	} else {
34		factory( global );
35	}
36
37// Pass this if window is not defined yet
38}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
39
40// Support: Firefox 18+
41// Can't be in strict mode, several libs including ASP.NET trace
42// the stack via arguments.caller.callee and Firefox dies if
43// you try to trace through "use strict" call chains. (#13335)
44//"use strict";
45var arr = [];
46
47var document = window.document;
48
49var slice = arr.slice;
50
51var concat = arr.concat;
52
53var push = arr.push;
54
55var indexOf = arr.indexOf;
56
57var class2type = {};
58
59var toString = class2type.toString;
60
61var hasOwn = class2type.hasOwnProperty;
62
63var support = {};
64
65
66
67var
68	version = "2.2.2
vendor: 132,342 bytes, lines 68-5008
68",
69
70	// Define a local copy of jQuery
71	jQuery = function( selector, context ) {
72
73		// The jQuery object is actually just the init constructor 'enhanced'
74		// Need init if jQuery is called (just allow error to be thrown if not included)
75		return new jQuery.fn.init( selector, context );
76	},
77
78	// Support: Android<4.1
79	// Make sure we trim BOM and NBSP
80	rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
81
82	// Matches dashed string for camelizing
83	rmsPrefix = /^-ms-/,
84	rdashAlpha = /-([\da-z])/gi,
85
86	// Used by jQuery.camelCase as callback to replace()
87	fcamelCase = function( all, letter ) {
88		return letter.toUpperCase();
89	};
90
91jQuery.fn = jQuery.prototype = {
92
93	// The current version of jQuery being used
94	jquery: version,
95
96	constructor: jQuery,
97
98	// Start with an empty selector
99	selector: "",
100
101	// The default length of a jQuery object is 0
102	length: 0,
103
104	toArray: function() {
105		return slice.call( this );
106	},
107
108	// Get the Nth element in the matched element set OR
109	// Get the whole matched element set as a clean array
110	get: function( num ) {
111		return num != null ?
112
113			// Return just the one element from the set
114			( num < 0 ? this[ num + this.length ] : this[ num ] ) :
115
116			// Return all the elements in a clean array
117			slice.call( this );
118	},
119
120	// Take an array of elements and push it onto the stack
121	// (returning the new matched element set)
122	pushStack: function( elems ) {
123
124		// Build a new jQuery matched element set
125		var ret = jQuery.merge( this.constructor(), elems );
126
127		// Add the old object onto the stack (as a reference)
128		ret.prevObject = this;
129		ret.context = this.context;
130
131		// Return the newly-formed element set
132		return ret;
133	},
134
135	// Execute a callback for every element in the matched set.
136	each: function( callback ) {
137		return jQuery.each( this, callback );
138	},
139
140	map: function( callback ) {
141		return this.pushStack( jQuery.map( this, function( elem, i ) {
142			return callback.call( elem, i, elem );
143		} ) );
144	},
145
146	slice: function() {
147		return this.pushStack( slice.apply( this, arguments ) );
148	},
149
150	first: function() {
151		return this.eq( 0 );
152	},
153
154	last: function() {
155		return this.eq( -1 );
156	},
157
158	eq: function( i ) {
159		var len = this.length,
160			j = +i + ( i < 0 ? len : 0 );
161		return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );
162	},
163
164	end: function() {
165		return this.prevObject || this.constructor();
166	},
167
168	// For internal use only.
169	// Behaves like an Array's method, not like a jQuery method.
170	push: push,
171	sort: arr.sort,
172	splice: arr.splice
173};
174
175jQuery.extend = jQuery.fn.extend = function() {
176	var options, name, src, copy, copyIsArray, clone,
177		target = arguments[ 0 ] || {},
178		i = 1,
179		length = arguments.length,
180		deep = false;
181
182	// Handle a deep copy situation
183	if ( typeof target === "boolean" ) {
184		deep = target;
185
186		// Skip the boolean and the target
187		target = arguments[ i ] || {};
188		i++;
189	}
190
191	// Handle case when target is a string or something (possible in deep copy)
192	if ( typeof target !== "object" && !jQuery.isFunction( target ) ) {
193		target = {};
194	}
195
196	// Extend jQuery itself if only one argument is passed
197	if ( i === length ) {
198		target = this;
199		i--;
200	}
201
202	for ( ; i < length; i++ ) {
203
204		// Only deal with non-null/undefined values
205		if ( ( options = arguments[ i ] ) != null ) {
206
207			// Extend the base object
208			for ( name in options ) {
209				src = target[ name ];
210				copy = options[ name ];
211
212				// Prevent never-ending loop
213				if ( target === copy ) {
214					continue;
215				}
216
217				// Recurse if we're merging plain objects or arrays
218				if ( deep && copy && ( jQuery.isPlainObject( copy ) ||
219					( copyIsArray = jQuery.isArray( copy ) ) ) ) {
220
221					if ( copyIsArray ) {
222						copyIsArray = false;
223						clone = src && jQuery.isArray( src ) ? src : [];
224
225					} else {
226						clone = src && jQuery.isPlainObject( src ) ? src : {};
227					}
228
229					// Never move original objects, clone them
230					target[ name ] = jQuery.extend( deep, clone, copy );
231
232				// Don't bring in undefined values
233				} else if ( copy !== undefined ) {
234					target[ name ] = copy;
235				}
236			}
237		}
238	}
239
240	// Return the modified object
241	return target;
242};
243
244jQuery.extend( {
245
246	// Unique for each copy of jQuery on the page
247	expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),
248
249	// Assume jQuery is ready without the ready module
250	isReady: true,
251
252	error: function( msg ) {
253		throw new Error( msg );
254	},
255
256	noop: function() {},
257
258	isFunction: function( obj ) {
259		return jQuery.type( obj ) === "function";
260	},
261
262	isArray: Array.isArray,
263
264	isWindow: function( obj ) {
265		return obj != null && obj === obj.window;
266	},
267
268	isNumeric: function( obj ) {
269
270		// parseFloat NaNs numeric-cast false positives (null|true|false|"")
271		// ...but misinterprets leading-number strings, particularly hex literals ("0x...")
272		// subtraction forces infinities to NaN
273		// adding 1 corrects loss of precision from parseFloat (#15100)
274		var realStringObj = obj && obj.toString();
275		return !jQuery.isArray( obj ) && ( realStringObj - parseFloat( realStringObj ) + 1 ) >= 0;
276	},
277
278	isPlainObject: function( obj ) {
279		var key;
280
281		// Not plain objects:
282		// - Any object or value whose internal [[Class]] property is not "[object Object]"
283		// - DOM nodes
284		// - window
285		if ( jQuery.type( obj ) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
286			return false;
287		}
288
289		// Not own constructor property must be Object
290		if ( obj.constructor &&
291				!hasOwn.call( obj, "constructor" ) &&
292				!hasOwn.call( obj.constructor.prototype || {}, "isPrototypeOf" ) ) {
293			return false;
294		}
295
296		// Own properties are enumerated firstly, so to speed up,
297		// if last one is own, then all properties are own
298		for ( key in obj ) {}
299
300		return key === undefined || hasOwn.call( obj, key );
301	},
302
303	isEmptyObject: function( obj ) {
304		var name;
305		for ( name in obj ) {
306			return false;
307		}
308		return true;
309	},
310
311	type: function( obj ) {
312		if ( obj == null ) {
313			return obj + "";
314		}
315
316		// Support: Android<4.0, iOS<6 (functionish RegExp)
317		return typeof obj === "object" || typeof obj === "function" ?
318			class2type[ toString.call( obj ) ] || "object" :
319			typeof obj;
320	},
321
322	// Evaluates a script in a global context
323	globalEval: function( code ) {
324		var script,
325			indirect = eval;
326
327		code = jQuery.trim( code );
328
329		if ( code ) {
330
331			// If the code includes a valid, prologue position
332			// strict mode pragma, execute code by injecting a
333			// script tag into the document.
334			if ( code.indexOf( "use strict" ) === 1 ) {
335				script = document.createElement( "script" );
336				script.text = code;
337				document.head.appendChild( script ).parentNode.removeChild( script );
338			} else {
339
340				// Otherwise, avoid the DOM node creation, insertion
341				// and removal by using an indirect global eval
342
343				indirect( code );
344			}
345		}
346	},
347
348	// Convert dashed to camelCase; used by the css and data modules
349	// Support: IE9-11+
350	// Microsoft forgot to hump their vendor prefix (#9572)
351	camelCase: function( string ) {
352		return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
353	},
354
355	nodeName: function( elem, name ) {
356		return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
357	},
358
359	each: function( obj, callback ) {
360		var length, i = 0;
361
362		if ( isArrayLike( obj ) ) {
363			length = obj.length;
364			for ( ; i < length; i++ ) {
365				if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
366					break;
367				}
368			}
369		} else {
370			for ( i in obj ) {
371				if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
372					break;
373				}
374			}
375		}
376
377		return obj;
378	},
379
380	// Support: Android<4.1
381	trim: function( text ) {
382		return text == null ?
383			"" :
384			( text + "" ).replace( rtrim, "" );
385	},
386
387	// results is for internal usage only
388	makeArray: function( arr, results ) {
389		var ret = results || [];
390
391		if ( arr != null ) {
392			if ( isArrayLike( Object( arr ) ) ) {
393				jQuery.merge( ret,
394					typeof arr === "string" ?
395					[ arr ] : arr
396				);
397			} else {
398				push.call( ret, arr );
399			}
400		}
401
402		return ret;
403	},
404
405	inArray: function( elem, arr, i ) {
406		return arr == null ? -1 : indexOf.call( arr, elem, i );
407	},
408
409	merge: function( first, second ) {
410		var len = +second.length,
411			j = 0,
412			i = first.length;
413
414		for ( ; j < len; j++ ) {
415			first[ i++ ] = second[ j ];
416		}
417
418		first.length = i;
419
420		return first;
421	},
422
423	grep: function( elems, callback, invert ) {
424		var callbackInverse,
425			matches = [],
426			i = 0,
427			length = elems.length,
428			callbackExpect = !invert;
429
430		// Go through the array, only saving the items
431		// that pass the validator function
432		for ( ; i < length; i++ ) {
433			callbackInverse = !callback( elems[ i ], i );
434			if ( callbackInverse !== callbackExpect ) {
435				matches.push( elems[ i ] );
436			}
437		}
438
439		return matches;
440	},
441
442	// arg is for internal usage only
443	map: function( elems, callback, arg ) {
444		var length, value,
445			i = 0,
446			ret = [];
447
448		// Go through the array, translating each of the items to their new values
449		if ( isArrayLike( elems ) ) {
450			length = elems.length;
451			for ( ; i < length; i++ ) {
452				value = callback( elems[ i ], i, arg );
453
454				if ( value != null ) {
455					ret.push( value );
456				}
457			}
458
459		// Go through every key on the object,
460		} else {
461			for ( i in elems ) {
462				value = callback( elems[ i ], i, arg );
463
464				if ( value != null ) {
465					ret.push( value );
466				}
467			}
468		}
469
470		// Flatten any nested arrays
471		return concat.apply( [], ret );
472	},
473
474	// A global GUID counter for objects
475	guid: 1,
476
477	// Bind a function to a context, optionally partially applying any
478	// arguments.
479	proxy: function( fn, context ) {
480		var tmp, args, proxy;
481
482		if ( typeof context === "string" ) {
483			tmp = fn[ context ];
484			context = fn;
485			fn = tmp;
486		}
487
488		// Quick check to determine if target is callable, in the spec
489		// this throws a TypeError, but we will just return undefined.
490		if ( !jQuery.isFunction( fn ) ) {
491			return undefined;
492		}
493
494		// Simulated bind
495		args = slice.call( arguments, 2 );
496		proxy = function() {
497			return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
498		};
499
500		// Set the guid of unique handler to the same of original handler, so it can be removed
501		proxy.guid = fn.guid = fn.guid || jQuery.guid++;
502
503		return proxy;
504	},
505
506	now: Date.now,
507
508	// jQuery.support is not used in Core but other projects attach their
509	// properties to it so it needs to exist.
510	support: support
511} );
512
513// JSHint would error on this code due to the Symbol not being defined in ES5.
514// Defining this global in .jshintrc would create a danger of using the global
515// unguarded in another place, it seems safer to just disable JSHint for these
516// three lines.
517/* jshint ignore: start */
518if ( typeof Symbol === "function" ) {
519	jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ];
520}
521/* jshint ignore: end */
522
523// Populate the class2type map
524jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ),
525function( i, name ) {
526	class2type[ "[object " + name + "]" ] = name.toLowerCase();
527} );
528
529function isArrayLike( obj ) {
530
531	// Support: iOS 8.2 (not reproducible in simulator)
532	// `in` check used to prevent JIT error (gh-2145)
533	// hasOwn isn't used here due to false negatives
534	// regarding Nodelist length in IE
535	var length = !!obj && "length" in obj && obj.length,
536		type = jQuery.type( obj );
537
538	if ( type === "function" || jQuery.isWindow( obj ) ) {
539		return false;
540	}
541
542	return type === "array" || length === 0 ||
543		typeof length === "number" && length > 0 && ( length - 1 ) in obj;
544}
545var Sizzle =
546/*!
547 * Sizzle CSS Selector Engine v2.2.1
548 * http://sizzlejs.com/
549 *
550 * Copyright jQuery Foundation and other contributors
551 * Released under the MIT license
552 * http://jquery.org/license
553 *
554 * Date: 2015-10-17
555 */
556(function( window ) {
557
558var i,
559	support,
560	Expr,
561	getText,
562	isXML,
563	tokenize,
564	compile,
565	select,
566	outermostContext,
567	sortInput,
568	hasDuplicate,
569
570	// Local document vars
571	setDocument,
572	document,
573	docElem,
574	documentIsHTML,
575	rbuggyQSA,
576	rbuggyMatches,
577	matches,
578	contains,
579
580	// Instance-specific data
581	expando = "sizzle" + 1 * new Date(),
582	preferredDoc = window.document,
583	dirruns = 0,
584	done = 0,
585	classCache = createCache(),
586	tokenCache = createCache(),
587	compilerCache = createCache(),
588	sortOrder = function( a, b ) {
589		if ( a === b ) {
590			hasDuplicate = true;
591		}
592		return 0;
593	},
594
595	// General-purpose constants
596	MAX_NEGATIVE = 1 << 31,
597
598	// Instance methods
599	hasOwn = ({}).hasOwnProperty,
600	arr = [],
601	pop = arr.pop,
602	push_native = arr.push,
603	push = arr.push,
604	slice = arr.slice,
605	// Use a stripped-down indexOf as it's faster than native
606	// http://jsperf.com/thor-indexof-vs-for/5
607	indexOf = function( list, elem ) {
608		var i = 0,
609			len = list.length;
610		for ( ; i < len; i++ ) {
611			if ( list[i] === elem ) {
612				return i;
613			}
614		}
615		return -1;
616	},
617
618	booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
619
620	// Regular expressions
621
622	// http://www.w3.org/TR/css3-selectors/#whitespace
623	whitespace = "[\\x20\\t\\r\\n\\f]",
624
625	// http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
626	identifier = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
627
628	// Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
629	attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace +
630		// Operator (capture 2)
631		"*([*^$|!~]?=)" + whitespace +
632		// "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
633		"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace +
634		"*\\]",
635
636	pseudos = ":(" + identifier + ")(?:\\((" +
637		// To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
638		// 1. quoted (capture 3; capture 4 or capture 5)
639		"('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
640		// 2. simple (capture 6)
641		"((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +
642		// 3. anything else (capture 2)
643		".*" +
644		")\\)|)",
645
646	// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
647	rwhitespace = new RegExp( whitespace + "+", "g" ),
648	rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
649
650	rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
651	rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
652
653	rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ),
654
655	rpseudo = new RegExp( pseudos ),
656	ridentifier = new RegExp( "^" + identifier + "$" ),
657
658	matchExpr = {
659		"ID": new RegExp( "^#(" + identifier + ")" ),
660		"CLASS": new RegExp( "^\\.(" + identifier + ")" ),
661		"TAG": new RegExp( "^(" + identifier + "|[*])" ),
662		"ATTR": new RegExp( "^" + attributes ),
663		"PSEUDO": new RegExp( "^" + pseudos ),
664		"CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
665			"*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
666			"*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
667		"bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
668		// For use in libraries implementing .is()
669		// We use this for POS matching in `select`
670		"needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
671			whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
672	},
673
674	rinputs = /^(?:input|select|textarea|button)$/i,
675	rheader = /^h\d$/i,
676
677	rnative = /^[^{]+\{\s*\[native \w/,
678
679	// Easily-parseable/retrievable ID or TAG or CLASS selectors
680	rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
681
682	rsibling = /[+~]/,
683	rescape = /'|\\/g,
684
685	// CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
686	runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
687	funescape = function( _, escaped, escapedWhitespace ) {
688		var high = "0x" + escaped - 0x10000;
689		// NaN means non-codepoint
690		// Support: Firefox<24
691		// Workaround erroneous numeric interpretation of +"0x"
692		return high !== high || escapedWhitespace ?
693			escaped :
694			high < 0 ?
695				// BMP codepoint
696				String.fromCharCode( high + 0x10000 ) :
697				// Supplemental Plane codepoint (surrogate pair)
698				String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
699	},
700
701	// Used for iframes
702	// See setDocument()
703	// Removing the function wrapper causes a "Permission Denied"
704	// error in IE
705	unloadHandler = function() {
706		setDocument();
707	};
708
709// Optimize for push.apply( _, NodeList )
710try {
711	push.apply(
712		(arr = slice.call( preferredDoc.childNodes )),
713		preferredDoc.childNodes
714	);
715	// Support: Android<4.0
716	// Detect silently failing push.apply
717	arr[ preferredDoc.childNodes.length ].nodeType;
718} catch ( e ) {
719	push = { apply: arr.length ?
720
721		// Leverage slice if possible
722		function( target, els ) {
723			push_native.apply( target, slice.call(els) );
724		} :
725
726		// Support: IE<9
727		// Otherwise append directly
728		function( target, els ) {
729			var j = target.length,
730				i = 0;
731			// Can't trust NodeList.length
732			while ( (target[j++] = els[i++]) ) {}
733			target.length = j - 1;
734		}
735	};
736}
737
738function Sizzle( selector, context, results, seed ) {
739	var m, i, elem, nid, nidselect, match, groups, newSelector,
740		newContext = context && context.ownerDocument,
741
742		// nodeType defaults to 9, since context defaults to document
743		nodeType = context ? context.nodeType : 9;
744
745	results = results || [];
746
747	// Return early from calls with invalid selector or context
748	if ( typeof selector !== "string" || !selector ||
749		nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {
750
751		return results;
752	}
753
754	// Try to shortcut find operations (as opposed to filters) in HTML documents
755	if ( !seed ) {
756
757		if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
758			setDocument( context );
759		}
760		context = context || document;
761
762		if ( documentIsHTML ) {
763
764			// If the selector is sufficiently simple, try using a "get*By*" DOM method
765			// (excepting DocumentFragment context, where the methods don't exist)
766			if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) {
767
768				// ID selector
769				if ( (m = match[1]) ) {
770
771					// Document context
772					if ( nodeType === 9 ) {
773						if ( (elem = context.getElementById( m )) ) {
774
775							// Support: IE, Opera, Webkit
776							// TODO: identify versions
777							// getElementById can match elements by name instead of ID
778							if ( elem.id === m ) {
779								results.push( elem );
780								return results;
781							}
782						} else {
783							return results;
784						}
785
786					// Element context
787					} else {
788
789						// Support: IE, Opera, Webkit
790						// TODO: identify versions
791						// getElementById can match elements by name instead of ID
792						if ( newContext && (elem = newContext.getElementById( m )) &&
793							contains( context, elem ) &&
794							elem.id === m ) {
795
796							results.push( elem );
797							return results;
798						}
799					}
800
801				// Type selector
802				} else if ( match[2] ) {
803					push.apply( results, context.getElementsByTagName( selector ) );
804					return results;
805
806				// Class selector
807				} else if ( (m = match[3]) && support.getElementsByClassName &&
808					context.getElementsByClassName ) {
809
810					push.apply( results, context.getElementsByClassName( m ) );
811					return results;
812				}
813			}
814
815			// Take advantage of querySelectorAll
816			if ( support.qsa &&
817				!compilerCache[ selector + " " ] &&
818				(!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
819
820				if ( nodeType !== 1 ) {
821					newContext = context;
822					newSelector = selector;
823
824				// qSA looks outside Element context, which is not what we want
825				// Thanks to Andrew Dupont for this workaround technique
826				// Support: IE <=8
827				// Exclude object elements
828				} else if ( context.nodeName.toLowerCase() !== "object" ) {
829
830					// Capture the context ID, setting it first if necessary
831					if ( (nid = context.getAttribute( "id" )) ) {
832						nid = nid.replace( rescape, "\\$&" );
833					} else {
834						context.setAttribute( "id", (nid = expando) );
835					}
836
837					// Prefix every selector in the list
838					groups = tokenize( selector );
839					i = groups.length;
840					nidselect = ridentifier.test( nid ) ? "#" + nid : "[id='" + nid + "']";
841					while ( i-- ) {
842						groups[i] = nidselect + " " + toSelector( groups[i] );
843					}
844					newSelector = groups.join( "," );
845
846					// Expand context for sibling selectors
847					newContext = rsibling.test( selector ) && testContext( context.parentNode ) ||
848						context;
849				}
850
851				if ( newSelector ) {
852					try {
853						push.apply( results,
854							newContext.querySelectorAll( newSelector )
855						);
856						return results;
857					} catch ( qsaError ) {
858					} finally {
859						if ( nid === expando ) {
860							context.removeAttribute( "id" );
861						}
862					}
863				}
864			}
865		}
866	}
867
868	// All others
869	return select( selector.replace( rtrim, "$1" ), context, results, seed );
870}
871
872/**
873 * Create key-value caches of limited size
874 * @returns {function(string, object)} Returns the Object data after storing it on itself with
875 *	property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
876 *	deleting the oldest entry
877 */
878function createCache() {
879	var keys = [];
880
881	function cache( key, value ) {
882		// Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
883		if ( keys.push( key + " " ) > Expr.cacheLength ) {
884			// Only keep the most recent entries
885			delete cache[ keys.shift() ];
886		}
887		return (cache[ key + " " ] = value);
888	}
889	return cache;
890}
891
892/**
893 * Mark a function for special use by Sizzle
894 * @param {Function} fn The function to mark
895 */
896function markFunction( fn ) {
897	fn[ expando ] = true;
898	return fn;
899}
900
901/**
902 * Support testing using an element
903 * @param {Function} fn Passed the created div and expects a boolean result
904 */
905function assert( fn ) {
906	var div = document.createElement("div");
907
908	try {
909		return !!fn( div );
910	} catch (e) {
911		return false;
912	} finally {
913		// Remove from its parent by default
914		if ( div.parentNode ) {
915			div.parentNode.removeChild( div );
916		}
917		// release memory in IE
918		div = null;
919	}
920}
921
922/**
923 * Adds the same handler for all of the specified attrs
924 * @param {String} attrs Pipe-separated list of attributes
925 * @param {Function} handler The method that will be applied
926 */
927function addHandle( attrs, handler ) {
928	var arr = attrs.split("|"),
929		i = arr.length;
930
931	while ( i-- ) {
932		Expr.attrHandle[ arr[i] ] = handler;
933	}
934}
935
936/**
937 * Checks document order of two siblings
938 * @param {Element} a
939 * @param {Element} b
940 * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
941 */
942function siblingCheck( a, b ) {
943	var cur = b && a,
944		diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
945			( ~b.sourceIndex || MAX_NEGATIVE ) -
946			( ~a.sourceIndex || MAX_NEGATIVE );
947
948	// Use IE sourceIndex if available on both nodes
949	if ( diff ) {
950		return diff;
951	}
952
953	// Check if b follows a
954	if ( cur ) {
955		while ( (cur = cur.nextSibling) ) {
956			if ( cur === b ) {
957				return -1;
958			}
959		}
960	}
961
962	return a ? 1 : -1;
963}
964
965/**
966 * Returns a function to use in pseudos for input types
967 * @param {String} type
968 */
969function createInputPseudo( type ) {
970	return function( elem ) {
971		var name = elem.nodeName.toLowerCase();
972		return name === "input" && elem.type === type;
973	};
974}
975
976/**
977 * Returns a function to use in pseudos for buttons
978 * @param {String} type
979 */
980function createButtonPseudo( type ) {
981	return function( elem ) {
982		var name = elem.nodeName.toLowerCase();
983		return (name === "input" || name === "button") && elem.type === type;
984	};
985}
986
987/**
988 * Returns a function to use in pseudos for positionals
989 * @param {Function} fn
990 */
991function createPositionalPseudo( fn ) {
992	return markFunction(function( argument ) {
993		argument = +argument;
994		return markFunction(function( seed, matches ) {
995			var j,
996				matchIndexes = fn( [], seed.length, argument ),
997				i = matchIndexes.length;
998
999			// Match elements found at the specified indexes
1000			while ( i-- ) {
1001				if ( seed[ (j = matchIndexes[i]) ] ) {
1002					seed[j] = !(matches[j] = seed[j]);
1003				}
1004			}
1005		});
1006	});
1007}
1008
1009/**
1010 * Checks a node for validity as a Sizzle context
1011 * @param {Element|Object=} context
1012 * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
1013 */
1014function testContext( context ) {
1015	return context && typeof context.getElementsByTagName !== "undefined" && context;
1016}
1017
1018// Expose support vars for convenience
1019support = Sizzle.support = {};
1020
1021/**
1022 * Detects XML nodes
1023 * @param {Element|Object} elem An element or a document
1024 * @returns {Boolean} True iff elem is a non-HTML XML node
1025 */
1026isXML = Sizzle.isXML = function( elem ) {
1027	// documentElement is verified for cases where it doesn't yet exist
1028	// (such as loading iframes in IE - #4833)
1029	var documentElement = elem && (elem.ownerDocument || elem).documentElement;
1030	return documentElement ? documentElement.nodeName !== "HTML" : false;
1031};
1032
1033/**
1034 * Sets document-related variables once based on the current document
1035 * @param {Element|Object} [doc] An element or document object to use to set the document
1036 * @returns {Object} Returns the current document
1037 */
1038setDocument = Sizzle.setDocument = function( node ) {
1039	var hasCompare, parent,
1040		doc = node ? node.ownerDocument || node : preferredDoc;
1041
1042	// Return early if doc is invalid or already selected
1043	if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
1044		return document;
1045	}
1046
1047	// Update global variables
1048	document = doc;
1049	docElem = document.documentElement;
1050	documentIsHTML = !isXML( document );
1051
1052	// Support: IE 9-11, Edge
1053	// Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936)
1054	if ( (parent = document.defaultView) && parent.top !== parent ) {
1055		// Support: IE 11
1056		if ( parent.addEventListener ) {
1057			parent.addEventListener( "unload", unloadHandler, false );
1058
1059		// Support: IE 9 - 10 only
1060		} else if ( parent.attachEvent ) {
1061			parent.attachEvent( "onunload", unloadHandler );
1062		}
1063	}
1064
1065	/* Attributes
1066	---------------------------------------------------------------------- */
1067
1068	// Support: IE<8
1069	// Verify that getAttribute really returns attributes and not properties
1070	// (excepting IE8 booleans)
1071	support.attributes = assert(function( div ) {
1072		div.className = "i";
1073		return !div.getAttribute("className");
1074	});
1075
1076	/* getElement(s)By*
1077	---------------------------------------------------------------------- */
1078
1079	// Check if getElementsByTagName("*") returns only elements
1080	support.getElementsByTagName = assert(function( div ) {
1081		div.appendChild( document.createComment("") );
1082		return !div.getElementsByTagName("*").length;
1083	});
1084
1085	// Support: IE<9
1086	support.getElementsByClassName = rnative.test( document.getElementsByClassName );
1087
1088	// Support: IE<10
1089	// Check if getElementById returns elements by name
1090	// The broken getElementById methods don't pick up programatically-set names,
1091	// so use a roundabout getElementsByName test
1092	support.getById = assert(function( div ) {
1093		docElem.appendChild( div ).id = expando;
1094		return !document.getElementsByName || !document.getElementsByName( expando ).length;
1095	});
1096
1097	// ID find and filter
1098	if ( support.getById ) {
1099		Expr.find["ID"] = function( id, context ) {
1100			if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
1101				var m = context.getElementById( id );
1102				return m ? [ m ] : [];
1103			}
1104		};
1105		Expr.filter["ID"] = function( id ) {
1106			var attrId = id.replace( runescape, funescape );
1107			return function( elem ) {
1108				return elem.getAttribute("id") === attrId;
1109			};
1110		};
1111	} else {
1112		// Support: IE6/7
1113		// getElementById is not reliable as a find shortcut
1114		delete Expr.find["ID"];
1115
1116		Expr.filter["ID"] =  function( id ) {
1117			var attrId = id.replace( runescape, funescape );
1118			return function( elem ) {
1119				var node = typeof elem.getAttributeNode !== "undefined" &&
1120					elem.getAttributeNode("id");
1121				return node && node.value === attrId;
1122			};
1123		};
1124	}
1125
1126	// Tag
1127	Expr.find["TAG"] = support.getElementsByTagName ?
1128		function( tag, context ) {
1129			if ( typeof context.getElementsByTagName !== "undefined" ) {
1130				return context.getElementsByTagName( tag );
1131
1132			// DocumentFragment nodes don't have gEBTN
1133			} else if ( support.qsa ) {
1134				return context.querySelectorAll( tag );
1135			}
1136		} :
1137
1138		function( tag, context ) {
1139			var elem,
1140				tmp = [],
1141				i = 0,
1142				// By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too
1143				results = context.getElementsByTagName( tag );
1144
1145			// Filter out possible comments
1146			if ( tag === "*" ) {
1147				while ( (elem = results[i++]) ) {
1148					if ( elem.nodeType === 1 ) {
1149						tmp.push( elem );
1150					}
1151				}
1152
1153				return tmp;
1154			}
1155			return results;
1156		};
1157
1158	// Class
1159	Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
1160		if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) {
1161			return context.getElementsByClassName( className );
1162		}
1163	};
1164
1165	/* QSA/matchesSelector
1166	---------------------------------------------------------------------- */
1167
1168	// QSA and matchesSelector support
1169
1170	// matchesSelector(:active) reports false when true (IE9/Opera 11.5)
1171	rbuggyMatches = [];
1172
1173	// qSa(:focus) reports false when true (Chrome 21)
1174	// We allow this because of a bug in IE8/9 that throws an error
1175	// whenever `document.activeElement` is accessed on an iframe
1176	// So, we allow :focus to pass through QSA all the time to avoid the IE error
1177	// See http://bugs.jquery.com/ticket/13378
1178	rbuggyQSA = [];
1179
1180	if ( (support.qsa = rnative.test( document.querySelectorAll )) ) {
1181		// Build QSA regex
1182		// Regex strategy adopted from Diego Perini
1183		assert(function( div ) {
1184			// Select is set to empty string on purpose
1185			// This is to test IE's treatment of not explicitly
1186			// setting a boolean content attribute,
1187			// since its presence should be enough
1188			// http://bugs.jquery.com/ticket/12359
1189			docElem.appendChild( div ).innerHTML = "<a id='" + expando + "'></a>" +
1190				"<select id='" + expando + "-\r\\' msallowcapture=''>" +
1191				"<option selected=''></option></select>";
1192
1193			// Support: IE8, Opera 11-12.16
1194			// Nothing should be selected when empty strings follow ^= or $= or *=
1195			// The test attribute must be unknown in Opera but "safe" for WinRT
1196			// http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
1197			if ( div.querySelectorAll("[msallowcapture^='']").length ) {
1198				rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
1199			}
1200
1201			// Support: IE8
1202			// Boolean attributes and "value" are not treated correctly
1203			if ( !div.querySelectorAll("[selected]").length ) {
1204				rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
1205			}
1206
1207			// Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+
1208			if ( !div.querySelectorAll( "[id~=" + expando + "-]" ).length ) {
1209				rbuggyQSA.push("~=");
1210			}
1211
1212			// Webkit/Opera - :checked should return selected option elements
1213			// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
1214			// IE8 throws error here and will not see later tests
1215			if ( !div.querySelectorAll(":checked").length ) {
1216				rbuggyQSA.push(":checked");
1217			}
1218
1219			// Support: Safari 8+, iOS 8+
1220			// https://bugs.webkit.org/show_bug.cgi?id=136851
1221			// In-page `selector#id sibing-combinator selector` fails
1222			if ( !div.querySelectorAll( "a#" + expando + "+*" ).length ) {
1223				rbuggyQSA.push(".#.+[+~]");
1224			}
1225		});
1226
1227		assert(function( div ) {
1228			// Support: Windows 8 Native Apps
1229			// The type and name attributes are restricted during .innerHTML assignment
1230			var input = document.createElement("input");
1231			input.setAttribute( "type", "hidden" );
1232			div.appendChild( input ).setAttribute( "name", "D" );
1233
1234			// Support: IE8
1235			// Enforce case-sensitivity of name attribute
1236			if ( div.querySelectorAll("[name=d]").length ) {
1237				rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
1238			}
1239
1240			// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
1241			// IE8 throws error here and will not see later tests
1242			if ( !div.querySelectorAll(":enabled").length ) {
1243				rbuggyQSA.push( ":enabled", ":disabled" );
1244			}
1245
1246			// Opera 10-11 does not throw on post-comma invalid pseudos
1247			div.querySelectorAll("*,:x");
1248			rbuggyQSA.push(",.*:");
1249		});
1250	}
1251
1252	if ( (support.matchesSelector = rnative.test( (matches = docElem.matches ||
1253		docElem.webkitMatchesSelector ||
1254		docElem.mozMatchesSelector ||
1255		docElem.oMatchesSelector ||
1256		docElem.msMatchesSelector) )) ) {
1257
1258		assert(function( div ) {
1259			// Check to see if it's possible to do matchesSelector
1260			// on a disconnected node (IE 9)
1261			support.disconnectedMatch = matches.call( div, "div" );
1262
1263			// This should fail with an exception
1264			// Gecko does not error, returns false instead
1265			matches.call( div, "[s!='']:x" );
1266			rbuggyMatches.push( "!=", pseudos );
1267		});
1268	}
1269
1270	rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
1271	rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
1272
1273	/* Contains
1274	---------------------------------------------------------------------- */
1275	hasCompare = rnative.test( docElem.compareDocumentPosition );
1276
1277	// Element contains another
1278	// Purposefully self-exclusive
1279	// As in, an element does not contain itself
1280	contains = hasCompare || rnative.test( docElem.contains ) ?
1281		function( a, b ) {
1282			var adown = a.nodeType === 9 ? a.documentElement : a,
1283				bup = b && b.parentNode;
1284			return a === bup || !!( bup && bup.nodeType === 1 && (
1285				adown.contains ?
1286					adown.contains( bup ) :
1287					a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
1288			));
1289		} :
1290		function( a, b ) {
1291			if ( b ) {
1292				while ( (b = b.parentNode) ) {
1293					if ( b === a ) {
1294						return true;
1295					}
1296				}
1297			}
1298			return false;
1299		};
1300
1301	/* Sorting
1302	---------------------------------------------------------------------- */
1303
1304	// Document order sorting
1305	sortOrder = hasCompare ?
1306	function( a, b ) {
1307
1308		// Flag for duplicate removal
1309		if ( a === b ) {
1310			hasDuplicate = true;
1311			return 0;
1312		}
1313
1314		// Sort on method existence if only one input has compareDocumentPosition
1315		var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
1316		if ( compare ) {
1317			return compare;
1318		}
1319
1320		// Calculate position if both inputs belong to the same document
1321		compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?
1322			a.compareDocumentPosition( b ) :
1323
1324			// Otherwise we know they are disconnected
1325			1;
1326
1327		// Disconnected nodes
1328		if ( compare & 1 ||
1329			(!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
1330
1331			// Choose the first element that is related to our preferred document
1332			if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
1333				return -1;
1334			}
1335			if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
1336				return 1;
1337			}
1338
1339			// Maintain original order
1340			return sortInput ?
1341				( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
1342				0;
1343		}
1344
1345		return compare & 4 ? -1 : 1;
1346	} :
1347	function( a, b ) {
1348		// Exit early if the nodes are identical
1349		if ( a === b ) {
1350			hasDuplicate = true;
1351			return 0;
1352		}
1353
1354		var cur,
1355			i = 0,
1356			aup = a.parentNode,
1357			bup = b.parentNode,
1358			ap = [ a ],
1359			bp = [ b ];
1360
1361		// Parentless nodes are either documents or disconnected
1362		if ( !aup || !bup ) {
1363			return a === document ? -1 :
1364				b === document ? 1 :
1365				aup ? -1 :
1366				bup ? 1 :
1367				sortInput ?
1368				( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
1369				0;
1370
1371		// If the nodes are siblings, we can do a quick check
1372		} else if ( aup === bup ) {
1373			return siblingCheck( a, b );
1374		}
1375
1376		// Otherwise we need full lists of their ancestors for comparison
1377		cur = a;
1378		while ( (cur = cur.parentNode) ) {
1379			ap.unshift( cur );
1380		}
1381		cur = b;
1382		while ( (cur = cur.parentNode) ) {
1383			bp.unshift( cur );
1384		}
1385
1386		// Walk down the tree looking for a discrepancy
1387		while ( ap[i] === bp[i] ) {
1388			i++;
1389		}
1390
1391		return i ?
1392			// Do a sibling check if the nodes have a common ancestor
1393			siblingCheck( ap[i], bp[i] ) :
1394
1395			// Otherwise nodes in our document sort first
1396			ap[i] === preferredDoc ? -1 :
1397			bp[i] === preferredDoc ? 1 :
1398			0;
1399	};
1400
1401	return document;
1402};
1403
1404Sizzle.matches = function( expr, elements ) {
1405	return Sizzle( expr, null, null, elements );
1406};
1407
1408Sizzle.matchesSelector = function( elem, expr ) {
1409	// Set document vars if needed
1410	if ( ( elem.ownerDocument || elem ) !== document ) {
1411		setDocument( elem );
1412	}
1413
1414	// Make sure that attribute selectors are quoted
1415	expr = expr.replace( rattributeQuotes, "='$1']" );
1416
1417	if ( support.matchesSelector && documentIsHTML &&
1418		!compilerCache[ expr + " " ] &&
1419		( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
1420		( !rbuggyQSA     || !rbuggyQSA.test( expr ) ) ) {
1421
1422		try {
1423			var ret = matches.call( elem, expr );
1424
1425			// IE 9's matchesSelector returns false on disconnected nodes
1426			if ( ret || support.disconnectedMatch ||
1427					// As well, disconnected nodes are said to be in a document
1428					// fragment in IE 9
1429					elem.document && elem.document.nodeType !== 11 ) {
1430				return ret;
1431			}
1432		} catch (e) {}
1433	}
1434
1435	return Sizzle( expr, document, null, [ elem ] ).length > 0;
1436};
1437
1438Sizzle.contains = function( context, elem ) {
1439	// Set document vars if needed
1440	if ( ( context.ownerDocument || context ) !== document ) {
1441		setDocument( context );
1442	}
1443	return contains( context, elem );
1444};
1445
1446Sizzle.attr = function( elem, name ) {
1447	// Set document vars if needed
1448	if ( ( elem.ownerDocument || elem ) !== document ) {
1449		setDocument( elem );
1450	}
1451
1452	var fn = Expr.attrHandle[ name.toLowerCase() ],
1453		// Don't get fooled by Object.prototype properties (jQuery #13807)
1454		val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
1455			fn( elem, name, !documentIsHTML ) :
1456			undefined;
1457
1458	return val !== undefined ?
1459		val :
1460		support.attributes || !documentIsHTML ?
1461			elem.getAttribute( name ) :
1462			(val = elem.getAttributeNode(name)) && val.specified ?
1463				val.value :
1464				null;
1465};
1466
1467Sizzle.error = function( msg ) {
1468	throw new Error( "Syntax error, unrecognized expression: " + msg );
1469};
1470
1471/**
1472 * Document sorting and removing duplicates
1473 * @param {ArrayLike} results
1474 */
1475Sizzle.uniqueSort = function( results ) {
1476	var elem,
1477		duplicates = [],
1478		j = 0,
1479		i = 0;
1480
1481	// Unless we *know* we can detect duplicates, assume their presence
1482	hasDuplicate = !support.detectDuplicates;
1483	sortInput = !support.sortStable && results.slice( 0 );
1484	results.sort( sortOrder );
1485
1486	if ( hasDuplicate ) {
1487		while ( (elem = results[i++]) ) {
1488			if ( elem === results[ i ] ) {
1489				j = duplicates.push( i );
1490			}
1491		}
1492		while ( j-- ) {
1493			results.splice( duplicates[ j ], 1 );
1494		}
1495	}
1496
1497	// Clear input after sorting to release objects
1498	// See https://github.com/jquery/sizzle/pull/225
1499	sortInput = null;
1500
1501	return results;
1502};
1503
1504/**
1505 * Utility function for retrieving the text value of an array of DOM nodes
1506 * @param {Array|Element} elem
1507 */
1508getText = Sizzle.getText = function( elem ) {
1509	var node,
1510		ret = "",
1511		i = 0,
1512		nodeType = elem.nodeType;
1513
1514	if ( !nodeType ) {
1515		// If no nodeType, this is expected to be an array
1516		while ( (node = elem[i++]) ) {
1517			// Do not traverse comment nodes
1518			ret += getText( node );
1519		}
1520	} else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
1521		// Use textContent for elements
1522		// innerText usage removed for consistency of new lines (jQuery #11153)
1523		if ( typeof elem.textContent === "string" ) {
1524			return elem.textContent;
1525		} else {
1526			// Traverse its children
1527			for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
1528				ret += getText( elem );
1529			}
1530		}
1531	} else if ( nodeType === 3 || nodeType === 4 ) {
1532		return elem.nodeValue;
1533	}
1534	// Do not include comment or processing instruction nodes
1535
1536	return ret;
1537};
1538
1539Expr = Sizzle.selectors = {
1540
1541	// Can be adjusted by the user
1542	cacheLength: 50,
1543
1544	createPseudo: markFunction,
1545
1546	match: matchExpr,
1547
1548	attrHandle: {},
1549
1550	find: {},
1551
1552	relative: {
1553		">": { dir: "parentNode", first: true },
1554		" ": { dir: "parentNode" },
1555		"+": { dir: "previousSibling", first: true },
1556		"~": { dir: "previousSibling" }
1557	},
1558
1559	preFilter: {
1560		"ATTR": function( match ) {
1561			match[1] = match[1].replace( runescape, funescape );
1562
1563			// Move the given value to match[3] whether quoted or unquoted
1564			match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape );
1565
1566			if ( match[2] === "~=" ) {
1567				match[3] = " " + match[3] + " ";
1568			}
1569
1570			return match.slice( 0, 4 );
1571		},
1572
1573		"CHILD": function( match ) {
1574			/* matches from matchExpr["CHILD"]
1575				1 type (only|nth|...)
1576				2 what (child|of-type)
1577				3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
1578				4 xn-component of xn+y argument ([+-]?\d*n|)
1579				5 sign of xn-component
1580				6 x of xn-component
1581				7 sign of y-component
1582				8 y of y-component
1583			*/
1584			match[1] = match[1].toLowerCase();
1585
1586			if ( match[1].slice( 0, 3 ) === "nth" ) {
1587				// nth-* requires argument
1588				if ( !match[3] ) {
1589					Sizzle.error( match[0] );
1590				}
1591
1592				// numeric x and y parameters for Expr.filter.CHILD
1593				// remember that false/true cast respectively to 0/1
1594				match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
1595				match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
1596
1597			// other types prohibit arguments
1598			} else if ( match[3] ) {
1599				Sizzle.error( match[0] );
1600			}
1601
1602			return match;
1603		},
1604
1605		"PSEUDO": function( match ) {
1606			var excess,
1607				unquoted = !match[6] && match[2];
1608
1609			if ( matchExpr["CHILD"].test( match[0] ) ) {
1610				return null;
1611			}
1612
1613			// Accept quoted arguments as-is
1614			if ( match[3] ) {
1615				match[2] = match[4] || match[5] || "";
1616
1617			// Strip excess characters from unquoted arguments
1618			} else if ( unquoted && rpseudo.test( unquoted ) &&
1619				// Get excess from tokenize (recursively)
1620				(excess = tokenize( unquoted, true )) &&
1621				// advance to the next closing parenthesis
1622				(excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
1623
1624				// excess is a negative index
1625				match[0] = match[0].slice( 0, excess );
1626				match[2] = unquoted.slice( 0, excess );
1627			}
1628
1629			// Return only captures needed by the pseudo filter method (type and argument)
1630			return match.slice( 0, 3 );
1631		}
1632	},
1633
1634	filter: {
1635
1636		"TAG": function( nodeNameSelector ) {
1637			var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
1638			return nodeNameSelector === "*" ?
1639				function() { return true; } :
1640				function( elem ) {
1641					return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
1642				};
1643		},
1644
1645		"CLASS": function( className ) {
1646			var pattern = classCache[ className + " " ];
1647
1648			return pattern ||
1649				(pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
1650				classCache( className, function( elem ) {
1651					return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" );
1652				});
1653		},
1654
1655		"ATTR": function( name, operator, check ) {
1656			return function( elem ) {
1657				var result = Sizzle.attr( elem, name );
1658
1659				if ( result == null ) {
1660					return operator === "!=";
1661				}
1662				if ( !operator ) {
1663					return true;
1664				}
1665
1666				result += "";
1667
1668				return operator === "=" ? result === check :
1669					operator === "!=" ? result !== check :
1670					operator === "^=" ? check && result.indexOf( check ) === 0 :
1671					operator === "*=" ? check && result.indexOf( check ) > -1 :
1672					operator === "$=" ? check && result.slice( -check.length ) === check :
1673					operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 :
1674					operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
1675					false;
1676			};
1677		},
1678
1679		"CHILD": function( type, what, argument, first, last ) {
1680			var simple = type.slice( 0, 3 ) !== "nth",
1681				forward = type.slice( -4 ) !== "last",
1682				ofType = what === "of-type";
1683
1684			return first === 1 && last === 0 ?
1685
1686				// Shortcut for :nth-*(n)
1687				function( elem ) {
1688					return !!elem.parentNode;
1689				} :
1690
1691				function( elem, context, xml ) {
1692					var cache, uniqueCache, outerCache, node, nodeIndex, start,
1693						dir = simple !== forward ? "nextSibling" : "previousSibling",
1694						parent = elem.parentNode,
1695						name = ofType && elem.nodeName.toLowerCase(),
1696						useCache = !xml && !ofType,
1697						diff = false;
1698
1699					if ( parent ) {
1700
1701						// :(first|last|only)-(child|of-type)
1702						if ( simple ) {
1703							while ( dir ) {
1704								node = elem;
1705								while ( (node = node[ dir ]) ) {
1706									if ( ofType ?
1707										node.nodeName.toLowerCase() === name :
1708										node.nodeType === 1 ) {
1709
1710										return false;
1711									}
1712								}
1713								// Reverse direction for :only-* (if we haven't yet done so)
1714								start = dir = type === "only" && !start && "nextSibling";
1715							}
1716							return true;
1717						}
1718
1719						start = [ forward ? parent.firstChild : parent.lastChild ];
1720
1721						// non-xml :nth-child(...) stores cache data on `parent`
1722						if ( forward && useCache ) {
1723
1724							// Seek `elem` from a previously-cached index
1725
1726							// ...in a gzip-friendly way
1727							node = parent;
1728							outerCache = node[ expando ] || (node[ expando ] = {});
1729
1730							// Support: IE <9 only
1731							// Defend against cloned attroperties (jQuery gh-1709)
1732							uniqueCache = outerCache[ node.uniqueID ] ||
1733								(outerCache[ node.uniqueID ] = {});
1734
1735							cache = uniqueCache[ type ] || [];
1736							nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
1737							diff = nodeIndex && cache[ 2 ];
1738							node = nodeIndex && parent.childNodes[ nodeIndex ];
1739
1740							while ( (node = ++nodeIndex && node && node[ dir ] ||
1741
1742								// Fallback to seeking `elem` from the start
1743								(diff = nodeIndex = 0) || start.pop()) ) {
1744
1745								// When found, cache indexes on `parent` and break
1746								if ( node.nodeType === 1 && ++diff && node === elem ) {
1747									uniqueCache[ type ] = [ dirruns, nodeIndex, diff ];
1748									break;
1749								}
1750							}
1751
1752						} else {
1753							// Use previously-cached element index if available
1754							if ( useCache ) {
1755								// ...in a gzip-friendly way
1756								node = elem;
1757								outerCache = node[ expando ] || (node[ expando ] = {});
1758
1759								// Support: IE <9 only
1760								// Defend against cloned attroperties (jQuery gh-1709)
1761								uniqueCache = outerCache[ node.uniqueID ] ||
1762									(outerCache[ node.uniqueID ] = {});
1763
1764								cache = uniqueCache[ type ] || [];
1765								nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
1766								diff = nodeIndex;
1767							}
1768
1769							// xml :nth-child(...)
1770							// or :nth-last-child(...) or :nth(-last)?-of-type(...)
1771							if ( diff === false ) {
1772								// Use the same loop as above to seek `elem` from the start
1773								while ( (node = ++nodeIndex && node && node[ dir ] ||
1774									(diff = nodeIndex = 0) || start.pop()) ) {
1775
1776									if ( ( ofType ?
1777										node.nodeName.toLowerCase() === name :
1778										node.nodeType === 1 ) &&
1779										++diff ) {
1780
1781										// Cache the index of each encountered element
1782										if ( useCache ) {
1783											outerCache = node[ expando ] || (node[ expando ] = {});
1784
1785											// Support: IE <9 only
1786											// Defend against cloned attroperties (jQuery gh-1709)
1787											uniqueCache = outerCache[ node.uniqueID ] ||
1788												(outerCache[ node.uniqueID ] = {});
1789
1790											uniqueCache[ type ] = [ dirruns, diff ];
1791										}
1792
1793										if ( node === elem ) {
1794											break;
1795										}
1796									}
1797								}
1798							}
1799						}
1800
1801						// Incorporate the offset, then check against cycle size
1802						diff -= last;
1803						return diff === first || ( diff % first === 0 && diff / first >= 0 );
1804					}
1805				};
1806		},
1807
1808		"PSEUDO": function( pseudo, argument ) {
1809			// pseudo-class names are case-insensitive
1810			// http://www.w3.org/TR/selectors/#pseudo-classes
1811			// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
1812			// Remember that setFilters inherits from pseudos
1813			var args,
1814				fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
1815					Sizzle.error( "unsupported pseudo: " + pseudo );
1816
1817			// The user may use createPseudo to indicate that
1818			// arguments are needed to create the filter function
1819			// just as Sizzle does
1820			if ( fn[ expando ] ) {
1821				return fn( argument );
1822			}
1823
1824			// But maintain support for old signatures
1825			if ( fn.length > 1 ) {
1826				args = [ pseudo, pseudo, "", argument ];
1827				return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
1828					markFunction(function( seed, matches ) {
1829						var idx,
1830							matched = fn( seed, argument ),
1831							i = matched.length;
1832						while ( i-- ) {
1833							idx = indexOf( seed, matched[i] );
1834							seed[ idx ] = !( matches[ idx ] = matched[i] );
1835						}
1836					}) :
1837					function( elem ) {
1838						return fn( elem, 0, args );
1839					};
1840			}
1841
1842			return fn;
1843		}
1844	},
1845
1846	pseudos: {
1847		// Potentially complex pseudos
1848		"not": markFunction(function( selector ) {
1849			// Trim the selector passed to compile
1850			// to avoid treating leading and trailing
1851			// spaces as combinators
1852			var input = [],
1853				results = [],
1854				matcher = compile( selector.replace( rtrim, "$1" ) );
1855
1856			return matcher[ expando ] ?
1857				markFunction(function( seed, matches, context, xml ) {
1858					var elem,
1859						unmatched = matcher( seed, null, xml, [] ),
1860						i = seed.length;
1861
1862					// Match elements unmatched by `matcher`
1863					while ( i-- ) {
1864						if ( (elem = unmatched[i]) ) {
1865							seed[i] = !(matches[i] = elem);
1866						}
1867					}
1868				}) :
1869				function( elem, context, xml ) {
1870					input[0] = elem;
1871					matcher( input, null, xml, results );
1872					// Don't keep the element (issue #299)
1873					input[0] = null;
1874					return !results.pop();
1875				};
1876		}),
1877
1878		"has": markFunction(function( selector ) {
1879			return function( elem ) {
1880				return Sizzle( selector, elem ).length > 0;
1881			};
1882		}),
1883
1884		"contains": markFunction(function( text ) {
1885			text = text.replace( runescape, funescape );
1886			return function( elem ) {
1887				return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
1888			};
1889		}),
1890
1891		// "Whether an element is represented by a :lang() selector
1892		// is based solely on the element's language value
1893		// being equal to the identifier C,
1894		// or beginning with the identifier C immediately followed by "-".
1895		// The matching of C against the element's language value is performed case-insensitively.
1896		// The identifier C does not have to be a valid language name."
1897		// http://www.w3.org/TR/selectors/#lang-pseudo
1898		"lang": markFunction( function( lang ) {
1899			// lang value must be a valid identifier
1900			if ( !ridentifier.test(lang || "") ) {
1901				Sizzle.error( "unsupported lang: " + lang );
1902			}
1903			lang = lang.replace( runescape, funescape ).toLowerCase();
1904			return function( elem ) {
1905				var elemLang;
1906				do {
1907					if ( (elemLang = documentIsHTML ?
1908						elem.lang :
1909						elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
1910
1911						elemLang = elemLang.toLowerCase();
1912						return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
1913					}
1914				} while ( (elem = elem.parentNode) && elem.nodeType === 1 );
1915				return false;
1916			};
1917		}),
1918
1919		// Miscellaneous
1920		"target": function( elem ) {
1921			var hash = window.location && window.location.hash;
1922			return hash && hash.slice( 1 ) === elem.id;
1923		},
1924
1925		"root": function( elem ) {
1926			return elem === docElem;
1927		},
1928
1929		"focus": function( elem ) {
1930			return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
1931		},
1932
1933		// Boolean properties
1934		"enabled": function( elem ) {
1935			return elem.disabled === false;
1936		},
1937
1938		"disabled": function( elem ) {
1939			return elem.disabled === true;
1940		},
1941
1942		"checked": function( elem ) {
1943			// In CSS3, :checked should return both checked and selected elements
1944			// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
1945			var nodeName = elem.nodeName.toLowerCase();
1946			return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
1947		},
1948
1949		"selected": function( elem ) {
1950			// Accessing this property makes selected-by-default
1951			// options in Safari work properly
1952			if ( elem.parentNode ) {
1953				elem.parentNode.selectedIndex;
1954			}
1955
1956			return elem.selected === true;
1957		},
1958
1959		// Contents
1960		"empty": function( elem ) {
1961			// http://www.w3.org/TR/selectors/#empty-pseudo
1962			// :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
1963			//   but not by others (comment: 8; processing instruction: 7; etc.)
1964			// nodeType < 6 works because attributes (2) do not appear as children
1965			for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
1966				if ( elem.nodeType < 6 ) {
1967					return false;
1968				}
1969			}
1970			return true;
1971		},
1972
1973		"parent": function( elem ) {
1974			return !Expr.pseudos["empty"]( elem );
1975		},
1976
1977		// Element/input types
1978		"header": function( elem ) {
1979			return rheader.test( elem.nodeName );
1980		},
1981
1982		"input": function( elem ) {
1983			return rinputs.test( elem.nodeName );
1984		},
1985
1986		"button": function( elem ) {
1987			var name = elem.nodeName.toLowerCase();
1988			return name === "input" && elem.type === "button" || name === "button";
1989		},
1990
1991		"text": function( elem ) {
1992			var attr;
1993			return elem.nodeName.toLowerCase() === "input" &&
1994				elem.type === "text" &&
1995
1996				// Support: IE<8
1997				// New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
1998				( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" );
1999		},
2000
2001		// Position-in-collection
2002		"first": createPositionalPseudo(function() {
2003			return [ 0 ];
2004		}),
2005
2006		"last": createPositionalPseudo(function( matchIndexes, length ) {
2007			return [ length - 1 ];
2008		}),
2009
2010		"eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
2011			return [ argument < 0 ? argument + length : argument ];
2012		}),
2013
2014		"even": createPositionalPseudo(function( matchIndexes, length ) {
2015			var i = 0;
2016			for ( ; i < length; i += 2 ) {
2017				matchIndexes.push( i );
2018			}
2019			return matchIndexes;
2020		}),
2021
2022		"odd": createPositionalPseudo(function( matchIndexes, length ) {
2023			var i = 1;
2024			for ( ; i < length; i += 2 ) {
2025				matchIndexes.push( i );
2026			}
2027			return matchIndexes;
2028		}),
2029
2030		"lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
2031			var i = argument < 0 ? argument + length : argument;
2032			for ( ; --i >= 0; ) {
2033				matchIndexes.push( i );
2034			}
2035			return matchIndexes;
2036		}),
2037
2038		"gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
2039			var i = argument < 0 ? argument + length : argument;
2040			for ( ; ++i < length; ) {
2041				matchIndexes.push( i );
2042			}
2043			return matchIndexes;
2044		})
2045	}
2046};
2047
2048Expr.pseudos["nth"] = Expr.pseudos["eq"];
2049
2050// Add button/input type pseudos
2051for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
2052	Expr.pseudos[ i ] = createInputPseudo( i );
2053}
2054for ( i in { submit: true, reset: true } ) {
2055	Expr.pseudos[ i ] = createButtonPseudo( i );
2056}
2057
2058// Easy API for creating new setFilters
2059function setFilters() {}
2060setFilters.prototype = Expr.filters = Expr.pseudos;
2061Expr.setFilters = new setFilters();
2062
2063tokenize = Sizzle.tokenize = function( selector, parseOnly ) {
2064	var matched, match, tokens, type,
2065		soFar, groups, preFilters,
2066		cached = tokenCache[ selector + " " ];
2067
2068	if ( cached ) {
2069		return parseOnly ? 0 : cached.slice( 0 );
2070	}
2071
2072	soFar = selector;
2073	groups = [];
2074	preFilters = Expr.preFilter;
2075
2076	while ( soFar ) {
2077
2078		// Comma and first run
2079		if ( !matched || (match = rcomma.exec( soFar )) ) {
2080			if ( match ) {
2081				// Don't consume trailing commas as valid
2082				soFar = soFar.slice( match[0].length ) || soFar;
2083			}
2084			groups.push( (tokens = []) );
2085		}
2086
2087		matched = false;
2088
2089		// Combinators
2090		if ( (match = rcombinators.exec( soFar )) ) {
2091			matched = match.shift();
2092			tokens.push({
2093				value: matched,
2094				// Cast descendant combinators to space
2095				type: match[0].replace( rtrim, " " )
2096			});
2097			soFar = soFar.slice( matched.length );
2098		}
2099
2100		// Filters
2101		for ( type in Expr.filter ) {
2102			if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
2103				(match = preFilters[ type ]( match ))) ) {
2104				matched = match.shift();
2105				tokens.push({
2106					value: matched,
2107					type: type,
2108					matches: match
2109				});
2110				soFar = soFar.slice( matched.length );
2111			}
2112		}
2113
2114		if ( !matched ) {
2115			break;
2116		}
2117	}
2118
2119	// Return the length of the invalid excess
2120	// if we're just parsing
2121	// Otherwise, throw an error or return tokens
2122	return parseOnly ?
2123		soFar.length :
2124		soFar ?
2125			Sizzle.error( selector ) :
2126			// Cache the tokens
2127			tokenCache( selector, groups ).slice( 0 );
2128};
2129
2130function toSelector( tokens ) {
2131	var i = 0,
2132		len = tokens.length,
2133		selector = "";
2134	for ( ; i < len; i++ ) {
2135		selector += tokens[i].value;
2136	}
2137	return selector;
2138}
2139
2140function addCombinator( matcher, combinator, base ) {
2141	var dir = combinator.dir,
2142		checkNonElements = base && dir === "parentNode",
2143		doneName = done++;
2144
2145	return combinator.first ?
2146		// Check against closest ancestor/preceding element
2147		function( elem, context, xml ) {
2148			while ( (elem = elem[ dir ]) ) {
2149				if ( elem.nodeType === 1 || checkNonElements ) {
2150					return matcher( elem, context, xml );
2151				}
2152			}
2153		} :
2154
2155		// Check against all ancestor/preceding elements
2156		function( elem, context, xml ) {
2157			var oldCache, uniqueCache, outerCache,
2158				newCache = [ dirruns, doneName ];
2159
2160			// We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching
2161			if ( xml ) {
2162				while ( (elem = elem[ dir ]) ) {
2163					if ( elem.nodeType === 1 || checkNonElements ) {
2164						if ( matcher( elem, context, xml ) ) {
2165							return true;
2166						}
2167					}
2168				}
2169			} else {
2170				while ( (elem = elem[ dir ]) ) {
2171					if ( elem.nodeType === 1 || checkNonElements ) {
2172						outerCache = elem[ expando ] || (elem[ expando ] = {});
2173
2174						// Support: IE <9 only
2175						// Defend against cloned attroperties (jQuery gh-1709)
2176						uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {});
2177
2178						if ( (oldCache = uniqueCache[ dir ]) &&
2179							oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
2180
2181							// Assign to newCache so results back-propagate to previous elements
2182							return (newCache[ 2 ] = oldCache[ 2 ]);
2183						} else {
2184							// Reuse newcache so results back-propagate to previous elements
2185							uniqueCache[ dir ] = newCache;
2186
2187							// A match means we're done; a fail means we have to keep checking
2188							if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {
2189								return true;
2190							}
2191						}
2192					}
2193				}
2194			}
2195		};
2196}
2197
2198function elementMatcher( matchers ) {
2199	return matchers.length > 1 ?
2200		function( elem, context, xml ) {
2201			var i = matchers.length;
2202			while ( i-- ) {
2203				if ( !matchers[i]( elem, context, xml ) ) {
2204					return false;
2205				}
2206			}
2207			return true;
2208		} :
2209		matchers[0];
2210}
2211
2212function multipleContexts( selector, contexts, results ) {
2213	var i = 0,
2214		len = contexts.length;
2215	for ( ; i < len; i++ ) {
2216		Sizzle( selector, contexts[i], results );
2217	}
2218	return results;
2219}
2220
2221function condense( unmatched, map, filter, context, xml ) {
2222	var elem,
2223		newUnmatched = [],
2224		i = 0,
2225		len = unmatched.length,
2226		mapped = map != null;
2227
2228	for ( ; i < len; i++ ) {
2229		if ( (elem = unmatched[i]) ) {
2230			if ( !filter || filter( elem, context, xml ) ) {
2231				newUnmatched.push( elem );
2232				if ( mapped ) {
2233					map.push( i );
2234				}
2235			}
2236		}
2237	}
2238
2239	return newUnmatched;
2240}
2241
2242function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
2243	if ( postFilter && !postFilter[ expando ] ) {
2244		postFilter = setMatcher( postFilter );
2245	}
2246	if ( postFinder && !postFinder[ expando ] ) {
2247		postFinder = setMatcher( postFinder, postSelector );
2248	}
2249	return markFunction(function( seed, results, context, xml ) {
2250		var temp, i, elem,
2251			preMap = [],
2252			postMap = [],
2253			preexisting = results.length,
2254
2255			// Get initial elements from seed or context
2256			elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
2257
2258			// Prefilter to get matcher input, preserving a map for seed-results synchronization
2259			matcherIn = preFilter && ( seed || !selector ) ?
2260				condense( elems, preMap, preFilter, context, xml ) :
2261				elems,
2262
2263			matcherOut = matcher ?
2264				// If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
2265				postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
2266
2267					// ...intermediate processing is necessary
2268					[] :
2269
2270					// ...otherwise use results directly
2271					results :
2272				matcherIn;
2273
2274		// Find primary matches
2275		if ( matcher ) {
2276			matcher( matcherIn, matcherOut, context, xml );
2277		}
2278
2279		// Apply postFilter
2280		if ( postFilter ) {
2281			temp = condense( matcherOut, postMap );
2282			postFilter( temp, [], context, xml );
2283
2284			// Un-match failing elements by moving them back to matcherIn
2285			i = temp.length;
2286			while ( i-- ) {
2287				if ( (elem = temp[i]) ) {
2288					matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
2289				}
2290			}
2291		}
2292
2293		if ( seed ) {
2294			if ( postFinder || preFilter ) {
2295				if ( postFinder ) {
2296					// Get the final matcherOut by condensing this intermediate into postFinder contexts
2297					temp = [];
2298					i = matcherOut.length;
2299					while ( i-- ) {
2300						if ( (elem = matcherOut[i]) ) {
2301							// Restore matcherIn since elem is not yet a final match
2302							temp.push( (matcherIn[i] = elem) );
2303						}
2304					}
2305					postFinder( null, (matcherOut = []), temp, xml );
2306				}
2307
2308				// Move matched elements from seed to results to keep them synchronized
2309				i = matcherOut.length;
2310				while ( i-- ) {
2311					if ( (elem = matcherOut[i]) &&
2312						(temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) {
2313
2314						seed[temp] = !(results[temp] = elem);
2315					}
2316				}
2317			}
2318
2319		// Add elements to results, through postFinder if defined
2320		} else {
2321			matcherOut = condense(
2322				matcherOut === results ?
2323					matcherOut.splice( preexisting, matcherOut.length ) :
2324					matcherOut
2325			);
2326			if ( postFinder ) {
2327				postFinder( null, results, matcherOut, xml );
2328			} else {
2329				push.apply( results, matcherOut );
2330			}
2331		}
2332	});
2333}
2334
2335function matcherFromTokens( tokens ) {
2336	var checkContext, matcher, j,
2337		len = tokens.length,
2338		leadingRelative = Expr.relative[ tokens[0].type ],
2339		implicitRelative = leadingRelative || Expr.relative[" "],
2340		i = leadingRelative ? 1 : 0,
2341
2342		// The foundational matcher ensures that elements are reachable from top-level context(s)
2343		matchContext = addCombinator( function( elem ) {
2344			return elem === checkContext;
2345		}, implicitRelative, true ),
2346		matchAnyContext = addCombinator( function( elem ) {
2347			return indexOf( checkContext, elem ) > -1;
2348		}, implicitRelative, true ),
2349		matchers = [ function( elem, context, xml ) {
2350			var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
2351				(checkContext = context).nodeType ?
2352					matchContext( elem, context, xml ) :
2353					matchAnyContext( elem, context, xml ) );
2354			// Avoid hanging onto element (issue #299)
2355			checkContext = null;
2356			return ret;
2357		} ];
2358
2359	for ( ; i < len; i++ ) {
2360		if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
2361			matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
2362		} else {
2363			matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
2364
2365			// Return special upon seeing a positional matcher
2366			if ( matcher[ expando ] ) {
2367				// Find the next relative operator (if any) for proper handling
2368				j = ++i;
2369				for ( ; j < len; j++ ) {
2370					if ( Expr.relative[ tokens[j].type ] ) {
2371						break;
2372					}
2373				}
2374				return setMatcher(
2375					i > 1 && elementMatcher( matchers ),
2376					i > 1 && toSelector(
2377						// If the preceding token was a descendant combinator, insert an implicit any-element `*`
2378						tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
2379					).replace( rtrim, "$1" ),
2380					matcher,
2381					i < j && matcherFromTokens( tokens.slice( i, j ) ),
2382					j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
2383					j < len && toSelector( tokens )
2384				);
2385			}
2386			matchers.push( matcher );
2387		}
2388	}
2389
2390	return elementMatcher( matchers );
2391}
2392
2393function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
2394	var bySet = setMatchers.length > 0,
2395		byElement = elementMatchers.length > 0,
2396		superMatcher = function( seed, context, xml, results, outermost ) {
2397			var elem, j, matcher,
2398				matchedCount = 0,
2399				i = "0",
2400				unmatched = seed && [],
2401				setMatched = [],
2402				contextBackup = outermostContext,
2403				// We must always have either seed elements or outermost context
2404				elems = seed || byElement && Expr.find["TAG"]( "*", outermost ),
2405				// Use integer dirruns iff this is the outermost matcher
2406				dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
2407				len = elems.length;
2408
2409			if ( outermost ) {
2410				outermostContext = context === document || context || outermost;
2411			}
2412
2413			// Add elements passing elementMatchers directly to results
2414			// Support: IE<9, Safari
2415			// Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id
2416			for ( ; i !== len && (elem = elems[i]) != null; i++ ) {
2417				if ( byElement && elem ) {
2418					j = 0;
2419					if ( !context && elem.ownerDocument !== document ) {
2420						setDocument( elem );
2421						xml = !documentIsHTML;
2422					}
2423					while ( (matcher = elementMatchers[j++]) ) {
2424						if ( matcher( elem, context || document, xml) ) {
2425							results.push( elem );
2426							break;
2427						}
2428					}
2429					if ( outermost ) {
2430						dirruns = dirrunsUnique;
2431					}
2432				}
2433
2434				// Track unmatched elements for set filters
2435				if ( bySet ) {
2436					// They will have gone through all possible matchers
2437					if ( (elem = !matcher && elem) ) {
2438						matchedCount--;
2439					}
2440
2441					// Lengthen the array for every element, matched or not
2442					if ( seed ) {
2443						unmatched.push( elem );
2444					}
2445				}
2446			}
2447
2448			// `i` is now the count of elements visited above, and adding it to `matchedCount`
2449			// makes the latter nonnegative.
2450			matchedCount += i;
2451
2452			// Apply set filters to unmatched elements
2453			// NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount`
2454			// equals `i`), unless we didn't visit _any_ elements in the above loop because we have
2455			// no element matchers and no seed.
2456			// Incrementing an initially-string "0" `i` allows `i` to remain a string only in that
2457			// case, which will result in a "00" `matchedCount` that differs from `i` but is also
2458			// numerically zero.
2459			if ( bySet && i !== matchedCount ) {
2460				j = 0;
2461				while ( (matcher = setMatchers[j++]) ) {
2462					matcher( unmatched, setMatched, context, xml );
2463				}
2464
2465				if ( seed ) {
2466					// Reintegrate element matches to eliminate the need for sorting
2467					if ( matchedCount > 0 ) {
2468						while ( i-- ) {
2469							if ( !(unmatched[i] || setMatched[i]) ) {
2470								setMatched[i] = pop.call( results );
2471							}
2472						}
2473					}
2474
2475					// Discard index placeholder values to get only actual matches
2476					setMatched = condense( setMatched );
2477				}
2478
2479				// Add matches to results
2480				push.apply( results, setMatched );
2481
2482				// Seedless set matches succeeding multiple successful matchers stipulate sorting
2483				if ( outermost && !seed && setMatched.length > 0 &&
2484					( matchedCount + setMatchers.length ) > 1 ) {
2485
2486					Sizzle.uniqueSort( results );
2487				}
2488			}
2489
2490			// Override manipulation of globals by nested matchers
2491			if ( outermost ) {
2492				dirruns = dirrunsUnique;
2493				outermostContext = contextBackup;
2494			}
2495
2496			return unmatched;
2497		};
2498
2499	return bySet ?
2500		markFunction( superMatcher ) :
2501		superMatcher;
2502}
2503
2504compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {
2505	var i,
2506		setMatchers = [],
2507		elementMatchers = [],
2508		cached = compilerCache[ selector + " " ];
2509
2510	if ( !cached ) {
2511		// Generate a function of recursive functions that can be used to check each element
2512		if ( !match ) {
2513			match = tokenize( selector );
2514		}
2515		i = match.length;
2516		while ( i-- ) {
2517			cached = matcherFromTokens( match[i] );
2518			if ( cached[ expando ] ) {
2519				setMatchers.push( cached );
2520			} else {
2521				elementMatchers.push( cached );
2522			}
2523		}
2524
2525		// Cache the compiled function
2526		cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
2527
2528		// Save selector and tokenization
2529		cached.selector = selector;
2530	}
2531	return cached;
2532};
2533
2534/**
2535 * A low-level selection function that works with Sizzle's compiled
2536 *  selector functions
2537 * @param {String|Function} selector A selector or a pre-compiled
2538 *  selector function built with Sizzle.compile
2539 * @param {Element} context
2540 * @param {Array} [results]
2541 * @param {Array} [seed] A set of elements to match against
2542 */
2543select = Sizzle.select = function( selector, context, results, seed ) {
2544	var i, tokens, token, type, find,
2545		compiled = typeof selector === "function" && selector,
2546		match = !seed && tokenize( (selector = compiled.selector || selector) );
2547
2548	results = results || [];
2549
2550	// Try to minimize operations if there is only one selector in the list and no seed
2551	// (the latter of which guarantees us context)
2552	if ( match.length === 1 ) {
2553
2554		// Reduce context if the leading compound selector is an ID
2555		tokens = match[0] = match[0].slice( 0 );
2556		if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
2557				support.getById && context.nodeType === 9 && documentIsHTML &&
2558				Expr.relative[ tokens[1].type ] ) {
2559
2560			context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
2561			if ( !context ) {
2562				return results;
2563
2564			// Precompiled matchers will still verify ancestry, so step up a level
2565			} else if ( compiled ) {
2566				context = context.parentNode;
2567			}
2568
2569			selector = selector.slice( tokens.shift().value.length );
2570		}
2571
2572		// Fetch a seed set for right-to-left matching
2573		i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
2574		while ( i-- ) {
2575			token = tokens[i];
2576
2577			// Abort if we hit a combinator
2578			if ( Expr.relative[ (type = token.type) ] ) {
2579				break;
2580			}
2581			if ( (find = Expr.find[ type ]) ) {
2582				// Search, expanding context for leading sibling combinators
2583				if ( (seed = find(
2584					token.matches[0].replace( runescape, funescape ),
2585					rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context
2586				)) ) {
2587
2588					// If seed is empty or no tokens remain, we can return early
2589					tokens.splice( i, 1 );
2590					selector = seed.length && toSelector( tokens );
2591					if ( !selector ) {
2592						push.apply( results, seed );
2593						return results;
2594					}
2595
2596					break;
2597				}
2598			}
2599		}
2600	}
2601
2602	// Compile and execute a filtering function if one is not provided
2603	// Provide `match` to avoid retokenization if we modified the selector above
2604	( compiled || compile( selector, match ) )(
2605		seed,
2606		context,
2607		!documentIsHTML,
2608		results,
2609		!context || rsibling.test( selector ) && testContext( context.parentNode ) || context
2610	);
2611	return results;
2612};
2613
2614// One-time assignments
2615
2616// Sort stability
2617support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
2618
2619// Support: Chrome 14-35+
2620// Always assume duplicates if they aren't passed to the comparison function
2621support.detectDuplicates = !!hasDuplicate;
2622
2623// Initialize against the default document
2624setDocument();
2625
2626// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
2627// Detached nodes confoundingly follow *each other*
2628support.sortDetached = assert(function( div1 ) {
2629	// Should return 1, but returns 4 (following)
2630	return div1.compareDocumentPosition( document.createElement("div") ) & 1;
2631});
2632
2633// Support: IE<8
2634// Prevent attribute/property "interpolation"
2635// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
2636if ( !assert(function( div ) {
2637	div.innerHTML = "<a href='#'></a>";
2638	return div.firstChild.getAttribute("href") === "#" ;
2639}) ) {
2640	addHandle( "type|href|height|width", function( elem, name, isXML ) {
2641		if ( !isXML ) {
2642			return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
2643		}
2644	});
2645}
2646
2647// Support: IE<9
2648// Use defaultValue in place of getAttribute("value")
2649if ( !support.attributes || !assert(function( div ) {
2650	div.innerHTML = "<input/>";
2651	div.firstChild.setAttribute( "value", "" );
2652	return div.firstChild.getAttribute( "value" ) === "";
2653}) ) {
2654	addHandle( "value", function( elem, name, isXML ) {
2655		if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
2656			return elem.defaultValue;
2657		}
2658	});
2659}
2660
2661// Support: IE<9
2662// Use getAttributeNode to fetch booleans when getAttribute lies
2663if ( !assert(function( div ) {
2664	return div.getAttribute("disabled") == null;
2665}) ) {
2666	addHandle( booleans, function( elem, name, isXML ) {
2667		var val;
2668		if ( !isXML ) {
2669			return elem[ name ] === true ? name.toLowerCase() :
2670					(val = elem.getAttributeNode( name )) && val.specified ?
2671					val.value :
2672				null;
2673		}
2674	});
2675}
2676
2677return Sizzle;
2678
2679})( window );
2680
2681
2682
2683jQuery.find = Sizzle;
2684jQuery.expr = Sizzle.selectors;
2685jQuery.expr[ ":" ] = jQuery.expr.pseudos;
2686jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort;
2687jQuery.text = Sizzle.getText;
2688jQuery.isXMLDoc = Sizzle.isXML;
2689jQuery.contains = Sizzle.contains;
2690
2691
2692
2693var dir = function( elem, dir, until ) {
2694	var matched = [],
2695		truncate = until !== undefined;
2696
2697	while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) {
2698		if ( elem.nodeType === 1 ) {
2699			if ( truncate && jQuery( elem ).is( until ) ) {
2700				break;
2701			}
2702			matched.push( elem );
2703		}
2704	}
2705	return matched;
2706};
2707
2708
2709var siblings = function( n, elem ) {
2710	var matched = [];
2711
2712	for ( ; n; n = n.nextSibling ) {
2713		if ( n.nodeType === 1 && n !== elem ) {
2714			matched.push( n );
2715		}
2716	}
2717
2718	return matched;
2719};
2720
2721
2722var rneedsContext = jQuery.expr.match.needsContext;
2723
2724var rsingleTag = ( /^<([\w-]+)\s*\/?>(?:<\/\1>|)$/ );
2725
2726
2727
2728var risSimple = /^.[^:#\[\.,]*$/;
2729
2730// Implement the identical functionality for filter and not
2731function winnow( elements, qualifier, not ) {
2732	if ( jQuery.isFunction( qualifier ) ) {
2733		return jQuery.grep( elements, function( elem, i ) {
2734			/* jshint -W018 */
2735			return !!qualifier.call( elem, i, elem ) !== not;
2736		} );
2737
2738	}
2739
2740	if ( qualifier.nodeType ) {
2741		return jQuery.grep( elements, function( elem ) {
2742			return ( elem === qualifier ) !== not;
2743		} );
2744
2745	}
2746
2747	if ( typeof qualifier === "string" ) {
2748		if ( risSimple.test( qualifier ) ) {
2749			return jQuery.filter( qualifier, elements, not );
2750		}
2751
2752		qualifier = jQuery.filter( qualifier, elements );
2753	}
2754
2755	return jQuery.grep( elements, function( elem ) {
2756		return ( indexOf.call( qualifier, elem ) > -1 ) !== not;
2757	} );
2758}
2759
2760jQuery.filter = function( expr, elems, not ) {
2761	var elem = elems[ 0 ];
2762
2763	if ( not ) {
2764		expr = ":not(" + expr + ")";
2765	}
2766
2767	return elems.length === 1 && elem.nodeType === 1 ?
2768		jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :
2769		jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
2770			return elem.nodeType === 1;
2771		} ) );
2772};
2773
2774jQuery.fn.extend( {
2775	find: function( selector ) {
2776		var i,
2777			len = this.length,
2778			ret = [],
2779			self = this;
2780
2781		if ( typeof selector !== "string" ) {
2782			return this.pushStack( jQuery( selector ).filter( function() {
2783				for ( i = 0; i < len; i++ ) {
2784					if ( jQuery.contains( self[ i ], this ) ) {
2785						return true;
2786					}
2787				}
2788			} ) );
2789		}
2790
2791		for ( i = 0; i < len; i++ ) {
2792			jQuery.find( selector, self[ i ], ret );
2793		}
2794
2795		// Needed because $( selector, context ) becomes $( context ).find( selector )
2796		ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
2797		ret.selector = this.selector ? this.selector + " " + selector : selector;
2798		return ret;
2799	},
2800	filter: function( selector ) {
2801		return this.pushStack( winnow( this, selector || [], false ) );
2802	},
2803	not: function( selector ) {
2804		return this.pushStack( winnow( this, selector || [], true ) );
2805	},
2806	is: function( selector ) {
2807		return !!winnow(
2808			this,
2809
2810			// If this is a positional/relative selector, check membership in the returned set
2811			// so $("p:first").is("p:last") won't return true for a doc with two "p".
2812			typeof selector === "string" && rneedsContext.test( selector ) ?
2813				jQuery( selector ) :
2814				selector || [],
2815			false
2816		).length;
2817	}
2818} );
2819
2820
2821// Initialize a jQuery object
2822
2823
2824// A central reference to the root jQuery(document)
2825var rootjQuery,
2826
2827	// A simple way to check for HTML strings
2828	// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
2829	// Strict HTML recognition (#11290: must start with <)
2830	rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,
2831
2832	init = jQuery.fn.init = function( selector, context, root ) {
2833		var match, elem;
2834
2835		// HANDLE: $(""), $(null), $(undefined), $(false)
2836		if ( !selector ) {
2837			return this;
2838		}
2839
2840		// Method init() accepts an alternate rootjQuery
2841		// so migrate can support jQuery.sub (gh-2101)
2842		root = root || rootjQuery;
2843
2844		// Handle HTML strings
2845		if ( typeof selector === "string" ) {
2846			if ( selector[ 0 ] === "<" &&
2847				selector[ selector.length - 1 ] === ">" &&
2848				selector.length >= 3 ) {
2849
2850				// Assume that strings that start and end with <> are HTML and skip the regex check
2851				match = [ null, selector, null ];
2852
2853			} else {
2854				match = rquickExpr.exec( selector );
2855			}
2856
2857			// Match html or make sure no context is specified for #id
2858			if ( match && ( match[ 1 ] || !context ) ) {
2859
2860				// HANDLE: $(html) -> $(array)
2861				if ( match[ 1 ] ) {
2862					context = context instanceof jQuery ? context[ 0 ] : context;
2863
2864					// Option to run scripts is true for back-compat
2865					// Intentionally let the error be thrown if parseHTML is not present
2866					jQuery.merge( this, jQuery.parseHTML(
2867						match[ 1 ],
2868						context && context.nodeType ? context.ownerDocument || context : document,
2869						true
2870					) );
2871
2872					// HANDLE: $(html, props)
2873					if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) {
2874						for ( match in context ) {
2875
2876							// Properties of context are called as methods if possible
2877							if ( jQuery.isFunction( this[ match ] ) ) {
2878								this[ match ]( context[ match ] );
2879
2880							// ...and otherwise set as attributes
2881							} else {
2882								this.attr( match, context[ match ] );
2883							}
2884						}
2885					}
2886
2887					return this;
2888
2889				// HANDLE: $(#id)
2890				} else {
2891					elem = document.getElementById( match[ 2 ] );
2892
2893					// Support: Blackberry 4.6
2894					// gEBID returns nodes no longer in the document (#6963)
2895					if ( elem && elem.parentNode ) {
2896
2897						// Inject the element directly into the jQuery object
2898						this.length = 1;
2899						this[ 0 ] = elem;
2900					}
2901
2902					this.context = document;
2903					this.selector = selector;
2904					return this;
2905				}
2906
2907			// HANDLE: $(expr, $(...))
2908			} else if ( !context || context.jquery ) {
2909				return ( context || root ).find( selector );
2910
2911			// HANDLE: $(expr, context)
2912			// (which is just equivalent to: $(context).find(expr)
2913			} else {
2914				return this.constructor( context ).find( selector );
2915			}
2916
2917		// HANDLE: $(DOMElement)
2918		} else if ( selector.nodeType ) {
2919			this.context = this[ 0 ] = selector;
2920			this.length = 1;
2921			return this;
2922
2923		// HANDLE: $(function)
2924		// Shortcut for document ready
2925		} else if ( jQuery.isFunction( selector ) ) {
2926			return root.ready !== undefined ?
2927				root.ready( selector ) :
2928
2929				// Execute immediately if ready is not present
2930				selector( jQuery );
2931		}
2932
2933		if ( selector.selector !== undefined ) {
2934			this.selector = selector.selector;
2935			this.context = selector.context;
2936		}
2937
2938		return jQuery.makeArray( selector, this );
2939	};
2940
2941// Give the init function the jQuery prototype for later instantiation
2942init.prototype = jQuery.fn;
2943
2944// Initialize central reference
2945rootjQuery = jQuery( document );
2946
2947
2948var rparentsprev = /^(?:parents|prev(?:Until|All))/,
2949
2950	// Methods guaranteed to produce a unique set when starting from a unique set
2951	guaranteedUnique = {
2952		children: true,
2953		contents: true,
2954		next: true,
2955		prev: true
2956	};
2957
2958jQuery.fn.extend( {
2959	has: function( target ) {
2960		var targets = jQuery( target, this ),
2961			l = targets.length;
2962
2963		return this.filter( function() {
2964			var i = 0;
2965			for ( ; i < l; i++ ) {
2966				if ( jQuery.contains( this, targets[ i ] ) ) {
2967					return true;
2968				}
2969			}
2970		} );
2971	},
2972
2973	closest: function( selectors, context ) {
2974		var cur,
2975			i = 0,
2976			l = this.length,
2977			matched = [],
2978			pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
2979				jQuery( selectors, context || this.context ) :
2980				0;
2981
2982		for ( ; i < l; i++ ) {
2983			for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) {
2984
2985				// Always skip document fragments
2986				if ( cur.nodeType < 11 && ( pos ?
2987					pos.index( cur ) > -1 :
2988
2989					// Don't pass non-elements to Sizzle
2990					cur.nodeType === 1 &&
2991						jQuery.find.matchesSelector( cur, selectors ) ) ) {
2992
2993					matched.push( cur );
2994					break;
2995				}
2996			}
2997		}
2998
2999		return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched );
3000	},
3001
3002	// Determine the position of an element within the set
3003	index: function( elem ) {
3004
3005		// No argument, return index in parent
3006		if ( !elem ) {
3007			return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;
3008		}
3009
3010		// Index in selector
3011		if ( typeof elem === "string" ) {
3012			return indexOf.call( jQuery( elem ), this[ 0 ] );
3013		}
3014
3015		// Locate the position of the desired element
3016		return indexOf.call( this,
3017
3018			// If it receives a jQuery object, the first element is used
3019			elem.jquery ? elem[ 0 ] : elem
3020		);
3021	},
3022
3023	add: function( selector, context ) {
3024		return this.pushStack(
3025			jQuery.uniqueSort(
3026				jQuery.merge( this.get(), jQuery( selector, context ) )
3027			)
3028		);
3029	},
3030
3031	addBack: function( selector ) {
3032		return this.add( selector == null ?
3033			this.prevObject : this.prevObject.filter( selector )
3034		);
3035	}
3036} );
3037
3038function sibling( cur, dir ) {
3039	while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {}
3040	return cur;
3041}
3042
3043jQuery.each( {
3044	parent: function( elem ) {
3045		var parent = elem.parentNode;
3046		return parent && parent.nodeType !== 11 ? parent : null;
3047	},
3048	parents: function( elem ) {
3049		return dir( elem, "parentNode" );
3050	},
3051	parentsUntil: function( elem, i, until ) {
3052		return dir( elem, "parentNode", until );
3053	},
3054	next: function( elem ) {
3055		return sibling( elem, "nextSibling" );
3056	},
3057	prev: function( elem ) {
3058		return sibling( elem, "previousSibling" );
3059	},
3060	nextAll: function( elem ) {
3061		return dir( elem, "nextSibling" );
3062	},
3063	prevAll: function( elem ) {
3064		return dir( elem, "previousSibling" );
3065	},
3066	nextUntil: function( elem, i, until ) {
3067		return dir( elem, "nextSibling", until );
3068	},
3069	prevUntil: function( elem, i, until ) {
3070		return dir( elem, "previousSibling", until );
3071	},
3072	siblings: function( elem ) {
3073		return siblings( ( elem.parentNode || {} ).firstChild, elem );
3074	},
3075	children: function( elem ) {
3076		return siblings( elem.firstChild );
3077	},
3078	contents: function( elem ) {
3079		return elem.contentDocument || jQuery.merge( [], elem.childNodes );
3080	}
3081}, function( name, fn ) {
3082	jQuery.fn[ name ] = function( until, selector ) {
3083		var matched = jQuery.map( this, fn, until );
3084
3085		if ( name.slice( -5 ) !== "Until" ) {
3086			selector = until;
3087		}
3088
3089		if ( selector && typeof selector === "string" ) {
3090			matched = jQuery.filter( selector, matched );
3091		}
3092
3093		if ( this.length > 1 ) {
3094
3095			// Remove duplicates
3096			if ( !guaranteedUnique[ name ] ) {
3097				jQuery.uniqueSort( matched );
3098			}
3099
3100			// Reverse order for parents* and prev-derivatives
3101			if ( rparentsprev.test( name ) ) {
3102				matched.reverse();
3103			}
3104		}
3105
3106		return this.pushStack( matched );
3107	};
3108} );
3109var rnotwhite = ( /\S+/g );
3110
3111
3112
3113// Convert String-formatted options into Object-formatted ones
3114function createOptions( options ) {
3115	var object = {};
3116	jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) {
3117		object[ flag ] = true;
3118	} );
3119	return object;
3120}
3121
3122/*
3123 * Create a callback list using the following parameters:
3124 *
3125 *	options: an optional list of space-separated options that will change how
3126 *			the callback list behaves or a more traditional option object
3127 *
3128 * By default a callback list will act like an event callback list and can be
3129 * "fired" multiple times.
3130 *
3131 * Possible options:
3132 *
3133 *	once:			will ensure the callback list can only be fired once (like a Deferred)
3134 *
3135 *	memory:			will keep track of previous values and will call any callback added
3136 *					after the list has been fired right away with the latest "memorized"
3137 *					values (like a Deferred)
3138 *
3139 *	unique:			will ensure a callback can only be added once (no duplicate in the list)
3140 *
3141 *	stopOnFalse:	interrupt callings when a callback returns false
3142 *
3143 */
3144jQuery.Callbacks = function( options ) {
3145
3146	// Convert options from String-formatted to Object-formatted if needed
3147	// (we check in cache first)
3148	options = typeof options === "string" ?
3149		createOptions( options ) :
3150		jQuery.extend( {}, options );
3151
3152	var // Flag to know if list is currently firing
3153		firing,
3154
3155		// Last fire value for non-forgettable lists
3156		memory,
3157
3158		// Flag to know if list was already fired
3159		fired,
3160
3161		// Flag to prevent firing
3162		locked,
3163
3164		// Actual callback list
3165		list = [],
3166
3167		// Queue of execution data for repeatable lists
3168		queue = [],
3169
3170		// Index of currently firing callback (modified by add/remove as needed)
3171		firingIndex = -1,
3172
3173		// Fire callbacks
3174		fire = function() {
3175
3176			// Enforce single-firing
3177			locked = options.once;
3178
3179			// Execute callbacks for all pending executions,
3180			// respecting firingIndex overrides and runtime changes
3181			fired = firing = true;
3182			for ( ; queue.length; firingIndex = -1 ) {
3183				memory = queue.shift();
3184				while ( ++firingIndex < list.length ) {
3185
3186					// Run callback and check for early termination
3187					if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&
3188						options.stopOnFalse ) {
3189
3190						// Jump to end and forget the data so .add doesn't re-fire
3191						firingIndex = list.length;
3192						memory = false;
3193					}
3194				}
3195			}
3196
3197			// Forget the data if we're done with it
3198			if ( !options.memory ) {
3199				memory = false;
3200			}
3201
3202			firing = false;
3203
3204			// Clean up if we're done firing for good
3205			if ( locked ) {
3206
3207				// Keep an empty list if we have data for future add calls
3208				if ( memory ) {
3209					list = [];
3210
3211				// Otherwise, this object is spent
3212				} else {
3213					list = "";
3214				}
3215			}
3216		},
3217
3218		// Actual Callbacks object
3219		self = {
3220
3221			// Add a callback or a collection of callbacks to the list
3222			add: function() {
3223				if ( list ) {
3224
3225					// If we have memory from a past run, we should fire after adding
3226					if ( memory && !firing ) {
3227						firingIndex = list.length - 1;
3228						queue.push( memory );
3229					}
3230
3231					( function add( args ) {
3232						jQuery.each( args, function( _, arg ) {
3233							if ( jQuery.isFunction( arg ) ) {
3234								if ( !options.unique || !self.has( arg ) ) {
3235									list.push( arg );
3236								}
3237							} else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) {
3238
3239								// Inspect recursively
3240								add( arg );
3241							}
3242						} );
3243					} )( arguments );
3244
3245					if ( memory && !firing ) {
3246						fire();
3247					}
3248				}
3249				return this;
3250			},
3251
3252			// Remove a callback from the list
3253			remove: function() {
3254				jQuery.each( arguments, function( _, arg ) {
3255					var index;
3256					while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
3257						list.splice( index, 1 );
3258
3259						// Handle firing indexes
3260						if ( index <= firingIndex ) {
3261							firingIndex--;
3262						}
3263					}
3264				} );
3265				return this;
3266			},
3267
3268			// Check if a given callback is in the list.
3269			// If no argument is given, return whether or not list has callbacks attached.
3270			has: function( fn ) {
3271				return fn ?
3272					jQuery.inArray( fn, list ) > -1 :
3273					list.length > 0;
3274			},
3275
3276			// Remove all callbacks from the list
3277			empty: function() {
3278				if ( list ) {
3279					list = [];
3280				}
3281				return this;
3282			},
3283
3284			// Disable .fire and .add
3285			// Abort any current/pending executions
3286			// Clear all callbacks and values
3287			disable: function() {
3288				locked = queue = [];
3289				list = memory = "";
3290				return this;
3291			},
3292			disabled: function() {
3293				return !list;
3294			},
3295
3296			// Disable .fire
3297			// Also disable .add unless we have memory (since it would have no effect)
3298			// Abort any pending executions
3299			lock: function() {
3300				locked = queue = [];
3301				if ( !memory ) {
3302					list = memory = "";
3303				}
3304				return this;
3305			},
3306			locked: function() {
3307				return !!locked;
3308			},
3309
3310			// Call all callbacks with the given context and arguments
3311			fireWith: function( context, args ) {
3312				if ( !locked ) {
3313					args = args || [];
3314					args = [ context, args.slice ? args.slice() : args ];
3315					queue.push( args );
3316					if ( !firing ) {
3317						fire();
3318					}
3319				}
3320				return this;
3321			},
3322
3323			// Call all the callbacks with the given arguments
3324			fire: function() {
3325				self.fireWith( this, arguments );
3326				return this;
3327			},
3328
3329			// To know if the callbacks have already been called at least once
3330			fired: function() {
3331				return !!fired;
3332			}
3333		};
3334
3335	return self;
3336};
3337
3338
3339jQuery.extend( {
3340
3341	Deferred: function( func ) {
3342		var tuples = [
3343
3344				// action, add listener, listener list, final state
3345				[ "resolve", "done", jQuery.Callbacks( "once memory" ), "resolved" ],
3346				[ "reject", "fail", jQuery.Callbacks( "once memory" ), "rejected" ],
3347				[ "notify", "progress", jQuery.Callbacks( "memory" ) ]
3348			],
3349			state = "pending",
3350			promise = {
3351				state: function() {
3352					return state;
3353				},
3354				always: function() {
3355					deferred.done( arguments ).fail( arguments );
3356					return this;
3357				},
3358				then: function( /* fnDone, fnFail, fnProgress */ ) {
3359					var fns = arguments;
3360					return jQuery.Deferred( function( newDefer ) {
3361						jQuery.each( tuples, function( i, tuple ) {
3362							var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
3363
3364							// deferred[ done | fail | progress ] for forwarding actions to newDefer
3365							deferred[ tuple[ 1 ] ]( function() {
3366								var returned = fn && fn.apply( this, arguments );
3367								if ( returned && jQuery.isFunction( returned.promise ) ) {
3368									returned.promise()
3369										.progress( newDefer.notify )
3370										.done( newDefer.resolve )
3371										.fail( newDefer.reject );
3372								} else {
3373									newDefer[ tuple[ 0 ] + "With" ](
3374										this === promise ? newDefer.promise() : this,
3375										fn ? [ returned ] : arguments
3376									);
3377								}
3378							} );
3379						} );
3380						fns = null;
3381					} ).promise();
3382				},
3383
3384				// Get a promise for this deferred
3385				// If obj is provided, the promise aspect is added to the object
3386				promise: function( obj ) {
3387					return obj != null ? jQuery.extend( obj, promise ) : promise;
3388				}
3389			},
3390			deferred = {};
3391
3392		// Keep pipe for back-compat
3393		promise.pipe = promise.then;
3394
3395		// Add list-specific methods
3396		jQuery.each( tuples, function( i, tuple ) {
3397			var list = tuple[ 2 ],
3398				stateString = tuple[ 3 ];
3399
3400			// promise[ done | fail | progress ] = list.add
3401			promise[ tuple[ 1 ] ] = list.add;
3402
3403			// Handle state
3404			if ( stateString ) {
3405				list.add( function() {
3406
3407					// state = [ resolved | rejected ]
3408					state = stateString;
3409
3410				// [ reject_list | resolve_list ].disable; progress_list.lock
3411				}, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
3412			}
3413
3414			// deferred[ resolve | reject | notify ]
3415			deferred[ tuple[ 0 ] ] = function() {
3416				deferred[ tuple[ 0 ] + "With" ]( this === deferred ? promise : this, arguments );
3417				return this;
3418			};
3419			deferred[ tuple[ 0 ] + "With" ] = list.fireWith;
3420		} );
3421
3422		// Make the deferred a promise
3423		promise.promise( deferred );
3424
3425		// Call given func if any
3426		if ( func ) {
3427			func.call( deferred, deferred );
3428		}
3429
3430		// All done!
3431		return deferred;
3432	},
3433
3434	// Deferred helper
3435	when: function( subordinate /* , ..., subordinateN */ ) {
3436		var i = 0,
3437			resolveValues = slice.call( arguments ),
3438			length = resolveValues.length,
3439
3440			// the count of uncompleted subordinates
3441			remaining = length !== 1 ||
3442				( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
3443
3444			// the master Deferred.
3445			// If resolveValues consist of only a single Deferred, just use that.
3446			deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
3447
3448			// Update function for both resolve and progress values
3449			updateFunc = function( i, contexts, values ) {
3450				return function( value ) {
3451					contexts[ i ] = this;
3452					values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
3453					if ( values === progressValues ) {
3454						deferred.notifyWith( contexts, values );
3455					} else if ( !( --remaining ) ) {
3456						deferred.resolveWith( contexts, values );
3457					}
3458				};
3459			},
3460
3461			progressValues, progressContexts, resolveContexts;
3462
3463		// Add listeners to Deferred subordinates; treat others as resolved
3464		if ( length > 1 ) {
3465			progressValues = new Array( length );
3466			progressContexts = new Array( length );
3467			resolveContexts = new Array( length );
3468			for ( ; i < length; i++ ) {
3469				if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
3470					resolveValues[ i ].promise()
3471						.progress( updateFunc( i, progressContexts, progressValues ) )
3472						.done( updateFunc( i, resolveContexts, resolveValues ) )
3473						.fail( deferred.reject );
3474				} else {
3475					--remaining;
3476				}
3477			}
3478		}
3479
3480		// If we're not waiting on anything, resolve the master
3481		if ( !remaining ) {
3482			deferred.resolveWith( resolveContexts, resolveValues );
3483		}
3484
3485		return deferred.promise();
3486	}
3487} );
3488
3489
3490// The deferred used on DOM ready
3491var readyList;
3492
3493jQuery.fn.ready = function( fn ) {
3494
3495	// Add the callback
3496	jQuery.ready.promise().done( fn );
3497
3498	return this;
3499};
3500
3501jQuery.extend( {
3502
3503	// Is the DOM ready to be used? Set to true once it occurs.
3504	isReady: false,
3505
3506	// A counter to track how many items to wait for before
3507	// the ready event fires. See #6781
3508	readyWait: 1,
3509
3510	// Hold (or release) the ready event
3511	holdReady: function( hold ) {
3512		if ( hold ) {
3513			jQuery.readyWait++;
3514		} else {
3515			jQuery.ready( true );
3516		}
3517	},
3518
3519	// Handle when the DOM is ready
3520	ready: function( wait ) {
3521
3522		// Abort if there are pending holds or we're already ready
3523		if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
3524			return;
3525		}
3526
3527		// Remember that the DOM is ready
3528		jQuery.isReady = true;
3529
3530		// If a normal DOM Ready event fired, decrement, and wait if need be
3531		if ( wait !== true && --jQuery.readyWait > 0 ) {
3532			return;
3533		}
3534
3535		// If there are functions bound, to execute
3536		readyList.resolveWith( document, [ jQuery ] );
3537
3538		// Trigger any bound ready events
3539		if ( jQuery.fn.triggerHandler ) {
3540			jQuery( document ).triggerHandler( "ready" );
3541			jQuery( document ).off( "ready" );
3542		}
3543	}
3544} );
3545
3546/**
3547 * The ready event handler and self cleanup method
3548 */
3549function completed() {
3550	document.removeEventListener( "DOMContentLoaded", completed );
3551	window.removeEventListener( "load", completed );
3552	jQuery.ready();
3553}
3554
3555jQuery.ready.promise = function( obj ) {
3556	if ( !readyList ) {
3557
3558		readyList = jQuery.Deferred();
3559
3560		// Catch cases where $(document).ready() is called
3561		// after the browser event has already occurred.
3562		// Support: IE9-10 only
3563		// Older IE sometimes signals "interactive" too soon
3564		if ( document.readyState === "complete" ||
3565			( document.readyState !== "loading" && !document.documentElement.doScroll ) ) {
3566
3567			// Handle it asynchronously to allow scripts the opportunity to delay ready
3568			window.setTimeout( jQuery.ready );
3569
3570		} else {
3571
3572			// Use the handy event callback
3573			document.addEventListener( "DOMContentLoaded", completed );
3574
3575			// A fallback to window.onload, that will always work
3576			window.addEventListener( "load", completed );
3577		}
3578	}
3579	return readyList.promise( obj );
3580};
3581
3582// Kick off the DOM ready check even if the user does not
3583jQuery.ready.promise();
3584
3585
3586
3587
3588// Multifunctional method to get and set values of a collection
3589// The value/s can optionally be executed if it's a function
3590var access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
3591	var i = 0,
3592		len = elems.length,
3593		bulk = key == null;
3594
3595	// Sets many values
3596	if ( jQuery.type( key ) === "object" ) {
3597		chainable = true;
3598		for ( i in key ) {
3599			access( elems, fn, i, key[ i ], true, emptyGet, raw );
3600		}
3601
3602	// Sets one value
3603	} else if ( value !== undefined ) {
3604		chainable = true;
3605
3606		if ( !jQuery.isFunction( value ) ) {
3607			raw = true;
3608		}
3609
3610		if ( bulk ) {
3611
3612			// Bulk operations run against the entire set
3613			if ( raw ) {
3614				fn.call( elems, value );
3615				fn = null;
3616
3617			// ...except when executing function values
3618			} else {
3619				bulk = fn;
3620				fn = function( elem, key, value ) {
3621					return bulk.call( jQuery( elem ), value );
3622				};
3623			}
3624		}
3625
3626		if ( fn ) {
3627			for ( ; i < len; i++ ) {
3628				fn(
3629					elems[ i ], key, raw ?
3630					value :
3631					value.call( elems[ i ], i, fn( elems[ i ], key ) )
3632				);
3633			}
3634		}
3635	}
3636
3637	return chainable ?
3638		elems :
3639
3640		// Gets
3641		bulk ?
3642			fn.call( elems ) :
3643			len ? fn( elems[ 0 ], key ) : emptyGet;
3644};
3645var acceptData = function( owner ) {
3646
3647	// Accepts only:
3648	//  - Node
3649	//    - Node.ELEMENT_NODE
3650	//    - Node.DOCUMENT_NODE
3651	//  - Object
3652	//    - Any
3653	/* jshint -W018 */
3654	return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType );
3655};
3656
3657
3658
3659
3660function Data() {
3661	this.expando = jQuery.expando + Data.uid++;
3662}
3663
3664Data.uid = 1;
3665
3666Data.prototype = {
3667
3668	register: function( owner, initial ) {
3669		var value = initial || {};
3670
3671		// If it is a node unlikely to be stringify-ed or looped over
3672		// use plain assignment
3673		if ( owner.nodeType ) {
3674			owner[ this.expando ] = value;
3675
3676		// Otherwise secure it in a non-enumerable, non-writable property
3677		// configurability must be true to allow the property to be
3678		// deleted with the delete operator
3679		} else {
3680			Object.defineProperty( owner, this.expando, {
3681				value: value,
3682				writable: true,
3683				configurable: true
3684			} );
3685		}
3686		return owner[ this.expando ];
3687	},
3688	cache: function( owner ) {
3689
3690		// We can accept data for non-element nodes in modern browsers,
3691		// but we should not, see #8335.
3692		// Always return an empty object.
3693		if ( !acceptData( owner ) ) {
3694			return {};
3695		}
3696
3697		// Check if the owner object already has a cache
3698		var value = owner[ this.expando ];
3699
3700		// If not, create one
3701		if ( !value ) {
3702			value = {};
3703
3704			// We can accept data for non-element nodes in modern browsers,
3705			// but we should not, see #8335.
3706			// Always return an empty object.
3707			if ( acceptData( owner ) ) {
3708
3709				// If it is a node unlikely to be stringify-ed or looped over
3710				// use plain assignment
3711				if ( owner.nodeType ) {
3712					owner[ this.expando ] = value;
3713
3714				// Otherwise secure it in a non-enumerable property
3715				// configurable must be true to allow the property to be
3716				// deleted when data is removed
3717				} else {
3718					Object.defineProperty( owner, this.expando, {
3719						value: value,
3720						configurable: true
3721					} );
3722				}
3723			}
3724		}
3725
3726		return value;
3727	},
3728	set: function( owner, data, value ) {
3729		var prop,
3730			cache = this.cache( owner );
3731
3732		// Handle: [ owner, key, value ] args
3733		if ( typeof data === "string" ) {
3734			cache[ data ] = value;
3735
3736		// Handle: [ owner, { properties } ] args
3737		} else {
3738
3739			// Copy the properties one-by-one to the cache object
3740			for ( prop in data ) {
3741				cache[ prop ] = data[ prop ];
3742			}
3743		}
3744		return cache;
3745	},
3746	get: function( owner, key ) {
3747		return key === undefined ?
3748			this.cache( owner ) :
3749			owner[ this.expando ] && owner[ this.expando ][ key ];
3750	},
3751	access: function( owner, key, value ) {
3752		var stored;
3753
3754		// In cases where either:
3755		//
3756		//   1. No key was specified
3757		//   2. A string key was specified, but no value provided
3758		//
3759		// Take the "read" path and allow the get method to determine
3760		// which value to return, respectively either:
3761		//
3762		//   1. The entire cache object
3763		//   2. The data stored at the key
3764		//
3765		if ( key === undefined ||
3766				( ( key && typeof key === "string" ) && value === undefined ) ) {
3767
3768			stored = this.get( owner, key );
3769
3770			return stored !== undefined ?
3771				stored : this.get( owner, jQuery.camelCase( key ) );
3772		}
3773
3774		// When the key is not a string, or both a key and value
3775		// are specified, set or extend (existing objects) with either:
3776		//
3777		//   1. An object of properties
3778		//   2. A key and value
3779		//
3780		this.set( owner, key, value );
3781
3782		// Since the "set" path can have two possible entry points
3783		// return the expected data based on which path was taken[*]
3784		return value !== undefined ? value : key;
3785	},
3786	remove: function( owner, key ) {
3787		var i, name, camel,
3788			cache = owner[ this.expando ];
3789
3790		if ( cache === undefined ) {
3791			return;
3792		}
3793
3794		if ( key === undefined ) {
3795			this.register( owner );
3796
3797		} else {
3798
3799			// Support array or space separated string of keys
3800			if ( jQuery.isArray( key ) ) {
3801
3802				// If "name" is an array of keys...
3803				// When data is initially created, via ("key", "val") signature,
3804				// keys will be converted to camelCase.
3805				// Since there is no way to tell _how_ a key was added, remove
3806				// both plain key and camelCase key. #12786
3807				// This will only penalize the array argument path.
3808				name = key.concat( key.map( jQuery.camelCase ) );
3809			} else {
3810				camel = jQuery.camelCase( key );
3811
3812				// Try the string as a key before any manipulation
3813				if ( key in cache ) {
3814					name = [ key, camel ];
3815				} else {
3816
3817					// If a key with the spaces exists, use it.
3818					// Otherwise, create an array by matching non-whitespace
3819					name = camel;
3820					name = name in cache ?
3821						[ name ] : ( name.match( rnotwhite ) || [] );
3822				}
3823			}
3824
3825			i = name.length;
3826
3827			while ( i-- ) {
3828				delete cache[ name[ i ] ];
3829			}
3830		}
3831
3832		// Remove the expando if there's no more data
3833		if ( key === undefined || jQuery.isEmptyObject( cache ) ) {
3834
3835			// Support: Chrome <= 35-45+
3836			// Webkit & Blink performance suffers when deleting properties
3837			// from DOM nodes, so set to undefined instead
3838			// https://code.google.com/p/chromium/issues/detail?id=378607
3839			if ( owner.nodeType ) {
3840				owner[ this.expando ] = undefined;
3841			} else {
3842				delete owner[ this.expando ];
3843			}
3844		}
3845	},
3846	hasData: function( owner ) {
3847		var cache = owner[ this.expando ];
3848		return cache !== undefined && !jQuery.isEmptyObject( cache );
3849	}
3850};
3851var dataPriv = new Data();
3852
3853var dataUser = new Data();
3854
3855
3856
3857//	Implementation Summary
3858//
3859//	1. Enforce API surface and semantic compatibility with 1.9.x branch
3860//	2. Improve the module's maintainability by reducing the storage
3861//		paths to a single mechanism.
3862//	3. Use the same single mechanism to support "private" and "user" data.
3863//	4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData)
3864//	5. Avoid exposing implementation details on user objects (eg. expando properties)
3865//	6. Provide a clear path for implementation upgrade to WeakMap in 2014
3866
3867var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,
3868	rmultiDash = /[A-Z]/g;
3869
3870function dataAttr( elem, key, data ) {
3871	var name;
3872
3873	// If nothing was found internally, try to fetch any
3874	// data from the HTML5 data-* attribute
3875	if ( data === undefined && elem.nodeType === 1 ) {
3876		name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase();
3877		data = elem.getAttribute( name );
3878
3879		if ( typeof data === "string" ) {
3880			try {
3881				data = data === "true" ? true :
3882					data === "false" ? false :
3883					data === "null" ? null :
3884
3885					// Only convert to a number if it doesn't change the string
3886					+data + "" === data ? +data :
3887					rbrace.test( data ) ? jQuery.parseJSON( data ) :
3888					data;
3889			} catch ( e ) {}
3890
3891			// Make sure we set the data so it isn't changed later
3892			dataUser.set( elem, key, data );
3893		} else {
3894			data = undefined;
3895		}
3896	}
3897	return data;
3898}
3899
3900jQuery.extend( {
3901	hasData: function( elem ) {
3902		return dataUser.hasData( elem ) || dataPriv.hasData( elem );
3903	},
3904
3905	data: function( elem, name, data ) {
3906		return dataUser.access( elem, name, data );
3907	},
3908
3909	removeData: function( elem, name ) {
3910		dataUser.remove( elem, name );
3911	},
3912
3913	// TODO: Now that all calls to _data and _removeData have been replaced
3914	// with direct calls to dataPriv methods, these can be deprecated.
3915	_data: function( elem, name, data ) {
3916		return dataPriv.access( elem, name, data );
3917	},
3918
3919	_removeData: function( elem, name ) {
3920		dataPriv.remove( elem, name );
3921	}
3922} );
3923
3924jQuery.fn.extend( {
3925	data: function( key, value ) {
3926		var i, name, data,
3927			elem = this[ 0 ],
3928			attrs = elem && elem.attributes;
3929
3930		// Gets all values
3931		if ( key === undefined ) {
3932			if ( this.length ) {
3933				data = dataUser.get( elem );
3934
3935				if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) {
3936					i = attrs.length;
3937					while ( i-- ) {
3938
3939						// Support: IE11+
3940						// The attrs elements can be null (#14894)
3941						if ( attrs[ i ] ) {
3942							name = attrs[ i ].name;
3943							if ( name.indexOf( "data-" ) === 0 ) {
3944								name = jQuery.camelCase( name.slice( 5 ) );
3945								dataAttr( elem, name, data[ name ] );
3946							}
3947						}
3948					}
3949					dataPriv.set( elem, "hasDataAttrs", true );
3950				}
3951			}
3952
3953			return data;
3954		}
3955
3956		// Sets multiple values
3957		if ( typeof key === "object" ) {
3958			return this.each( function() {
3959				dataUser.set( this, key );
3960			} );
3961		}
3962
3963		return access( this, function( value ) {
3964			var data, camelKey;
3965
3966			// The calling jQuery object (element matches) is not empty
3967			// (and therefore has an element appears at this[ 0 ]) and the
3968			// `value` parameter was not undefined. An empty jQuery object
3969			// will result in `undefined` for elem = this[ 0 ] which will
3970			// throw an exception if an attempt to read a data cache is made.
3971			if ( elem && value === undefined ) {
3972
3973				// Attempt to get data from the cache
3974				// with the key as-is
3975				data = dataUser.get( elem, key ) ||
3976
3977					// Try to find dashed key if it exists (gh-2779)
3978					// This is for 2.2.x only
3979					dataUser.get( elem, key.replace( rmultiDash, "-$&" ).toLowerCase() );
3980
3981				if ( data !== undefined ) {
3982					return data;
3983				}
3984
3985				camelKey = jQuery.camelCase( key );
3986
3987				// Attempt to get data from the cache
3988				// with the key camelized
3989				data = dataUser.get( elem, camelKey );
3990				if ( data !== undefined ) {
3991					return data;
3992				}
3993
3994				// Attempt to "discover" the data in
3995				// HTML5 custom data-* attrs
3996				data = dataAttr( elem, camelKey, undefined );
3997				if ( data !== undefined ) {
3998					return data;
3999				}
4000
4001				// We tried really hard, but the data doesn't exist.
4002				return;
4003			}
4004
4005			// Set the data...
4006			camelKey = jQuery.camelCase( key );
4007			this.each( function() {
4008
4009				// First, attempt to store a copy or reference of any
4010				// data that might've been store with a camelCased key.
4011				var data = dataUser.get( this, camelKey );
4012
4013				// For HTML5 data-* attribute interop, we have to
4014				// store property names with dashes in a camelCase form.
4015				// This might not apply to all properties...*
4016				dataUser.set( this, camelKey, value );
4017
4018				// *... In the case of properties that might _actually_
4019				// have dashes, we need to also store a copy of that
4020				// unchanged property.
4021				if ( key.indexOf( "-" ) > -1 && data !== undefined ) {
4022					dataUser.set( this, key, value );
4023				}
4024			} );
4025		}, null, value, arguments.length > 1, null, true );
4026	},
4027
4028	removeData: function( key ) {
4029		return this.each( function() {
4030			dataUser.remove( this, key );
4031		} );
4032	}
4033} );
4034
4035
4036jQuery.extend( {
4037	queue: function( elem, type, data ) {
4038		var queue;
4039
4040		if ( elem ) {
4041			type = ( type || "fx" ) + "queue";
4042			queue = dataPriv.get( elem, type );
4043
4044			// Speed up dequeue by getting out quickly if this is just a lookup
4045			if ( data ) {
4046				if ( !queue || jQuery.isArray( data ) ) {
4047					queue = dataPriv.access( elem, type, jQuery.makeArray( data ) );
4048				} else {
4049					queue.push( data );
4050				}
4051			}
4052			return queue || [];
4053		}
4054	},
4055
4056	dequeue: function( elem, type ) {
4057		type = type || "fx";
4058
4059		var queue = jQuery.queue( elem, type ),
4060			startLength = queue.length,
4061			fn = queue.shift(),
4062			hooks = jQuery._queueHooks( elem, type ),
4063			next = function() {
4064				jQuery.dequeue( elem, type );
4065			};
4066
4067		// If the fx queue is dequeued, always remove the progress sentinel
4068		if ( fn === "inprogress" ) {
4069			fn = queue.shift();
4070			startLength--;
4071		}
4072
4073		if ( fn ) {
4074
4075			// Add a progress sentinel to prevent the fx queue from being
4076			// automatically dequeued
4077			if ( type === "fx" ) {
4078				queue.unshift( "inprogress" );
4079			}
4080
4081			// Clear up the last queue stop function
4082			delete hooks.stop;
4083			fn.call( elem, next, hooks );
4084		}
4085
4086		if ( !startLength && hooks ) {
4087			hooks.empty.fire();
4088		}
4089	},
4090
4091	// Not public - generate a queueHooks object, or return the current one
4092	_queueHooks: function( elem, type ) {
4093		var key = type + "queueHooks";
4094		return dataPriv.get( elem, key ) || dataPriv.access( elem, key, {
4095			empty: jQuery.Callbacks( "once memory" ).add( function() {
4096				dataPriv.remove( elem, [ type + "queue", key ] );
4097			} )
4098		} );
4099	}
4100} );
4101
4102jQuery.fn.extend( {
4103	queue: function( type, data ) {
4104		var setter = 2;
4105
4106		if ( typeof type !== "string" ) {
4107			data = type;
4108			type = "fx";
4109			setter--;
4110		}
4111
4112		if ( arguments.length < setter ) {
4113			return jQuery.queue( this[ 0 ], type );
4114		}
4115
4116		return data === undefined ?
4117			this :
4118			this.each( function() {
4119				var queue = jQuery.queue( this, type, data );
4120
4121				// Ensure a hooks for this queue
4122				jQuery._queueHooks( this, type );
4123
4124				if ( type === "fx" && queue[ 0 ] !== "inprogress" ) {
4125					jQuery.dequeue( this, type );
4126				}
4127			} );
4128	},
4129	dequeue: function( type ) {
4130		return this.each( function() {
4131			jQuery.dequeue( this, type );
4132		} );
4133	},
4134	clearQueue: function( type ) {
4135		return this.queue( type || "fx", [] );
4136	},
4137
4138	// Get a promise resolved when queues of a certain type
4139	// are emptied (fx is the type by default)
4140	promise: function( type, obj ) {
4141		var tmp,
4142			count = 1,
4143			defer = jQuery.Deferred(),
4144			elements = this,
4145			i = this.length,
4146			resolve = function() {
4147				if ( !( --count ) ) {
4148					defer.resolveWith( elements, [ elements ] );
4149				}
4150			};
4151
4152		if ( typeof type !== "string" ) {
4153			obj = type;
4154			type = undefined;
4155		}
4156		type = type || "fx";
4157
4158		while ( i-- ) {
4159			tmp = dataPriv.get( elements[ i ], type + "queueHooks" );
4160			if ( tmp && tmp.empty ) {
4161				count++;
4162				tmp.empty.add( resolve );
4163			}
4164		}
4165		resolve();
4166		return defer.promise( obj );
4167	}
4168} );
4169var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source;
4170
4171var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" );
4172
4173
4174var cssExpand = [ "Top", "Right", "Bottom", "Left" ];
4175
4176var isHidden = function( elem, el ) {
4177
4178		// isHidden might be called from jQuery#filter function;
4179		// in that case, element will be second argument
4180		elem = el || elem;
4181		return jQuery.css( elem, "display" ) === "none" ||
4182			!jQuery.contains( elem.ownerDocument, elem );
4183	};
4184
4185
4186
4187function adjustCSS( elem, prop, valueParts, tween ) {
4188	var adjusted,
4189		scale = 1,
4190		maxIterations = 20,
4191		currentValue = tween ?
4192			function() { return tween.cur(); } :
4193			function() { return jQuery.css( elem, prop, "" ); },
4194		initial = currentValue(),
4195		unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
4196
4197		// Starting value computation is required for potential unit mismatches
4198		initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) &&
4199			rcssNum.exec( jQuery.css( elem, prop ) );
4200
4201	if ( initialInUnit && initialInUnit[ 3 ] !== unit ) {
4202
4203		// Trust units reported by jQuery.css
4204		unit = unit || initialInUnit[ 3 ];
4205
4206		// Make sure we update the tween properties later on
4207		valueParts = valueParts || [];
4208
4209		// Iteratively approximate from a nonzero starting point
4210		initialInUnit = +initial || 1;
4211
4212		do {
4213
4214			// If previous iteration zeroed out, double until we get *something*.
4215			// Use string for doubling so we don't accidentally see scale as unchanged below
4216			scale = scale || ".5";
4217
4218			// Adjust and apply
4219			initialInUnit = initialInUnit / scale;
4220			jQuery.style( elem, prop, initialInUnit + unit );
4221
4222		// Update scale, tolerating zero or NaN from tween.cur()
4223		// Break the loop if scale is unchanged or perfect, or if we've just had enough.
4224		} while (
4225			scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations
4226		);
4227	}
4228
4229	if ( valueParts ) {
4230		initialInUnit = +initialInUnit || +initial || 0;
4231
4232		// Apply relative offset (+=/-=) if specified
4233		adjusted = valueParts[ 1 ] ?
4234			initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] :
4235			+valueParts[ 2 ];
4236		if ( tween ) {
4237			tween.unit = unit;
4238			tween.start = initialInUnit;
4239			tween.end = adjusted;
4240		}
4241	}
4242	return adjusted;
4243}
4244var rcheckableType = ( /^(?:checkbox|radio)$/i );
4245
4246var rtagName = ( /<([\w:-]+)/ );
4247
4248var rscriptType = ( /^$|\/(?:java|ecma)script/i );
4249
4250
4251
4252// We have to close these tags to support XHTML (#13200)
4253var wrapMap = {
4254
4255	// Support: IE9
4256	option: [ 1, "<select multiple='multiple'>", "</select>" ],
4257
4258	// XHTML parsers do not magically insert elements in the
4259	// same way that tag soup parsers do. So we cannot shorten
4260	// this by omitting <tbody> or other required elements.
4261	thead: [ 1, "<table>", "</table>" ],
4262	col: [ 2, "<table><colgroup>", "</colgroup></table>" ],
4263	tr: [ 2, "<table><tbody>", "</tbody></table>" ],
4264	td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
4265
4266	_default: [ 0, "", "" ]
4267};
4268
4269// Support: IE9
4270wrapMap.optgroup = wrapMap.option;
4271
4272wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
4273wrapMap.th = wrapMap.td;
4274
4275
4276function getAll( context, tag ) {
4277
4278	// Support: IE9-11+
4279	// Use typeof to avoid zero-argument method invocation on host objects (#15151)
4280	var ret = typeof context.getElementsByTagName !== "undefined" ?
4281			context.getElementsByTagName( tag || "*" ) :
4282			typeof context.querySelectorAll !== "undefined" ?
4283				context.querySelectorAll( tag || "*" ) :
4284			[];
4285
4286	return tag === undefined || tag && jQuery.nodeName( context, tag ) ?
4287		jQuery.merge( [ context ], ret ) :
4288		ret;
4289}
4290
4291
4292// Mark scripts as having already been evaluated
4293function setGlobalEval( elems, refElements ) {
4294	var i = 0,
4295		l = elems.length;
4296
4297	for ( ; i < l; i++ ) {
4298		dataPriv.set(
4299			elems[ i ],
4300			"globalEval",
4301			!refElements || dataPriv.get( refElements[ i ], "globalEval" )
4302		);
4303	}
4304}
4305
4306
4307var rhtml = /<|&#?\w+;/;
4308
4309function buildFragment( elems, context, scripts, selection, ignored ) {
4310	var elem, tmp, tag, wrap, contains, j,
4311		fragment = context.createDocumentFragment(),
4312		nodes = [],
4313		i = 0,
4314		l = elems.length;
4315
4316	for ( ; i < l; i++ ) {
4317		elem = elems[ i ];
4318
4319		if ( elem || elem === 0 ) {
4320
4321			// Add nodes directly
4322			if ( jQuery.type( elem ) === "object" ) {
4323
4324				// Support: Android<4.1, PhantomJS<2
4325				// push.apply(_, arraylike) throws on ancient WebKit
4326				jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
4327
4328			// Convert non-html into a text node
4329			} else if ( !rhtml.test( elem ) ) {
4330				nodes.push( context.createTextNode( elem ) );
4331
4332			// Convert html into DOM nodes
4333			} else {
4334				tmp = tmp || fragment.appendChild( context.createElement( "div" ) );
4335
4336				// Deserialize a standard representation
4337				tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase();
4338				wrap = wrapMap[ tag ] || wrapMap._default;
4339				tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ];
4340
4341				// Descend through wrappers to the right content
4342				j = wrap[ 0 ];
4343				while ( j-- ) {
4344					tmp = tmp.lastChild;
4345				}
4346
4347				// Support: Android<4.1, PhantomJS<2
4348				// push.apply(_, arraylike) throws on ancient WebKit
4349				jQuery.merge( nodes, tmp.childNodes );
4350
4351				// Remember the top-level container
4352				tmp = fragment.firstChild;
4353
4354				// Ensure the created nodes are orphaned (#12392)
4355				tmp.textContent = "";
4356			}
4357		}
4358	}
4359
4360	// Remove wrapper from fragment
4361	fragment.textContent = "";
4362
4363	i = 0;
4364	while ( ( elem = nodes[ i++ ] ) ) {
4365
4366		// Skip elements already in the context collection (trac-4087)
4367		if ( selection && jQuery.inArray( elem, selection ) > -1 ) {
4368			if ( ignored ) {
4369				ignored.push( elem );
4370			}
4371			continue;
4372		}
4373
4374		contains = jQuery.contains( elem.ownerDocument, elem );
4375
4376		// Append to fragment
4377		tmp = getAll( fragment.appendChild( elem ), "script" );
4378
4379		// Preserve script evaluation history
4380		if ( contains ) {
4381			setGlobalEval( tmp );
4382		}
4383
4384		// Capture executables
4385		if ( scripts ) {
4386			j = 0;
4387			while ( ( elem = tmp[ j++ ] ) ) {
4388				if ( rscriptType.test( elem.type || "" ) ) {
4389					scripts.push( elem );
4390				}
4391			}
4392		}
4393	}
4394
4395	return fragment;
4396}
4397
4398
4399( function() {
4400	var fragment = document.createDocumentFragment(),
4401		div = fragment.appendChild( document.createElement( "div" ) ),
4402		input = document.createElement( "input" );
4403
4404	// Support: Android 4.0-4.3, Safari<=5.1
4405	// Check state lost if the name is set (#11217)
4406	// Support: Windows Web Apps (WWA)
4407	// `name` and `type` must use .setAttribute for WWA (#14901)
4408	input.setAttribute( "type", "radio" );
4409	input.setAttribute( "checked", "checked" );
4410	input.setAttribute( "name", "t" );
4411
4412	div.appendChild( input );
4413
4414	// Support: Safari<=5.1, Android<4.2
4415	// Older WebKit doesn't clone checked state correctly in fragments
4416	support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;
4417
4418	// Support: IE<=11+
4419	// Make sure textarea (and checkbox) defaultValue is properly cloned
4420	div.innerHTML = "<textarea>x</textarea>";
4421	support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;
4422} )();
4423
4424
4425var
4426	rkeyEvent = /^key/,
4427	rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/,
4428	rtypenamespace = /^([^.]*)(?:\.(.+)|)/;
4429
4430function returnTrue() {
4431	return true;
4432}
4433
4434function returnFalse() {
4435	return false;
4436}
4437
4438// Support: IE9
4439// See #13393 for more info
4440function safeActiveElement() {
4441	try {
4442		return document.activeElement;
4443	} catch ( err ) { }
4444}
4445
4446function on( elem, types, selector, data, fn, one ) {
4447	var origFn, type;
4448
4449	// Types can be a map of types/handlers
4450	if ( typeof types === "object" ) {
4451
4452		// ( types-Object, selector, data )
4453		if ( typeof selector !== "string" ) {
4454
4455			// ( types-Object, data )
4456			data = data || selector;
4457			selector = undefined;
4458		}
4459		for ( type in types ) {
4460			on( elem, type, selector, data, types[ type ], one );
4461		}
4462		return elem;
4463	}
4464
4465	if ( data == null && fn == null ) {
4466
4467		// ( types, fn )
4468		fn = selector;
4469		data = selector = undefined;
4470	} else if ( fn == null ) {
4471		if ( typeof selector === "string" ) {
4472
4473			// ( types, selector, fn )
4474			fn = data;
4475			data = undefined;
4476		} else {
4477
4478			// ( types, data, fn )
4479			fn = data;
4480			data = selector;
4481			selector = undefined;
4482		}
4483	}
4484	if ( fn === false ) {
4485		fn = returnFalse;
4486	} else if ( !fn ) {
4487		return elem;
4488	}
4489
4490	if ( one === 1 ) {
4491		origFn = fn;
4492		fn = function( event ) {
4493
4494			// Can use an empty set, since event contains the info
4495			jQuery().off( event );
4496			return origFn.apply( this, arguments );
4497		};
4498
4499		// Use same guid so caller can remove using origFn
4500		fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
4501	}
4502	return elem.each( function() {
4503		jQuery.event.add( this, types, fn, data, selector );
4504	} );
4505}
4506
4507/*
4508 * Helper functions for managing events -- not part of the public interface.
4509 * Props to Dean Edwards' addEvent library for many of the ideas.
4510 */
4511jQuery.event = {
4512
4513	global: {},
4514
4515	add: function( elem, types, handler, data, selector ) {
4516
4517		var handleObjIn, eventHandle, tmp,
4518			events, t, handleObj,
4519			special, handlers, type, namespaces, origType,
4520			elemData = dataPriv.get( elem );
4521
4522		// Don't attach events to noData or text/comment nodes (but allow plain objects)
4523		if ( !elemData ) {
4524			return;
4525		}
4526
4527		// Caller can pass in an object of custom data in lieu of the handler
4528		if ( handler.handler ) {
4529			handleObjIn = handler;
4530			handler = handleObjIn.handler;
4531			selector = handleObjIn.selector;
4532		}
4533
4534		// Make sure that the handler has a unique ID, used to find/remove it later
4535		if ( !handler.guid ) {
4536			handler.guid = jQuery.guid++;
4537		}
4538
4539		// Init the element's event structure and main handler, if this is the first
4540		if ( !( events = elemData.events ) ) {
4541			events = elemData.events = {};
4542		}
4543		if ( !( eventHandle = elemData.handle ) ) {
4544			eventHandle = elemData.handle = function( e ) {
4545
4546				// Discard the second event of a jQuery.event.trigger() and
4547				// when an event is called after a page has unloaded
4548				return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ?
4549					jQuery.event.dispatch.apply( elem, arguments ) : undefined;
4550			};
4551		}
4552
4553		// Handle multiple events separated by a space
4554		types = ( types || "" ).match( rnotwhite ) || [ "" ];
4555		t = types.length;
4556		while ( t-- ) {
4557			tmp = rtypenamespace.exec( types[ t ] ) || [];
4558			type = origType = tmp[ 1 ];
4559			namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();
4560
4561			// There *must* be a type, no attaching namespace-only handlers
4562			if ( !type ) {
4563				continue;
4564			}
4565
4566			// If event changes its type, use the special event handlers for the changed type
4567			special = jQuery.event.special[ type ] || {};
4568
4569			// If selector defined, determine special event api type, otherwise given type
4570			type = ( selector ? special.delegateType : special.bindType ) || type;
4571
4572			// Update special based on newly reset type
4573			special = jQuery.event.special[ type ] || {};
4574
4575			// handleObj is passed to all event handlers
4576			handleObj = jQuery.extend( {
4577				type: type,
4578				origType: origType,
4579				data: data,
4580				handler: handler,
4581				guid: handler.guid,
4582				selector: selector,
4583				needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
4584				namespace: namespaces.join( "." )
4585			}, handleObjIn );
4586
4587			// Init the event handler queue if we're the first
4588			if ( !( handlers = events[ type ] ) ) {
4589				handlers = events[ type ] = [];
4590				handlers.delegateCount = 0;
4591
4592				// Only use addEventListener if the special events handler returns false
4593				if ( !special.setup ||
4594					special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
4595
4596					if ( elem.addEventListener ) {
4597						elem.addEventListener( type, eventHandle );
4598					}
4599				}
4600			}
4601
4602			if ( special.add ) {
4603				special.add.call( elem, handleObj );
4604
4605				if ( !handleObj.handler.guid ) {
4606					handleObj.handler.guid = handler.guid;
4607				}
4608			}
4609
4610			// Add to the element's handler list, delegates in front
4611			if ( selector ) {
4612				handlers.splice( handlers.delegateCount++, 0, handleObj );
4613			} else {
4614				handlers.push( handleObj );
4615			}
4616
4617			// Keep track of which events have ever been used, for event optimization
4618			jQuery.event.global[ type ] = true;
4619		}
4620
4621	},
4622
4623	// Detach an event or set of events from an element
4624	remove: function( elem, types, handler, selector, mappedTypes ) {
4625
4626		var j, origCount, tmp,
4627			events, t, handleObj,
4628			special, handlers, type, namespaces, origType,
4629			elemData = dataPriv.hasData( elem ) && dataPriv.get( elem );
4630
4631		if ( !elemData || !( events = elemData.events ) ) {
4632			return;
4633		}
4634
4635		// Once for each type.namespace in types; type may be omitted
4636		types = ( types || "" ).match( rnotwhite ) || [ "" ];
4637		t = types.length;
4638		while ( t-- ) {
4639			tmp = rtypenamespace.exec( types[ t ] ) || [];
4640			type = origType = tmp[ 1 ];
4641			namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();
4642
4643			// Unbind all events (on this namespace, if provided) for the element
4644			if ( !type ) {
4645				for ( type in events ) {
4646					jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
4647				}
4648				continue;
4649			}
4650
4651			special = jQuery.event.special[ type ] || {};
4652			type = ( selector ? special.delegateType : special.bindType ) || type;
4653			handlers = events[ type ] || [];
4654			tmp = tmp[ 2 ] &&
4655				new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" );
4656
4657			// Remove matching events
4658			origCount = j = handlers.length;
4659			while ( j-- ) {
4660				handleObj = handlers[ j ];
4661
4662				if ( ( mappedTypes || origType === handleObj.origType ) &&
4663					( !handler || handler.guid === handleObj.guid ) &&
4664					( !tmp || tmp.test( handleObj.namespace ) ) &&
4665					( !selector || selector === handleObj.selector ||
4666						selector === "**" && handleObj.selector ) ) {
4667					handlers.splice( j, 1 );
4668
4669					if ( handleObj.selector ) {
4670						handlers.delegateCount--;
4671					}
4672					if ( special.remove ) {
4673						special.remove.call( elem, handleObj );
4674					}
4675				}
4676			}
4677
4678			// Remove generic event handler if we removed something and no more handlers exist
4679			// (avoids potential for endless recursion during removal of special event handlers)
4680			if ( origCount && !handlers.length ) {
4681				if ( !special.teardown ||
4682					special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
4683
4684					jQuery.removeEvent( elem, type, elemData.handle );
4685				}
4686
4687				delete events[ type ];
4688			}
4689		}
4690
4691		// Remove data and the expando if it's no longer used
4692		if ( jQuery.isEmptyObject( events ) ) {
4693			dataPriv.remove( elem, "handle events" );
4694		}
4695	},
4696
4697	dispatch: function( event ) {
4698
4699		// Make a writable jQuery.Event from the native event object
4700		event = jQuery.event.fix( event );
4701
4702		var i, j, ret, matched, handleObj,
4703			handlerQueue = [],
4704			args = slice.call( arguments ),
4705			handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [],
4706			special = jQuery.event.special[ event.type ] || {};
4707
4708		// Use the fix-ed jQuery.Event rather than the (read-only) native event
4709		args[ 0 ] = event;
4710		event.delegateTarget = this;
4711
4712		// Call the preDispatch hook for the mapped type, and let it bail if desired
4713		if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
4714			return;
4715		}
4716
4717		// Determine handlers
4718		handlerQueue = jQuery.event.handlers.call( this, event, handlers );
4719
4720		// Run delegates first; they may want to stop propagation beneath us
4721		i = 0;
4722		while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {
4723			event.currentTarget = matched.elem;
4724
4725			j = 0;
4726			while ( ( handleObj = matched.handlers[ j++ ] ) &&
4727				!event.isImmediatePropagationStopped() ) {
4728
4729				// Triggered event must either 1) have no namespace, or 2) have namespace(s)
4730				// a subset or equal to those in the bound event (both can have no namespace).
4731				if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) {
4732
4733					event.handleObj = handleObj;
4734					event.data = handleObj.data;
4735
4736					ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle ||
4737						handleObj.handler ).apply( matched.elem, args );
4738
4739					if ( ret !== undefined ) {
4740						if ( ( event.result = ret ) === false ) {
4741							event.preventDefault();
4742							event.stopPropagation();
4743						}
4744					}
4745				}
4746			}
4747		}
4748
4749		// Call the postDispatch hook for the mapped type
4750		if ( special.postDispatch ) {
4751			special.postDispatch.call( this, event );
4752		}
4753
4754		return event.result;
4755	},
4756
4757	handlers: function( event, handlers ) {
4758		var i, matches, sel, handleObj,
4759			handlerQueue = [],
4760			delegateCount = handlers.delegateCount,
4761			cur = event.target;
4762
4763		// Support (at least): Chrome, IE9
4764		// Find delegate handlers
4765		// Black-hole SVG <use> instance trees (#13180)
4766		//
4767		// Support: Firefox<=42+
4768		// Avoid non-left-click in FF but don't block IE radio events (#3861, gh-2343)
4769		if ( delegateCount && cur.nodeType &&
4770			( event.type !== "click" || isNaN( event.button ) || event.button < 1 ) ) {
4771
4772			for ( ; cur !== this; cur = cur.parentNode || this ) {
4773
4774				// Don't check non-elements (#13208)
4775				// Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
4776				if ( cur.nodeType === 1 && ( cur.disabled !== true || event.type !== "click" ) ) {
4777					matches = [];
4778					for ( i = 0; i < delegateCount; i++ ) {
4779						handleObj = handlers[ i ];
4780
4781						// Don't conflict with Object.prototype properties (#13203)
4782						sel = handleObj.selector + " ";
4783
4784						if ( matches[ sel ] === undefined ) {
4785							matches[ sel ] = handleObj.needsContext ?
4786								jQuery( sel, this ).index( cur ) > -1 :
4787								jQuery.find( sel, this, null, [ cur ] ).length;
4788						}
4789						if ( matches[ sel ] ) {
4790							matches.push( handleObj );
4791						}
4792					}
4793					if ( matches.length ) {
4794						handlerQueue.push( { elem: cur, handlers: matches } );
4795					}
4796				}
4797			}
4798		}
4799
4800		// Add the remaining (directly-bound) handlers
4801		if ( delegateCount < handlers.length ) {
4802			handlerQueue.push( { elem: this, handlers: handlers.slice( delegateCount ) } );
4803		}
4804
4805		return handlerQueue;
4806	},
4807
4808	// Includes some event props shared by KeyEvent and MouseEvent
4809	props: ( "altKey bubbles cancelable ctrlKey currentTarget detail eventPhase " +
4810		"metaKey relatedTarget shiftKey target timeStamp view which" ).split( " " ),
4811
4812	fixHooks: {},
4813
4814	keyHooks: {
4815		props: "char charCode key keyCode".split( " " ),
4816		filter: function( event, original ) {
4817
4818			// Add which for key events
4819			if ( event.which == null ) {
4820				event.which = original.charCode != null ? original.charCode : original.keyCode;
4821			}
4822
4823			return event;
4824		}
4825	},
4826
4827	mouseHooks: {
4828		props: ( "button buttons clientX clientY offsetX offsetY pageX pageY " +
4829			"screenX screenY toElement" ).split( " " ),
4830		filter: function( event, original ) {
4831			var eventDoc, doc, body,
4832				button = original.button;
4833
4834			// Calculate pageX/Y if missing and clientX/Y available
4835			if ( event.pageX == null && original.clientX != null ) {
4836				eventDoc = event.target.ownerDocument || document;
4837				doc = eventDoc.documentElement;
4838				body = eventDoc.body;
4839
4840				event.pageX = original.clientX +
4841					( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) -
4842					( doc && doc.clientLeft || body && body.clientLeft || 0 );
4843				event.pageY = original.clientY +
4844					( doc && doc.scrollTop  || body && body.scrollTop  || 0 ) -
4845					( doc && doc.clientTop  || body && body.clientTop  || 0 );
4846			}
4847
4848			// Add which for click: 1 === left; 2 === middle; 3 === right
4849			// Note: button is not normalized, so don't use it
4850			if ( !event.which && button !== undefined ) {
4851				event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
4852			}
4853
4854			return event;
4855		}
4856	},
4857
4858	fix: function( event ) {
4859		if ( event[ jQuery.expando ] ) {
4860			return event;
4861		}
4862
4863		// Create a writable copy of the event object and normalize some properties
4864		var i, prop, copy,
4865			type = event.type,
4866			originalEvent = event,
4867			fixHook = this.fixHooks[ type ];
4868
4869		if ( !fixHook ) {
4870			this.fixHooks[ type ] = fixHook =
4871				rmouseEvent.test( type ) ? this.mouseHooks :
4872				rkeyEvent.test( type ) ? this.keyHooks :
4873				{};
4874		}
4875		copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
4876
4877		event = new jQuery.Event( originalEvent );
4878
4879		i = copy.length;
4880		while ( i-- ) {
4881			prop = copy[ i ];
4882			event[ prop ] = originalEvent[ prop ];
4883		}
4884
4885		// Support: Cordova 2.5 (WebKit) (#13255)
4886		// All events should have a target; Cordova deviceready doesn't
4887		if ( !event.target ) {
4888			event.target = document;
4889		}
4890
4891		// Support: Safari 6.0+, Chrome<28
4892		// Target should not be a text node (#504, #13143)
4893		if ( event.target.nodeType === 3 ) {
4894			event.target = event.target.parentNode;
4895		}
4896
4897		return fixHook.filter ? fixHook.filter( event, originalEvent ) : event;
4898	},
4899
4900	special: {
4901		load: {
4902
4903			// Prevent triggered image.load events from bubbling to window.load
4904			noBubble: true
4905		},
4906		focus: {
4907
4908			// Fire native event if possible so blur/focus sequence is correct
4909			trigger: function() {
4910				if ( this !== safeActiveElement() && this.focus ) {
4911					this.focus();
4912					return false;
4913				}
4914			},
4915			delegateType: "focusin"
4916		},
4917		blur: {
4918			trigger: function() {
4919				if ( this === safeActiveElement() && this.blur ) {
4920					this.blur();
4921					return false;
4922				}
4923			},
4924			delegateType: "focusout"
4925		},
4926		click: {
4927
4928			// For checkbox, fire native event so checked state will be right
4929			trigger: function() {
4930				if ( this.type === "checkbox" && this.click && jQuery.nodeName( this, "input" ) ) {
4931					this.click();
4932					return false;
4933				}
4934			},
4935
4936			// For cross-browser consistency, don't fire native .click() on links
4937			_default: function( event ) {
4938				return jQuery.nodeName( event.target, "a" );
4939			}
4940		},
4941
4942		beforeunload: {
4943			postDispatch: function( event ) {
4944
4945				// Support: Firefox 20+
4946				// Firefox doesn't alert if the returnValue field is not set.
4947				if ( event.result !== undefined && event.originalEvent ) {
4948					event.originalEvent.returnValue = event.result;
4949				}
4950			}
4951		}
4952	}
4953};
4954
4955jQuery.removeEvent = function( elem, type, handle ) {
4956
4957	// This "if" is needed for plain objects
4958	if ( elem.removeEventListener ) {
4959		elem.removeEventListener( type, handle );
4960	}
4961};
4962
4963jQuery.Event = function( src, props ) {
4964
4965	// Allow instantiation without the 'new' keyword
4966	if ( !( this instanceof jQuery.Event ) ) {
4967		return new jQuery.Event( src, props );
4968	}
4969
4970	// Event object
4971	if ( src && src.type ) {
4972		this.originalEvent = src;
4973		this.type = src.type;
4974
4975		// Events bubbling up the document may have been marked as prevented
4976		// by a handler lower down the tree; reflect the correct value.
4977		this.isDefaultPrevented = src.defaultPrevented ||
4978				src.defaultPrevented === undefined &&
4979
4980				// Support: Android<4.0
4981				src.returnValue === false ?
4982			returnTrue :
4983			returnFalse;
4984
4985	// Event type
4986	} else {
4987		this.type = src;
4988	}
4989
4990	// Put explicitly provided properties onto the event object
4991	if ( props ) {
4992		jQuery.extend( this, props );
4993	}
4994
4995	// Create a timestamp if incoming event doesn't have one
4996	this.timeStamp = src && src.timeStamp || jQuery.now();
4997
4998	// Mark it as fixed
4999	this[ jQuery.expando ] = true;
5000};
5001
5002// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
5003// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
5004jQuery.Event.prototype = {
5005	constructor: jQuery.Event,
5006	isDefaultPrevented: returnFalse,
5007	isPropagationStopped: returnFalse,
5008	isImmediatePropagationStopped: returnFalse,
5009
5010	preventDefault: function() {
5011		var e = this.originalEvent;
5012
5013		this.isDefaultPrevented = returnTrue;
5014
5015		if ( e ) {
5016			e.preventDefault();
5017		}
5018	},
5019	stopPropagation: function() {
5020		var e = this.originalEvent;
5021
5022		this.isPropagationStopped = returnTrue;
5023
5024		if ( e ) {
5025			e.stopPropagation();
5026		}
5027	},
5028	stopImmediatePropagation: function() {
5029		var e = this.originalEvent;
5030
5031		this.isImmediatePropagationStopped = returnTrue;
5032
5033		if ( e
vendor: 24,946 bytes, lines 5033-5964
5033 ) {
5034			e.stopImmediatePropagation();
5035		}
5036
5037		this.stopPropagation();
5038	}
5039};
5040
5041// Create mouseenter/leave events using mouseover/out and event-time checks
5042// so that event delegation works in jQuery.
5043// Do the same for pointerenter/pointerleave and pointerover/pointerout
5044//
5045// Support: Safari 7 only
5046// Safari sends mouseenter too often; see:
5047// https://code.google.com/p/chromium/issues/detail?id=470258
5048// for the description of the bug (it existed in older Chrome versions as well).
5049jQuery.each( {
5050	mouseenter: "mouseover",
5051	mouseleave: "mouseout",
5052	pointerenter: "pointerover",
5053	pointerleave: "pointerout"
5054}, function( orig, fix ) {
5055	jQuery.event.special[ orig ] = {
5056		delegateType: fix,
5057		bindType: fix,
5058
5059		handle: function( event ) {
5060			var ret,
5061				target = this,
5062				related = event.relatedTarget,
5063				handleObj = event.handleObj;
5064
5065			// For mouseenter/leave call the handler if related is outside the target.
5066			// NB: No relatedTarget if the mouse left/entered the browser window
5067			if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) {
5068				event.type = handleObj.origType;
5069				ret = handleObj.handler.apply( this, arguments );
5070				event.type = fix;
5071			}
5072			return ret;
5073		}
5074	};
5075} );
5076
5077jQuery.fn.extend( {
5078	on: function( types, selector, data, fn ) {
5079		return on( this, types, selector, data, fn );
5080	},
5081	one: function( types, selector, data, fn ) {
5082		return on( this, types, selector, data, fn, 1 );
5083	},
5084	off: function( types, selector, fn ) {
5085		var handleObj, type;
5086		if ( types && types.preventDefault && types.handleObj ) {
5087
5088			// ( event )  dispatched jQuery.Event
5089			handleObj = types.handleObj;
5090			jQuery( types.delegateTarget ).off(
5091				handleObj.namespace ?
5092					handleObj.origType + "." + handleObj.namespace :
5093					handleObj.origType,
5094				handleObj.selector,
5095				handleObj.handler
5096			);
5097			return this;
5098		}
5099		if ( typeof types === "object" ) {
5100
5101			// ( types-object [, selector] )
5102			for ( type in types ) {
5103				this.off( type, selector, types[ type ] );
5104			}
5105			return this;
5106		}
5107		if ( selector === false || typeof selector === "function" ) {
5108
5109			// ( types [, fn] )
5110			fn = selector;
5111			selector = undefined;
5112		}
5113		if ( fn === false ) {
5114			fn = returnFalse;
5115		}
5116		return this.each( function() {
5117			jQuery.event.remove( this, types, fn, selector );
5118		} );
5119	}
5120} );
5121
5122
5123var
5124	rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi,
5125
5126	// Support: IE 10-11, Edge 10240+
5127	// In IE/Edge using regex groups here causes severe slowdowns.
5128	// See https://connect.microsoft.com/IE/feedback/details/1736512/
5129	rnoInnerhtml = /<script|<style|<link/i,
5130
5131	// checked="checked" or checked
5132	rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
5133	rscriptTypeMasked = /^true\/(.*)/,
5134	rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;
5135
5136// Manipulating tables requires a tbody
5137function manipulationTarget( elem, content ) {
5138	return jQuery.nodeName( elem, "table" ) &&
5139		jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ?
5140
5141		elem.getElementsByTagName( "tbody" )[ 0 ] ||
5142			elem.appendChild( elem.ownerDocument.createElement( "tbody" ) ) :
5143		elem;
5144}
5145
5146// Replace/restore the type attribute of script elements for safe DOM manipulation
5147function disableScript( elem ) {
5148	elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type;
5149	return elem;
5150}
5151function restoreScript( elem ) {
5152	var match = rscriptTypeMasked.exec( elem.type );
5153
5154	if ( match ) {
5155		elem.type = match[ 1 ];
5156	} else {
5157		elem.removeAttribute( "type" );
5158	}
5159
5160	return elem;
5161}
5162
5163function cloneCopyEvent( src, dest ) {
5164	var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;
5165
5166	if ( dest.nodeType !== 1 ) {
5167		return;
5168	}
5169
5170	// 1. Copy private data: events, handlers, etc.
5171	if ( dataPriv.hasData( src ) ) {
5172		pdataOld = dataPriv.access( src );
5173		pdataCur = dataPriv.set( dest, pdataOld );
5174		events = pdataOld.events;
5175
5176		if ( events ) {
5177			delete pdataCur.handle;
5178			pdataCur.events = {};
5179
5180			for ( type in events ) {
5181				for ( i = 0, l = events[ type ].length; i < l; i++ ) {
5182					jQuery.event.add( dest, type, events[ type ][ i ] );
5183				}
5184			}
5185		}
5186	}
5187
5188	// 2. Copy user data
5189	if ( dataUser.hasData( src ) ) {
5190		udataOld = dataUser.access( src );
5191		udataCur = jQuery.extend( {}, udataOld );
5192
5193		dataUser.set( dest, udataCur );
5194	}
5195}
5196
5197// Fix IE bugs, see support tests
5198function fixInput( src, dest ) {
5199	var nodeName = dest.nodeName.toLowerCase();
5200
5201	// Fails to persist the checked state of a cloned checkbox or radio button.
5202	if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
5203		dest.checked = src.checked;
5204
5205	// Fails to return the selected option to the default selected state when cloning options
5206	} else if ( nodeName === "input" || nodeName === "textarea" ) {
5207		dest.defaultValue = src.defaultValue;
5208	}
5209}
5210
5211function domManip( collection, args, callback, ignored ) {
5212
5213	// Flatten any nested arrays
5214	args = concat.apply( [], args );
5215
5216	var fragment, first, scripts, hasScripts, node, doc,
5217		i = 0,
5218		l = collection.length,
5219		iNoClone = l - 1,
5220		value = args[ 0 ],
5221		isFunction = jQuery.isFunction( value );
5222
5223	// We can't cloneNode fragments that contain checked, in WebKit
5224	if ( isFunction ||
5225			( l > 1 && typeof value === "string" &&
5226				!support.checkClone && rchecked.test( value ) ) ) {
5227		return collection.each( function( index ) {
5228			var self = collection.eq( index );
5229			if ( isFunction ) {
5230				args[ 0 ] = value.call( this, index, self.html() );
5231			}
5232			domManip( self, args, callback, ignored );
5233		} );
5234	}
5235
5236	if ( l ) {
5237		fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored );
5238		first = fragment.firstChild;
5239
5240		if ( fragment.childNodes.length === 1 ) {
5241			fragment = first;
5242		}
5243
5244		// Require either new content or an interest in ignored elements to invoke the callback
5245		if ( first || ignored ) {
5246			scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
5247			hasScripts = scripts.length;
5248
5249			// Use the original fragment for the last item
5250			// instead of the first because it can end up
5251			// being emptied incorrectly in certain situations (#8070).
5252			for ( ; i < l; i++ ) {
5253				node = fragment;
5254
5255				if ( i !== iNoClone ) {
5256					node = jQuery.clone( node, true, true );
5257
5258					// Keep references to cloned scripts for later restoration
5259					if ( hasScripts ) {
5260
5261						// Support: Android<4.1, PhantomJS<2
5262						// push.apply(_, arraylike) throws on ancient WebKit
5263						jQuery.merge( scripts, getAll( node, "script" ) );
5264					}
5265				}
5266
5267				callback.call( collection[ i ], node, i );
5268			}
5269
5270			if ( hasScripts ) {
5271				doc = scripts[ scripts.length - 1 ].ownerDocument;
5272
5273				// Reenable scripts
5274				jQuery.map( scripts, restoreScript );
5275
5276				// Evaluate executable scripts on first document insertion
5277				for ( i = 0; i < hasScripts; i++ ) {
5278					node = scripts[ i ];
5279					if ( rscriptType.test( node.type || "" ) &&
5280						!dataPriv.access( node, "globalEval" ) &&
5281						jQuery.contains( doc, node ) ) {
5282
5283						if ( node.src ) {
5284
5285							// Optional AJAX dependency, but won't run scripts if not present
5286							if ( jQuery._evalUrl ) {
5287								jQuery._evalUrl( node.src );
5288							}
5289						} else {
5290							jQuery.globalEval( node.textContent.replace( rcleanScript, "" ) );
5291						}
5292					}
5293				}
5294			}
5295		}
5296	}
5297
5298	return collection;
5299}
5300
5301function remove( elem, selector, keepData ) {
5302	var node,
5303		nodes = selector ? jQuery.filter( selector, elem ) : elem,
5304		i = 0;
5305
5306	for ( ; ( node = nodes[ i ] ) != null; i++ ) {
5307		if ( !keepData && node.nodeType === 1 ) {
5308			jQuery.cleanData( getAll( node ) );
5309		}
5310
5311		if ( node.parentNode ) {
5312			if ( keepData && jQuery.contains( node.ownerDocument, node ) ) {
5313				setGlobalEval( getAll( node, "script" ) );
5314			}
5315			node.parentNode.removeChild( node );
5316		}
5317	}
5318
5319	return elem;
5320}
5321
5322jQuery.extend( {
5323	htmlPrefilter: function( html ) {
5324		return html.replace( rxhtmlTag, "<$1></$2>" );
5325	},
5326
5327	clone: function( elem, dataAndEvents, deepDataAndEvents ) {
5328		var i, l, srcElements, destElements,
5329			clone = elem.cloneNode( true ),
5330			inPage = jQuery.contains( elem.ownerDocument, elem );
5331
5332		// Fix IE cloning issues
5333		if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&
5334				!jQuery.isXMLDoc( elem ) ) {
5335
5336			// We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2
5337			destElements = getAll( clone );
5338			srcElements = getAll( elem );
5339
5340			for ( i = 0, l = srcElements.length; i < l; i++ ) {
5341				fixInput( srcElements[ i ], destElements[ i ] );
5342			}
5343		}
5344
5345		// Copy the events from the original to the clone
5346		if ( dataAndEvents ) {
5347			if ( deepDataAndEvents ) {
5348				srcElements = srcElements || getAll( elem );
5349				destElements = destElements || getAll( clone );
5350
5351				for ( i = 0, l = srcElements.length; i < l; i++ ) {
5352					cloneCopyEvent( srcElements[ i ], destElements[ i ] );
5353				}
5354			} else {
5355				cloneCopyEvent( elem, clone );
5356			}
5357		}
5358
5359		// Preserve script evaluation history
5360		destElements = getAll( clone, "script" );
5361		if ( destElements.length > 0 ) {
5362			setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
5363		}
5364
5365		// Return the cloned set
5366		return clone;
5367	},
5368
5369	cleanData: function( elems ) {
5370		var data, elem, type,
5371			special = jQuery.event.special,
5372			i = 0;
5373
5374		for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) {
5375			if ( acceptData( elem ) ) {
5376				if ( ( data = elem[ dataPriv.expando ] ) ) {
5377					if ( data.events ) {
5378						for ( type in data.events ) {
5379							if ( special[ type ] ) {
5380								jQuery.event.remove( elem, type );
5381
5382							// This is a shortcut to avoid jQuery.event.remove's overhead
5383							} else {
5384								jQuery.removeEvent( elem, type, data.handle );
5385							}
5386						}
5387					}
5388
5389					// Support: Chrome <= 35-45+
5390					// Assign undefined instead of using delete, see Data#remove
5391					elem[ dataPriv.expando ] = undefined;
5392				}
5393				if ( elem[ dataUser.expando ] ) {
5394
5395					// Support: Chrome <= 35-45+
5396					// Assign undefined instead of using delete, see Data#remove
5397					elem[ dataUser.expando ] = undefined;
5398				}
5399			}
5400		}
5401	}
5402} );
5403
5404jQuery.fn.extend( {
5405
5406	// Keep domManip exposed until 3.0 (gh-2225)
5407	domManip: domManip,
5408
5409	detach: function( selector ) {
5410		return remove( this, selector, true );
5411	},
5412
5413	remove: function( selector ) {
5414		return remove( this, selector );
5415	},
5416
5417	text: function( value ) {
5418		return access( this, function( value ) {
5419			return value === undefined ?
5420				jQuery.text( this ) :
5421				this.empty().each( function() {
5422					if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
5423						this.textContent = value;
5424					}
5425				} );
5426		}, null, value, arguments.length );
5427	},
5428
5429	append: function() {
5430		return domManip( this, arguments, function( elem ) {
5431			if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
5432				var target = manipulationTarget( this, elem );
5433				target.appendChild( elem );
5434			}
5435		} );
5436	},
5437
5438	prepend: function() {
5439		return domManip( this, arguments, function( elem ) {
5440			if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
5441				var target = manipulationTarget( this, elem );
5442				target.insertBefore( elem, target.firstChild );
5443			}
5444		} );
5445	},
5446
5447	before: function() {
5448		return domManip( this, arguments, function( elem ) {
5449			if ( this.parentNode ) {
5450				this.parentNode.insertBefore( elem, this );
5451			}
5452		} );
5453	},
5454
5455	after: function() {
5456		return domManip( this, arguments, function( elem ) {
5457			if ( this.parentNode ) {
5458				this.parentNode.insertBefore( elem, this.nextSibling );
5459			}
5460		} );
5461	},
5462
5463	empty: function() {
5464		var elem,
5465			i = 0;
5466
5467		for ( ; ( elem = this[ i ] ) != null; i++ ) {
5468			if ( elem.nodeType === 1 ) {
5469
5470				// Prevent memory leaks
5471				jQuery.cleanData( getAll( elem, false ) );
5472
5473				// Remove any remaining nodes
5474				elem.textContent = "";
5475			}
5476		}
5477
5478		return this;
5479	},
5480
5481	clone: function( dataAndEvents, deepDataAndEvents ) {
5482		dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
5483		deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
5484
5485		return this.map( function() {
5486			return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
5487		} );
5488	},
5489
5490	html: function( value ) {
5491		return access( this, function( value ) {
5492			var elem = this[ 0 ] || {},
5493				i = 0,
5494				l = this.length;
5495
5496			if ( value === undefined && elem.nodeType === 1 ) {
5497				return elem.innerHTML;
5498			}
5499
5500			// See if we can take a shortcut and just use innerHTML
5501			if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
5502				!wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) {
5503
5504				value = jQuery.htmlPrefilter( value );
5505
5506				try {
5507					for ( ; i < l; i++ ) {
5508						elem = this[ i ] || {};
5509
5510						// Remove element nodes and prevent memory leaks
5511						if ( elem.nodeType === 1 ) {
5512							jQuery.cleanData( getAll( elem, false ) );
5513							elem.innerHTML = value;
5514						}
5515					}
5516
5517					elem = 0;
5518
5519				// If using innerHTML throws an exception, use the fallback method
5520				} catch ( e ) {}
5521			}
5522
5523			if ( elem ) {
5524				this.empty().append( value );
5525			}
5526		}, null, value, arguments.length );
5527	},
5528
5529	replaceWith: function() {
5530		var ignored = [];
5531
5532		// Make the changes, replacing each non-ignored context element with the new content
5533		return domManip( this, arguments, function( elem ) {
5534			var parent = this.parentNode;
5535
5536			if ( jQuery.inArray( this, ignored ) < 0 ) {
5537				jQuery.cleanData( getAll( this ) );
5538				if ( parent ) {
5539					parent.replaceChild( elem, this );
5540				}
5541			}
5542
5543		// Force callback invocation
5544		}, ignored );
5545	}
5546} );
5547
5548jQuery.each( {
5549	appendTo: "append",
5550	prependTo: "prepend",
5551	insertBefore: "before",
5552	insertAfter: "after",
5553	replaceAll: "replaceWith"
5554}, function( name, original ) {
5555	jQuery.fn[ name ] = function( selector ) {
5556		var elems,
5557			ret = [],
5558			insert = jQuery( selector ),
5559			last = insert.length - 1,
5560			i = 0;
5561
5562		for ( ; i <= last; i++ ) {
5563			elems = i === last ? this : this.clone( true );
5564			jQuery( insert[ i ] )[ original ]( elems );
5565
5566			// Support: QtWebKit
5567			// .get() because push.apply(_, arraylike) throws
5568			push.apply( ret, elems.get() );
5569		}
5570
5571		return this.pushStack( ret );
5572	};
5573} );
5574
5575
5576var iframe,
5577	elemdisplay = {
5578
5579		// Support: Firefox
5580		// We have to pre-define these values for FF (#10227)
5581		HTML: "block",
5582		BODY: "block"
5583	};
5584
5585/**
5586 * Retrieve the actual display of a element
5587 * @param {String} name nodeName of the element
5588 * @param {Object} doc Document object
5589 */
5590
5591// Called only from within defaultDisplay
5592function actualDisplay( name, doc ) {
5593	var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),
5594
5595		display = jQuery.css( elem[ 0 ], "display" );
5596
5597	// We don't have any data stored on the element,
5598	// so use "detach" method as fast way to get rid of the element
5599	elem.detach();
5600
5601	return display;
5602}
5603
5604/**
5605 * Try to determine the default display value of an element
5606 * @param {String} nodeName
5607 */
5608function defaultDisplay( nodeName ) {
5609	var doc = document,
5610		display = elemdisplay[ nodeName ];
5611
5612	if ( !display ) {
5613		display = actualDisplay( nodeName, doc );
5614
5615		// If the simple way fails, read from inside an iframe
5616		if ( display === "none" || !display ) {
5617
5618			// Use the already-created iframe if possible
5619			iframe = ( iframe || jQuery( "<iframe frameborder='0' width='0' height='0'/>" ) )
5620				.appendTo( doc.documentElement );
5621
5622			// Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse
5623			doc = iframe[ 0 ].contentDocument;
5624
5625			// Support: IE
5626			doc.write();
5627			doc.close();
5628
5629			display = actualDisplay( nodeName, doc );
5630			iframe.detach();
5631		}
5632
5633		// Store the correct default display
5634		elemdisplay[ nodeName ] = display;
5635	}
5636
5637	return display;
5638}
5639var rmargin = ( /^margin/ );
5640
5641var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" );
5642
5643var getStyles = function( elem ) {
5644
5645		// Support: IE<=11+, Firefox<=30+ (#15098, #14150)
5646		// IE throws on elements created in popups
5647		// FF meanwhile throws on frame elements through "defaultView.getComputedStyle"
5648		var view = elem.ownerDocument.defaultView;
5649
5650		if ( !view || !view.opener ) {
5651			view = window;
5652		}
5653
5654		return view.getComputedStyle( elem );
5655	};
5656
5657var swap = function( elem, options, callback, args ) {
5658	var ret, name,
5659		old = {};
5660
5661	// Remember the old values, and insert the new ones
5662	for ( name in options ) {
5663		old[ name ] = elem.style[ name ];
5664		elem.style[ name ] = options[ name ];
5665	}
5666
5667	ret = callback.apply( elem, args || [] );
5668
5669	// Revert the old values
5670	for ( name in options ) {
5671		elem.style[ name ] = old[ name ];
5672	}
5673
5674	return ret;
5675};
5676
5677
5678var documentElement = document.documentElement;
5679
5680
5681
5682( function() {
5683	var pixelPositionVal, boxSizingReliableVal, pixelMarginRightVal, reliableMarginLeftVal,
5684		container = document.createElement( "div" ),
5685		div = document.createElement( "div" );
5686
5687	// Finish early in limited (non-browser) environments
5688	if ( !div.style ) {
5689		return;
5690	}
5691
5692	// Support: IE9-11+
5693	// Style of cloned element affects source element cloned (#8908)
5694	div.style.backgroundClip = "content-box";
5695	div.cloneNode( true ).style.backgroundClip = "";
5696	support.clearCloneStyle = div.style.backgroundClip === "content-box";
5697
5698	container.style.cssText = "border:0;width:8px;height:0;top:0;left:-9999px;" +
5699		"padding:0;margin-top:1px;position:absolute";
5700	container.appendChild( div );
5701
5702	// Executing both pixelPosition & boxSizingReliable tests require only one layout
5703	// so they're executed at the same time to save the second computation.
5704	function computeStyleTests() {
5705		div.style.cssText =
5706
5707			// Support: Firefox<29, Android 2.3
5708			// Vendor-prefix box-sizing
5709			"-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;" +
5710			"position:relative;display:block;" +
5711			"margin:auto;border:1px;padding:1px;" +
5712			"top:1%;width:50%";
5713		div.innerHTML = "";
5714		documentElement.appendChild( container );
5715
5716		var divStyle = window.getComputedStyle( div );
5717		pixelPositionVal = divStyle.top !== "1%";
5718		reliableMarginLeftVal = divStyle.marginLeft === "2px";
5719		boxSizingReliableVal = divStyle.width === "4px";
5720
5721		// Support: Android 4.0 - 4.3 only
5722		// Some styles come back with percentage values, even though they shouldn't
5723		div.style.marginRight = "50%";
5724		pixelMarginRightVal = divStyle.marginRight === "4px";
5725
5726		documentElement.removeChild( container );
5727	}
5728
5729	jQuery.extend( support, {
5730		pixelPosition: function() {
5731
5732			// This test is executed only once but we still do memoizing
5733			// since we can use the boxSizingReliable pre-computing.
5734			// No need to check if the test was already performed, though.
5735			computeStyleTests();
5736			return pixelPositionVal;
5737		},
5738		boxSizingReliable: function() {
5739			if ( boxSizingReliableVal == null ) {
5740				computeStyleTests();
5741			}
5742			return boxSizingReliableVal;
5743		},
5744		pixelMarginRight: function() {
5745
5746			// Support: Android 4.0-4.3
5747			// We're checking for boxSizingReliableVal here instead of pixelMarginRightVal
5748			// since that compresses better and they're computed together anyway.
5749			if ( boxSizingReliableVal == null ) {
5750				computeStyleTests();
5751			}
5752			return pixelMarginRightVal;
5753		},
5754		reliableMarginLeft: function() {
5755
5756			// Support: IE <=8 only, Android 4.0 - 4.3 only, Firefox <=3 - 37
5757			if ( boxSizingReliableVal == null ) {
5758				computeStyleTests();
5759			}
5760			return reliableMarginLeftVal;
5761		},
5762		reliableMarginRight: function() {
5763
5764			// Support: Android 2.3
5765			// Check if div with explicit width and no margin-right incorrectly
5766			// gets computed margin-right based on width of container. (#3333)
5767			// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
5768			// This support function is only executed once so no memoizing is needed.
5769			var ret,
5770				marginDiv = div.appendChild( document.createElement( "div" ) );
5771
5772			// Reset CSS: box-sizing; display; margin; border; padding
5773			marginDiv.style.cssText = div.style.cssText =
5774
5775				// Support: Android 2.3
5776				// Vendor-prefix box-sizing
5777				"-webkit-box-sizing:content-box;box-sizing:content-box;" +
5778				"display:block;margin:0;border:0;padding:0";
5779			marginDiv.style.marginRight = marginDiv.style.width = "0";
5780			div.style.width = "1px";
5781			documentElement.appendChild( container );
5782
5783			ret = !parseFloat( window.getComputedStyle( marginDiv ).marginRight );
5784
5785			documentElement.removeChild( container );
5786			div.removeChild( marginDiv );
5787
5788			return ret;
5789		}
5790	} );
5791} )();
5792
5793
5794function curCSS( elem, name, computed ) {
5795	var width, minWidth, maxWidth, ret,
5796		style = elem.style;
5797
5798	computed = computed || getStyles( elem );
5799	ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined;
5800
5801	// Support: Opera 12.1x only
5802	// Fall back to style even without computed
5803	// computed is undefined for elems on document fragments
5804	if ( ( ret === "" || ret === undefined ) && !jQuery.contains( elem.ownerDocument, elem ) ) {
5805		ret = jQuery.style( elem, name );
5806	}
5807
5808	// Support: IE9
5809	// getPropertyValue is only needed for .css('filter') (#12537)
5810	if ( computed ) {
5811
5812		// A tribute to the "awesome hack by Dean Edwards"
5813		// Android Browser returns percentage for some values,
5814		// but width seems to be reliably pixels.
5815		// This is against the CSSOM draft spec:
5816		// http://dev.w3.org/csswg/cssom/#resolved-values
5817		if ( !support.pixelMarginRight() && rnumnonpx.test( ret ) && rmargin.test( name ) ) {
5818
5819			// Remember the original values
5820			width = style.width;
5821			minWidth = style.minWidth;
5822			maxWidth = style.maxWidth;
5823
5824			// Put in the new values to get a computed value out
5825			style.minWidth = style.maxWidth = style.width = ret;
5826			ret = computed.width;
5827
5828			// Revert the changed values
5829			style.width = width;
5830			style.minWidth = minWidth;
5831			style.maxWidth = maxWidth;
5832		}
5833	}
5834
5835	return ret !== undefined ?
5836
5837		// Support: IE9-11+
5838		// IE returns zIndex value as an integer.
5839		ret + "" :
5840		ret;
5841}
5842
5843
5844function addGetHookIf( conditionFn, hookFn ) {
5845
5846	// Define the hook, we'll check on the first run if it's really needed.
5847	return {
5848		get: function() {
5849			if ( conditionFn() ) {
5850
5851				// Hook not needed (or it's not possible to use it due
5852				// to missing dependency), remove it.
5853				delete this.get;
5854				return;
5855			}
5856
5857			// Hook needed; redefine it so that the support test is not executed again.
5858			return ( this.get = hookFn ).apply( this, arguments );
5859		}
5860	};
5861}
5862
5863
5864var
5865
5866	// Swappable if display is none or starts with table
5867	// except "table", "table-cell", or "table-caption"
5868	// See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
5869	rdisplayswap = /^(none|table(?!-c[ea]).+)/,
5870
5871	cssShow = { position: "absolute", visibility: "hidden", display: "block" },
5872	cssNormalTransform = {
5873		letterSpacing: "0",
5874		fontWeight: "400"
5875	},
5876
5877	cssPrefixes = [ "Webkit", "O", "Moz", "ms" ],
5878	emptyStyle = document.createElement( "div" ).style;
5879
5880// Return a css property mapped to a potentially vendor prefixed property
5881function vendorPropName( name ) {
5882
5883	// Shortcut for names that are not vendor prefixed
5884	if ( name in emptyStyle ) {
5885		return name;
5886	}
5887
5888	// Check for vendor prefixed names
5889	var capName = name[ 0 ].toUpperCase() + name.slice( 1 ),
5890		i = cssPrefixes.length;
5891
5892	while ( i-- ) {
5893		name = cssPrefixes[ i ] + capName;
5894		if ( name in emptyStyle ) {
5895			return name;
5896		}
5897	}
5898}
5899
5900function setPositiveNumber( elem, value, subtract ) {
5901
5902	// Any relative (+/-) values have already been
5903	// normalized at this point
5904	var matches = rcssNum.exec( value );
5905	return matches ?
5906
5907		// Guard against undefined "subtract", e.g., when used as in cssHooks
5908		Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) :
5909		value;
5910}
5911
5912function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
5913	var i = extra === ( isBorderBox ? "border" : "content" ) ?
5914
5915		// If we already have the right measurement, avoid augmentation
5916		4 :
5917
5918		// Otherwise initialize for horizontal or vertical properties
5919		name === "width" ? 1 : 0,
5920
5921		val = 0;
5922
5923	for ( ; i < 4; i += 2 ) {
5924
5925		// Both box models exclude margin, so add it if we want it
5926		if ( extra === "margin" ) {
5927			val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
5928		}
5929
5930		if ( isBorderBox ) {
5931
5932			// border-box includes padding, so remove it if we want content
5933			if ( extra === "content" ) {
5934				val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
5935			}
5936
5937			// At this point, extra isn't border nor margin, so remove border
5938			if ( extra !== "margin" ) {
5939				val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
5940			}
5941		} else {
5942
5943			// At this point, extra isn't content, so add padding
5944			val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
5945
5946			// At this point, extra isn't content nor padding, so add border
5947			if ( extra !== "padding" ) {
5948				val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
5949			}
5950		}
5951	}
5952
5953	return val;
5954}
5955
5956function getWidthOrHeight( elem, name, extra ) {
5957
5958	// Start with offset property, which is equivalent to the border-box value
5959	var valueIsBorderBox = true,
5960		val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
5961		styles = getStyles( elem ),
5962		isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
5963
5964	// S
5964upport: IE11 only
5965	// In IE 11 fullscreen elements inside of an iframe have
5966	// 100x too small dimensions (gh-1764).
5967	if ( document.msFullscreenElement && window.top !== window ) {
5968
5969		// Support: IE11 only
5970		// Running getBoundingClientRect on a disconnected node
5971		// in IE throws an error.
5972		if ( elem.getClientRects().length ) {
5973			val = Math.round( elem.getBoundingClientRect()[ name ] * 100 );
5974		}
5975	}
vendor: 47,683 bytes, lines 5975-7867
5975
5976
5977	// Some non-html elements return undefined for offsetWidth, so check for null/undefined
5978	// svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
5979	// MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
5980	if ( val <= 0 || val == null ) {
5981
5982		// Fall back to computed then uncomputed css if necessary
5983		val = curCSS( elem, name, styles );
5984		if ( val < 0 || val == null ) {
5985			val = elem.style[ name ];
5986		}
5987
5988		// Computed unit is not pixels. Stop here and return.
5989		if ( rnumnonpx.test( val ) ) {
5990			return val;
5991		}
5992
5993		// Check for style in case a browser which returns unreliable values
5994		// for getComputedStyle silently falls back to the reliable elem.style
5995		valueIsBorderBox = isBorderBox &&
5996			( support.boxSizingReliable() || val === elem.style[ name ] );
5997
5998		// Normalize "", auto, and prepare for extra
5999		val = parseFloat( val ) || 0;
6000	}
6001
6002	// Use the active box-sizing model to add/subtract irrelevant styles
6003	return ( val +
6004		augmentWidthOrHeight(
6005			elem,
6006			name,
6007			extra || ( isBorderBox ? "border" : "content" ),
6008			valueIsBorderBox,
6009			styles
6010		)
6011	) + "px";
6012}
6013
6014function showHide( elements, show ) {
6015	var display, elem, hidden,
6016		values = [],
6017		index = 0,
6018		length = elements.length;
6019
6020	for ( ; index < length; index++ ) {
6021		elem = elements[ index ];
6022		if ( !elem.style ) {
6023			continue;
6024		}
6025
6026		values[ index ] = dataPriv.get( elem, "olddisplay" );
6027		display = elem.style.display;
6028		if ( show ) {
6029
6030			// Reset the inline display of this element to learn if it is
6031			// being hidden by cascaded rules or not
6032			if ( !values[ index ] && display === "none" ) {
6033				elem.style.display = "";
6034			}
6035
6036			// Set elements which have been overridden with display: none
6037			// in a stylesheet to whatever the default browser style is
6038			// for such an element
6039			if ( elem.style.display === "" && isHidden( elem ) ) {
6040				values[ index ] = dataPriv.access(
6041					elem,
6042					"olddisplay",
6043					defaultDisplay( elem.nodeName )
6044				);
6045			}
6046		} else {
6047			hidden = isHidden( elem );
6048
6049			if ( display !== "none" || !hidden ) {
6050				dataPriv.set(
6051					elem,
6052					"olddisplay",
6053					hidden ? display : jQuery.css( elem, "display" )
6054				);
6055			}
6056		}
6057	}
6058
6059	// Set the display of most of the elements in a second loop
6060	// to avoid the constant reflow
6061	for ( index = 0; index < length; index++ ) {
6062		elem = elements[ index ];
6063		if ( !elem.style ) {
6064			continue;
6065		}
6066		if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
6067			elem.style.display = show ? values[ index ] || "" : "none";
6068		}
6069	}
6070
6071	return elements;
6072}
6073
6074jQuery.extend( {
6075
6076	// Add in style property hooks for overriding the default
6077	// behavior of getting and setting a style property
6078	cssHooks: {
6079		opacity: {
6080			get: function( elem, computed ) {
6081				if ( computed ) {
6082
6083					// We should always get a number back from opacity
6084					var ret = curCSS( elem, "opacity" );
6085					return ret === "" ? "1" : ret;
6086				}
6087			}
6088		}
6089	},
6090
6091	// Don't automatically add "px" to these possibly-unitless properties
6092	cssNumber: {
6093		"animationIterationCount": true,
6094		"columnCount": true,
6095		"fillOpacity": true,
6096		"flexGrow": true,
6097		"flexShrink": true,
6098		"fontWeight": true,
6099		"lineHeight": true,
6100		"opacity": true,
6101		"order": true,
6102		"orphans": true,
6103		"widows": true,
6104		"zIndex": true,
6105		"zoom": true
6106	},
6107
6108	// Add in properties whose names you wish to fix before
6109	// setting or getting the value
6110	cssProps: {
6111		"float": "cssFloat"
6112	},
6113
6114	// Get and set the style property on a DOM Node
6115	style: function( elem, name, value, extra ) {
6116
6117		// Don't set styles on text and comment nodes
6118		if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
6119			return;
6120		}
6121
6122		// Make sure that we're working with the right name
6123		var ret, type, hooks,
6124			origName = jQuery.camelCase( name ),
6125			style = elem.style;
6126
6127		name = jQuery.cssProps[ origName ] ||
6128			( jQuery.cssProps[ origName ] = vendorPropName( origName ) || origName );
6129
6130		// Gets hook for the prefixed version, then unprefixed version
6131		hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
6132
6133		// Check if we're setting a value
6134		if ( value !== undefined ) {
6135			type = typeof value;
6136
6137			// Convert "+=" or "-=" to relative numbers (#7345)
6138			if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) {
6139				value = adjustCSS( elem, name, ret );
6140
6141				// Fixes bug #9237
6142				type = "number";
6143			}
6144
6145			// Make sure that null and NaN values aren't set (#7116)
6146			if ( value == null || value !== value ) {
6147				return;
6148			}
6149
6150			// If a number was passed in, add the unit (except for certain CSS properties)
6151			if ( type === "number" ) {
6152				value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" );
6153			}
6154
6155			// Support: IE9-11+
6156			// background-* props affect original clone's values
6157			if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) {
6158				style[ name ] = "inherit";
6159			}
6160
6161			// If a hook was provided, use that value, otherwise just set the specified value
6162			if ( !hooks || !( "set" in hooks ) ||
6163				( value = hooks.set( elem, value, extra ) ) !== undefined ) {
6164
6165				style[ name ] = value;
6166			}
6167
6168		} else {
6169
6170			// If a hook was provided get the non-computed value from there
6171			if ( hooks && "get" in hooks &&
6172				( ret = hooks.get( elem, false, extra ) ) !== undefined ) {
6173
6174				return ret;
6175			}
6176
6177			// Otherwise just get the value from the style object
6178			return style[ name ];
6179		}
6180	},
6181
6182	css: function( elem, name, extra, styles ) {
6183		var val, num, hooks,
6184			origName = jQuery.camelCase( name );
6185
6186		// Make sure that we're working with the right name
6187		name = jQuery.cssProps[ origName ] ||
6188			( jQuery.cssProps[ origName ] = vendorPropName( origName ) || origName );
6189
6190		// Try prefixed name followed by the unprefixed name
6191		hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
6192
6193		// If a hook was provided get the computed value from there
6194		if ( hooks && "get" in hooks ) {
6195			val = hooks.get( elem, true, extra );
6196		}
6197
6198		// Otherwise, if a way to get the computed value exists, use that
6199		if ( val === undefined ) {
6200			val = curCSS( elem, name, styles );
6201		}
6202
6203		// Convert "normal" to computed value
6204		if ( val === "normal" && name in cssNormalTransform ) {
6205			val = cssNormalTransform[ name ];
6206		}
6207
6208		// Make numeric if forced or a qualifier was provided and val looks numeric
6209		if ( extra === "" || extra ) {
6210			num = parseFloat( val );
6211			return extra === true || isFinite( num ) ? num || 0 : val;
6212		}
6213		return val;
6214	}
6215} );
6216
6217jQuery.each( [ "height", "width" ], function( i, name ) {
6218	jQuery.cssHooks[ name ] = {
6219		get: function( elem, computed, extra ) {
6220			if ( computed ) {
6221
6222				// Certain elements can have dimension info if we invisibly show them
6223				// but it must have a current display style that would benefit
6224				return rdisplayswap.test( jQuery.css( elem, "display" ) ) &&
6225					elem.offsetWidth === 0 ?
6226						swap( elem, cssShow, function() {
6227							return getWidthOrHeight( elem, name, extra );
6228						} ) :
6229						getWidthOrHeight( elem, name, extra );
6230			}
6231		},
6232
6233		set: function( elem, value, extra ) {
6234			var matches,
6235				styles = extra && getStyles( elem ),
6236				subtract = extra && augmentWidthOrHeight(
6237					elem,
6238					name,
6239					extra,
6240					jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
6241					styles
6242				);
6243
6244			// Convert to pixels if value adjustment is needed
6245			if ( subtract && ( matches = rcssNum.exec( value ) ) &&
6246				( matches[ 3 ] || "px" ) !== "px" ) {
6247
6248				elem.style[ name ] = value;
6249				value = jQuery.css( elem, name );
6250			}
6251
6252			return setPositiveNumber( elem, value, subtract );
6253		}
6254	};
6255} );
6256
6257jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft,
6258	function( elem, computed ) {
6259		if ( computed ) {
6260			return ( parseFloat( curCSS( elem, "marginLeft" ) ) ||
6261				elem.getBoundingClientRect().left -
6262					swap( elem, { marginLeft: 0 }, function() {
6263						return elem.getBoundingClientRect().left;
6264					} )
6265				) + "px";
6266		}
6267	}
6268);
6269
6270// Support: Android 2.3
6271jQuery.cssHooks.marginRight = addGetHookIf( support.reliableMarginRight,
6272	function( elem, computed ) {
6273		if ( computed ) {
6274			return swap( elem, { "display": "inline-block" },
6275				curCSS, [ elem, "marginRight" ] );
6276		}
6277	}
6278);
6279
6280// These hooks are used by animate to expand properties
6281jQuery.each( {
6282	margin: "",
6283	padding: "",
6284	border: "Width"
6285}, function( prefix, suffix ) {
6286	jQuery.cssHooks[ prefix + suffix ] = {
6287		expand: function( value ) {
6288			var i = 0,
6289				expanded = {},
6290
6291				// Assumes a single number if not a string
6292				parts = typeof value === "string" ? value.split( " " ) : [ value ];
6293
6294			for ( ; i < 4; i++ ) {
6295				expanded[ prefix + cssExpand[ i ] + suffix ] =
6296					parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
6297			}
6298
6299			return expanded;
6300		}
6301	};
6302
6303	if ( !rmargin.test( prefix ) ) {
6304		jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
6305	}
6306} );
6307
6308jQuery.fn.extend( {
6309	css: function( name, value ) {
6310		return access( this, function( elem, name, value ) {
6311			var styles, len,
6312				map = {},
6313				i = 0;
6314
6315			if ( jQuery.isArray( name ) ) {
6316				styles = getStyles( elem );
6317				len = name.length;
6318
6319				for ( ; i < len; i++ ) {
6320					map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
6321				}
6322
6323				return map;
6324			}
6325
6326			return value !== undefined ?
6327				jQuery.style( elem, name, value ) :
6328				jQuery.css( elem, name );
6329		}, name, value, arguments.length > 1 );
6330	},
6331	show: function() {
6332		return showHide( this, true );
6333	},
6334	hide: function() {
6335		return showHide( this );
6336	},
6337	toggle: function( state ) {
6338		if ( typeof state === "boolean" ) {
6339			return state ? this.show() : this.hide();
6340		}
6341
6342		return this.each( function() {
6343			if ( isHidden( this ) ) {
6344				jQuery( this ).show();
6345			} else {
6346				jQuery( this ).hide();
6347			}
6348		} );
6349	}
6350} );
6351
6352
6353function Tween( elem, options, prop, end, easing ) {
6354	return new Tween.prototype.init( elem, options, prop, end, easing );
6355}
6356jQuery.Tween = Tween;
6357
6358Tween.prototype = {
6359	constructor: Tween,
6360	init: function( elem, options, prop, end, easing, unit ) {
6361		this.elem = elem;
6362		this.prop = prop;
6363		this.easing = easing || jQuery.easing._default;
6364		this.options = options;
6365		this.start = this.now = this.cur();
6366		this.end = end;
6367		this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
6368	},
6369	cur: function() {
6370		var hooks = Tween.propHooks[ this.prop ];
6371
6372		return hooks && hooks.get ?
6373			hooks.get( this ) :
6374			Tween.propHooks._default.get( this );
6375	},
6376	run: function( percent ) {
6377		var eased,
6378			hooks = Tween.propHooks[ this.prop ];
6379
6380		if ( this.options.duration ) {
6381			this.pos = eased = jQuery.easing[ this.easing ](
6382				percent, this.options.duration * percent, 0, 1, this.options.duration
6383			);
6384		} else {
6385			this.pos = eased = percent;
6386		}
6387		this.now = ( this.end - this.start ) * eased + this.start;
6388
6389		if ( this.options.step ) {
6390			this.options.step.call( this.elem, this.now, this );
6391		}
6392
6393		if ( hooks && hooks.set ) {
6394			hooks.set( this );
6395		} else {
6396			Tween.propHooks._default.set( this );
6397		}
6398		return this;
6399	}
6400};
6401
6402Tween.prototype.init.prototype = Tween.prototype;
6403
6404Tween.propHooks = {
6405	_default: {
6406		get: function( tween ) {
6407			var result;
6408
6409			// Use a property on the element directly when it is not a DOM element,
6410			// or when there is no matching style property that exists.
6411			if ( tween.elem.nodeType !== 1 ||
6412				tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) {
6413				return tween.elem[ tween.prop ];
6414			}
6415
6416			// Passing an empty string as a 3rd parameter to .css will automatically
6417			// attempt a parseFloat and fallback to a string if the parse fails.
6418			// Simple values such as "10px" are parsed to Float;
6419			// complex values such as "rotate(1rad)" are returned as-is.
6420			result = jQuery.css( tween.elem, tween.prop, "" );
6421
6422			// Empty strings, null, undefined and "auto" are converted to 0.
6423			return !result || result === "auto" ? 0 : result;
6424		},
6425		set: function( tween ) {
6426
6427			// Use step hook for back compat.
6428			// Use cssHook if its there.
6429			// Use .style if available and use plain properties where available.
6430			if ( jQuery.fx.step[ tween.prop ] ) {
6431				jQuery.fx.step[ tween.prop ]( tween );
6432			} else if ( tween.elem.nodeType === 1 &&
6433				( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null ||
6434					jQuery.cssHooks[ tween.prop ] ) ) {
6435				jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
6436			} else {
6437				tween.elem[ tween.prop ] = tween.now;
6438			}
6439		}
6440	}
6441};
6442
6443// Support: IE9
6444// Panic based approach to setting things on disconnected nodes
6445Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
6446	set: function( tween ) {
6447		if ( tween.elem.nodeType && tween.elem.parentNode ) {
6448			tween.elem[ tween.prop ] = tween.now;
6449		}
6450	}
6451};
6452
6453jQuery.easing = {
6454	linear: function( p ) {
6455		return p;
6456	},
6457	swing: function( p ) {
6458		return 0.5 - Math.cos( p * Math.PI ) / 2;
6459	},
6460	_default: "swing"
6461};
6462
6463jQuery.fx = Tween.prototype.init;
6464
6465// Back Compat <1.8 extension point
6466jQuery.fx.step = {};
6467
6468
6469
6470
6471var
6472	fxNow, timerId,
6473	rfxtypes = /^(?:toggle|show|hide)$/,
6474	rrun = /queueHooks$/;
6475
6476// Animations created synchronously will run synchronously
6477function createFxNow() {
6478	window.setTimeout( function() {
6479		fxNow = undefined;
6480	} );
6481	return ( fxNow = jQuery.now() );
6482}
6483
6484// Generate parameters to create a standard animation
6485function genFx( type, includeWidth ) {
6486	var which,
6487		i = 0,
6488		attrs = { height: type };
6489
6490	// If we include width, step value is 1 to do all cssExpand values,
6491	// otherwise step value is 2 to skip over Left and Right
6492	includeWidth = includeWidth ? 1 : 0;
6493	for ( ; i < 4 ; i += 2 - includeWidth ) {
6494		which = cssExpand[ i ];
6495		attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
6496	}
6497
6498	if ( includeWidth ) {
6499		attrs.opacity = attrs.width = type;
6500	}
6501
6502	return attrs;
6503}
6504
6505function createTween( value, prop, animation ) {
6506	var tween,
6507		collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ),
6508		index = 0,
6509		length = collection.length;
6510	for ( ; index < length; index++ ) {
6511		if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) {
6512
6513			// We're done with this property
6514			return tween;
6515		}
6516	}
6517}
6518
6519function defaultPrefilter( elem, props, opts ) {
6520	/* jshint validthis: true */
6521	var prop, value, toggle, tween, hooks, oldfire, display, checkDisplay,
6522		anim = this,
6523		orig = {},
6524		style = elem.style,
6525		hidden = elem.nodeType && isHidden( elem ),
6526		dataShow = dataPriv.get( elem, "fxshow" );
6527
6528	// Handle queue: false promises
6529	if ( !opts.queue ) {
6530		hooks = jQuery._queueHooks( elem, "fx" );
6531		if ( hooks.unqueued == null ) {
6532			hooks.unqueued = 0;
6533			oldfire = hooks.empty.fire;
6534			hooks.empty.fire = function() {
6535				if ( !hooks.unqueued ) {
6536					oldfire();
6537				}
6538			};
6539		}
6540		hooks.unqueued++;
6541
6542		anim.always( function() {
6543
6544			// Ensure the complete handler is called before this completes
6545			anim.always( function() {
6546				hooks.unqueued--;
6547				if ( !jQuery.queue( elem, "fx" ).length ) {
6548					hooks.empty.fire();
6549				}
6550			} );
6551		} );
6552	}
6553
6554	// Height/width overflow pass
6555	if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
6556
6557		// Make sure that nothing sneaks out
6558		// Record all 3 overflow attributes because IE9-10 do not
6559		// change the overflow attribute when overflowX and
6560		// overflowY are set to the same value
6561		opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
6562
6563		// Set display property to inline-block for height/width
6564		// animations on inline elements that are having width/height animated
6565		display = jQuery.css( elem, "display" );
6566
6567		// Test default display if display is currently "none"
6568		checkDisplay = display === "none" ?
6569			dataPriv.get( elem, "olddisplay" ) || defaultDisplay( elem.nodeName ) : display;
6570
6571		if ( checkDisplay === "inline" && jQuery.css( elem, "float" ) === "none" ) {
6572			style.display = "inline-block";
6573		}
6574	}
6575
6576	if ( opts.overflow ) {
6577		style.overflow = "hidden";
6578		anim.always( function() {
6579			style.overflow = opts.overflow[ 0 ];
6580			style.overflowX = opts.overflow[ 1 ];
6581			style.overflowY = opts.overflow[ 2 ];
6582		} );
6583	}
6584
6585	// show/hide pass
6586	for ( prop in props ) {
6587		value = props[ prop ];
6588		if ( rfxtypes.exec( value ) ) {
6589			delete props[ prop ];
6590			toggle = toggle || value === "toggle";
6591			if ( value === ( hidden ? "hide" : "show" ) ) {
6592
6593				// If there is dataShow left over from a stopped hide or show
6594				// and we are going to proceed with show, we should pretend to be hidden
6595				if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
6596					hidden = true;
6597				} else {
6598					continue;
6599				}
6600			}
6601			orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
6602
6603		// Any non-fx value stops us from restoring the original display value
6604		} else {
6605			display = undefined;
6606		}
6607	}
6608
6609	if ( !jQuery.isEmptyObject( orig ) ) {
6610		if ( dataShow ) {
6611			if ( "hidden" in dataShow ) {
6612				hidden = dataShow.hidden;
6613			}
6614		} else {
6615			dataShow = dataPriv.access( elem, "fxshow", {} );
6616		}
6617
6618		// Store state if its toggle - enables .stop().toggle() to "reverse"
6619		if ( toggle ) {
6620			dataShow.hidden = !hidden;
6621		}
6622		if ( hidden ) {
6623			jQuery( elem ).show();
6624		} else {
6625			anim.done( function() {
6626				jQuery( elem ).hide();
6627			} );
6628		}
6629		anim.done( function() {
6630			var prop;
6631
6632			dataPriv.remove( elem, "fxshow" );
6633			for ( prop in orig ) {
6634				jQuery.style( elem, prop, orig[ prop ] );
6635			}
6636		} );
6637		for ( prop in orig ) {
6638			tween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
6639
6640			if ( !( prop in dataShow ) ) {
6641				dataShow[ prop ] = tween.start;
6642				if ( hidden ) {
6643					tween.end = tween.start;
6644					tween.start = prop === "width" || prop === "height" ? 1 : 0;
6645				}
6646			}
6647		}
6648
6649	// If this is a noop like .hide().hide(), restore an overwritten display value
6650	} else if ( ( display === "none" ? defaultDisplay( elem.nodeName ) : display ) === "inline" ) {
6651		style.display = display;
6652	}
6653}
6654
6655function propFilter( props, specialEasing ) {
6656	var index, name, easing, value, hooks;
6657
6658	// camelCase, specialEasing and expand cssHook pass
6659	for ( index in props ) {
6660		name = jQuery.camelCase( index );
6661		easing = specialEasing[ name ];
6662		value = props[ index ];
6663		if ( jQuery.isArray( value ) ) {
6664			easing = value[ 1 ];
6665			value = props[ index ] = value[ 0 ];
6666		}
6667
6668		if ( index !== name ) {
6669			props[ name ] = value;
6670			delete props[ index ];
6671		}
6672
6673		hooks = jQuery.cssHooks[ name ];
6674		if ( hooks && "expand" in hooks ) {
6675			value = hooks.expand( value );
6676			delete props[ name ];
6677
6678			// Not quite $.extend, this won't overwrite existing keys.
6679			// Reusing 'index' because we have the correct "name"
6680			for ( index in value ) {
6681				if ( !( index in props ) ) {
6682					props[ index ] = value[ index ];
6683					specialEasing[ index ] = easing;
6684				}
6685			}
6686		} else {
6687			specialEasing[ name ] = easing;
6688		}
6689	}
6690}
6691
6692function Animation( elem, properties, options ) {
6693	var result,
6694		stopped,
6695		index = 0,
6696		length = Animation.prefilters.length,
6697		deferred = jQuery.Deferred().always( function() {
6698
6699			// Don't match elem in the :animated selector
6700			delete tick.elem;
6701		} ),
6702		tick = function() {
6703			if ( stopped ) {
6704				return false;
6705			}
6706			var currentTime = fxNow || createFxNow(),
6707				remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
6708
6709				// Support: Android 2.3
6710				// Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497)
6711				temp = remaining / animation.duration || 0,
6712				percent = 1 - temp,
6713				index = 0,
6714				length = animation.tweens.length;
6715
6716			for ( ; index < length ; index++ ) {
6717				animation.tweens[ index ].run( percent );
6718			}
6719
6720			deferred.notifyWith( elem, [ animation, percent, remaining ] );
6721
6722			if ( percent < 1 && length ) {
6723				return remaining;
6724			} else {
6725				deferred.resolveWith( elem, [ animation ] );
6726				return false;
6727			}
6728		},
6729		animation = deferred.promise( {
6730			elem: elem,
6731			props: jQuery.extend( {}, properties ),
6732			opts: jQuery.extend( true, {
6733				specialEasing: {},
6734				easing: jQuery.easing._default
6735			}, options ),
6736			originalProperties: properties,
6737			originalOptions: options,
6738			startTime: fxNow || createFxNow(),
6739			duration: options.duration,
6740			tweens: [],
6741			createTween: function( prop, end ) {
6742				var tween = jQuery.Tween( elem, animation.opts, prop, end,
6743						animation.opts.specialEasing[ prop ] || animation.opts.easing );
6744				animation.tweens.push( tween );
6745				return tween;
6746			},
6747			stop: function( gotoEnd ) {
6748				var index = 0,
6749
6750					// If we are going to the end, we want to run all the tweens
6751					// otherwise we skip this part
6752					length = gotoEnd ? animation.tweens.length : 0;
6753				if ( stopped ) {
6754					return this;
6755				}
6756				stopped = true;
6757				for ( ; index < length ; index++ ) {
6758					animation.tweens[ index ].run( 1 );
6759				}
6760
6761				// Resolve when we played the last frame; otherwise, reject
6762				if ( gotoEnd ) {
6763					deferred.notifyWith( elem, [ animation, 1, 0 ] );
6764					deferred.resolveWith( elem, [ animation, gotoEnd ] );
6765				} else {
6766					deferred.rejectWith( elem, [ animation, gotoEnd ] );
6767				}
6768				return this;
6769			}
6770		} ),
6771		props = animation.props;
6772
6773	propFilter( props, animation.opts.specialEasing );
6774
6775	for ( ; index < length ; index++ ) {
6776		result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts );
6777		if ( result ) {
6778			if ( jQuery.isFunction( result.stop ) ) {
6779				jQuery._queueHooks( animation.elem, animation.opts.queue ).stop =
6780					jQuery.proxy( result.stop, result );
6781			}
6782			return result;
6783		}
6784	}
6785
6786	jQuery.map( props, createTween, animation );
6787
6788	if ( jQuery.isFunction( animation.opts.start ) ) {
6789		animation.opts.start.call( elem, animation );
6790	}
6791
6792	jQuery.fx.timer(
6793		jQuery.extend( tick, {
6794			elem: elem,
6795			anim: animation,
6796			queue: animation.opts.queue
6797		} )
6798	);
6799
6800	// attach callbacks from options
6801	return animation.progress( animation.opts.progress )
6802		.done( animation.opts.done, animation.opts.complete )
6803		.fail( animation.opts.fail )
6804		.always( animation.opts.always );
6805}
6806
6807jQuery.Animation = jQuery.extend( Animation, {
6808	tweeners: {
6809		"*": [ function( prop, value ) {
6810			var tween = this.createTween( prop, value );
6811			adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween );
6812			return tween;
6813		} ]
6814	},
6815
6816	tweener: function( props, callback ) {
6817		if ( jQuery.isFunction( props ) ) {
6818			callback = props;
6819			props = [ "*" ];
6820		} else {
6821			props = props.match( rnotwhite );
6822		}
6823
6824		var prop,
6825			index = 0,
6826			length = props.length;
6827
6828		for ( ; index < length ; index++ ) {
6829			prop = props[ index ];
6830			Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || [];
6831			Animation.tweeners[ prop ].unshift( callback );
6832		}
6833	},
6834
6835	prefilters: [ defaultPrefilter ],
6836
6837	prefilter: function( callback, prepend ) {
6838		if ( prepend ) {
6839			Animation.prefilters.unshift( callback );
6840		} else {
6841			Animation.prefilters.push( callback );
6842		}
6843	}
6844} );
6845
6846jQuery.speed = function( speed, easing, fn ) {
6847	var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
6848		complete: fn || !fn && easing ||
6849			jQuery.isFunction( speed ) && speed,
6850		duration: speed,
6851		easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
6852	};
6853
6854	opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ?
6855		opt.duration : opt.duration in jQuery.fx.speeds ?
6856			jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
6857
6858	// Normalize opt.queue - true/undefined/null -> "fx"
6859	if ( opt.queue == null || opt.queue === true ) {
6860		opt.queue = "fx";
6861	}
6862
6863	// Queueing
6864	opt.old = opt.complete;
6865
6866	opt.complete = function() {
6867		if ( jQuery.isFunction( opt.old ) ) {
6868			opt.old.call( this );
6869		}
6870
6871		if ( opt.queue ) {
6872			jQuery.dequeue( this, opt.queue );
6873		}
6874	};
6875
6876	return opt;
6877};
6878
6879jQuery.fn.extend( {
6880	fadeTo: function( speed, to, easing, callback ) {
6881
6882		// Show any hidden elements after setting opacity to 0
6883		return this.filter( isHidden ).css( "opacity", 0 ).show()
6884
6885			// Animate to the value specified
6886			.end().animate( { opacity: to }, speed, easing, callback );
6887	},
6888	animate: function( prop, speed, easing, callback ) {
6889		var empty = jQuery.isEmptyObject( prop ),
6890			optall = jQuery.speed( speed, easing, callback ),
6891			doAnimation = function() {
6892
6893				// Operate on a copy of prop so per-property easing won't be lost
6894				var anim = Animation( this, jQuery.extend( {}, prop ), optall );
6895
6896				// Empty animations, or finishing resolves immediately
6897				if ( empty || dataPriv.get( this, "finish" ) ) {
6898					anim.stop( true );
6899				}
6900			};
6901			doAnimation.finish = doAnimation;
6902
6903		return empty || optall.queue === false ?
6904			this.each( doAnimation ) :
6905			this.queue( optall.queue, doAnimation );
6906	},
6907	stop: function( type, clearQueue, gotoEnd ) {
6908		var stopQueue = function( hooks ) {
6909			var stop = hooks.stop;
6910			delete hooks.stop;
6911			stop( gotoEnd );
6912		};
6913
6914		if ( typeof type !== "string" ) {
6915			gotoEnd = clearQueue;
6916			clearQueue = type;
6917			type = undefined;
6918		}
6919		if ( clearQueue && type !== false ) {
6920			this.queue( type || "fx", [] );
6921		}
6922
6923		return this.each( function() {
6924			var dequeue = true,
6925				index = type != null && type + "queueHooks",
6926				timers = jQuery.timers,
6927				data = dataPriv.get( this );
6928
6929			if ( index ) {
6930				if ( data[ index ] && data[ index ].stop ) {
6931					stopQueue( data[ index ] );
6932				}
6933			} else {
6934				for ( index in data ) {
6935					if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
6936						stopQueue( data[ index ] );
6937					}
6938				}
6939			}
6940
6941			for ( index = timers.length; index--; ) {
6942				if ( timers[ index ].elem === this &&
6943					( type == null || timers[ index ].queue === type ) ) {
6944
6945					timers[ index ].anim.stop( gotoEnd );
6946					dequeue = false;
6947					timers.splice( index, 1 );
6948				}
6949			}
6950
6951			// Start the next in the queue if the last step wasn't forced.
6952			// Timers currently will call their complete callbacks, which
6953			// will dequeue but only if they were gotoEnd.
6954			if ( dequeue || !gotoEnd ) {
6955				jQuery.dequeue( this, type );
6956			}
6957		} );
6958	},
6959	finish: function( type ) {
6960		if ( type !== false ) {
6961			type = type || "fx";
6962		}
6963		return this.each( function() {
6964			var index,
6965				data = dataPriv.get( this ),
6966				queue = data[ type + "queue" ],
6967				hooks = data[ type + "queueHooks" ],
6968				timers = jQuery.timers,
6969				length = queue ? queue.length : 0;
6970
6971			// Enable finishing flag on private data
6972			data.finish = true;
6973
6974			// Empty the queue first
6975			jQuery.queue( this, type, [] );
6976
6977			if ( hooks && hooks.stop ) {
6978				hooks.stop.call( this, true );
6979			}
6980
6981			// Look for any active animations, and finish them
6982			for ( index = timers.length; index--; ) {
6983				if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
6984					timers[ index ].anim.stop( true );
6985					timers.splice( index, 1 );
6986				}
6987			}
6988
6989			// Look for any animations in the old queue and finish them
6990			for ( index = 0; index < length; index++ ) {
6991				if ( queue[ index ] && queue[ index ].finish ) {
6992					queue[ index ].finish.call( this );
6993				}
6994			}
6995
6996			// Turn off finishing flag
6997			delete data.finish;
6998		} );
6999	}
7000} );
7001
7002jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) {
7003	var cssFn = jQuery.fn[ name ];
7004	jQuery.fn[ name ] = function( speed, easing, callback ) {
7005		return speed == null || typeof speed === "boolean" ?
7006			cssFn.apply( this, arguments ) :
7007			this.animate( genFx( name, true ), speed, easing, callback );
7008	};
7009} );
7010
7011// Generate shortcuts for custom animations
7012jQuery.each( {
7013	slideDown: genFx( "show" ),
7014	slideUp: genFx( "hide" ),
7015	slideToggle: genFx( "toggle" ),
7016	fadeIn: { opacity: "show" },
7017	fadeOut: { opacity: "hide" },
7018	fadeToggle: { opacity: "toggle" }
7019}, function( name, props ) {
7020	jQuery.fn[ name ] = function( speed, easing, callback ) {
7021		return this.animate( props, speed, easing, callback );
7022	};
7023} );
7024
7025jQuery.timers = [];
7026jQuery.fx.tick = function() {
7027	var timer,
7028		i = 0,
7029		timers = jQuery.timers;
7030
7031	fxNow = jQuery.now();
7032
7033	for ( ; i < timers.length; i++ ) {
7034		timer = timers[ i ];
7035
7036		// Checks the timer has not already been removed
7037		if ( !timer() && timers[ i ] === timer ) {
7038			timers.splice( i--, 1 );
7039		}
7040	}
7041
7042	if ( !timers.length ) {
7043		jQuery.fx.stop();
7044	}
7045	fxNow = undefined;
7046};
7047
7048jQuery.fx.timer = function( timer ) {
7049	jQuery.timers.push( timer );
7050	if ( timer() ) {
7051		jQuery.fx.start();
7052	} else {
7053		jQuery.timers.pop();
7054	}
7055};
7056
7057jQuery.fx.interval = 13;
7058jQuery.fx.start = function() {
7059	if ( !timerId ) {
7060		timerId = window.setInterval( jQuery.fx.tick, jQuery.fx.interval );
7061	}
7062};
7063
7064jQuery.fx.stop = function() {
7065	window.clearInterval( timerId );
7066
7067	timerId = null;
7068};
7069
7070jQuery.fx.speeds = {
7071	slow: 600,
7072	fast: 200,
7073
7074	// Default speed
7075	_default: 400
7076};
7077
7078
7079// Based off of the plugin by Clint Helfers, with permission.
7080// http://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/
7081jQuery.fn.delay = function( time, type ) {
7082	time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
7083	type = type || "fx";
7084
7085	return this.queue( type, function( next, hooks ) {
7086		var timeout = window.setTimeout( next, time );
7087		hooks.stop = function() {
7088			window.clearTimeout( timeout );
7089		};
7090	} );
7091};
7092
7093
7094( function() {
7095	var input = document.createElement( "input" ),
7096		select = document.createElement( "select" ),
7097		opt = select.appendChild( document.createElement( "option" ) );
7098
7099	input.type = "checkbox";
7100
7101	// Support: iOS<=5.1, Android<=4.2+
7102	// Default value for a checkbox should be "on"
7103	support.checkOn = input.value !== "";
7104
7105	// Support: IE<=11+
7106	// Must access selectedIndex to make default options select
7107	support.optSelected = opt.selected;
7108
7109	// Support: Android<=2.3
7110	// Options inside disabled selects are incorrectly marked as disabled
7111	select.disabled = true;
7112	support.optDisabled = !opt.disabled;
7113
7114	// Support: IE<=11+
7115	// An input loses its value after becoming a radio
7116	input = document.createElement( "input" );
7117	input.value = "t";
7118	input.type = "radio";
7119	support.radioValue = input.value === "t";
7120} )();
7121
7122
7123var boolHook,
7124	attrHandle = jQuery.expr.attrHandle;
7125
7126jQuery.fn.extend( {
7127	attr: function( name, value ) {
7128		return access( this, jQuery.attr, name, value, arguments.length > 1 );
7129	},
7130
7131	removeAttr: function( name ) {
7132		return this.each( function() {
7133			jQuery.removeAttr( this, name );
7134		} );
7135	}
7136} );
7137
7138jQuery.extend( {
7139	attr: function( elem, name, value ) {
7140		var ret, hooks,
7141			nType = elem.nodeType;
7142
7143		// Don't get/set attributes on text, comment and attribute nodes
7144		if ( nType === 3 || nType === 8 || nType === 2 ) {
7145			return;
7146		}
7147
7148		// Fallback to prop when attributes are not supported
7149		if ( typeof elem.getAttribute === "undefined" ) {
7150			return jQuery.prop( elem, name, value );
7151		}
7152
7153		// All attributes are lowercase
7154		// Grab necessary hook if one is defined
7155		if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
7156			name = name.toLowerCase();
7157			hooks = jQuery.attrHooks[ name ] ||
7158				( jQuery.expr.match.bool.test( name ) ? boolHook : undefined );
7159		}
7160
7161		if ( value !== undefined ) {
7162			if ( value === null ) {
7163				jQuery.removeAttr( elem, name );
7164				return;
7165			}
7166
7167			if ( hooks && "set" in hooks &&
7168				( ret = hooks.set( elem, value, name ) ) !== undefined ) {
7169				return ret;
7170			}
7171
7172			elem.setAttribute( name, value + "" );
7173			return value;
7174		}
7175
7176		if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {
7177			return ret;
7178		}
7179
7180		ret = jQuery.find.attr( elem, name );
7181
7182		// Non-existent attributes return null, we normalize to undefined
7183		return ret == null ? undefined : ret;
7184	},
7185
7186	attrHooks: {
7187		type: {
7188			set: function( elem, value ) {
7189				if ( !support.radioValue && value === "radio" &&
7190					jQuery.nodeName( elem, "input" ) ) {
7191					var val = elem.value;
7192					elem.setAttribute( "type", value );
7193					if ( val ) {
7194						elem.value = val;
7195					}
7196					return value;
7197				}
7198			}
7199		}
7200	},
7201
7202	removeAttr: function( elem, value ) {
7203		var name, propName,
7204			i = 0,
7205			attrNames = value && value.match( rnotwhite );
7206
7207		if ( attrNames && elem.nodeType === 1 ) {
7208			while ( ( name = attrNames[ i++ ] ) ) {
7209				propName = jQuery.propFix[ name ] || name;
7210
7211				// Boolean attributes get special treatment (#10870)
7212				if ( jQuery.expr.match.bool.test( name ) ) {
7213
7214					// Set corresponding property to false
7215					elem[ propName ] = false;
7216				}
7217
7218				elem.removeAttribute( name );
7219			}
7220		}
7221	}
7222} );
7223
7224// Hooks for boolean attributes
7225boolHook = {
7226	set: function( elem, value, name ) {
7227		if ( value === false ) {
7228
7229			// Remove boolean attributes when set to false
7230			jQuery.removeAttr( elem, name );
7231		} else {
7232			elem.setAttribute( name, name );
7233		}
7234		return name;
7235	}
7236};
7237jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) {
7238	var getter = attrHandle[ name ] || jQuery.find.attr;
7239
7240	attrHandle[ name ] = function( elem, name, isXML ) {
7241		var ret, handle;
7242		if ( !isXML ) {
7243
7244			// Avoid an infinite loop by temporarily removing this function from the getter
7245			handle = attrHandle[ name ];
7246			attrHandle[ name ] = ret;
7247			ret = getter( elem, name, isXML ) != null ?
7248				name.toLowerCase() :
7249				null;
7250			attrHandle[ name ] = handle;
7251		}
7252		return ret;
7253	};
7254} );
7255
7256
7257
7258
7259var rfocusable = /^(?:input|select|textarea|button)$/i,
7260	rclickable = /^(?:a|area)$/i;
7261
7262jQuery.fn.extend( {
7263	prop: function( name, value ) {
7264		return access( this, jQuery.prop, name, value, arguments.length > 1 );
7265	},
7266
7267	removeProp: function( name ) {
7268		return this.each( function() {
7269			delete this[ jQuery.propFix[ name ] || name ];
7270		} );
7271	}
7272} );
7273
7274jQuery.extend( {
7275	prop: function( elem, name, value ) {
7276		var ret, hooks,
7277			nType = elem.nodeType;
7278
7279		// Don't get/set properties on text, comment and attribute nodes
7280		if ( nType === 3 || nType === 8 || nType === 2 ) {
7281			return;
7282		}
7283
7284		if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
7285
7286			// Fix name and attach hooks
7287			name = jQuery.propFix[ name ] || name;
7288			hooks = jQuery.propHooks[ name ];
7289		}
7290
7291		if ( value !== undefined ) {
7292			if ( hooks && "set" in hooks &&
7293				( ret = hooks.set( elem, value, name ) ) !== undefined ) {
7294				return ret;
7295			}
7296
7297			return ( elem[ name ] = value );
7298		}
7299
7300		if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {
7301			return ret;
7302		}
7303
7304		return elem[ name ];
7305	},
7306
7307	propHooks: {
7308		tabIndex: {
7309			get: function( elem ) {
7310
7311				// elem.tabIndex doesn't always return the
7312				// correct value when it hasn't been explicitly set
7313				// http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
7314				// Use proper attribute retrieval(#12072)
7315				var tabindex = jQuery.find.attr( elem, "tabindex" );
7316
7317				return tabindex ?
7318					parseInt( tabindex, 10 ) :
7319					rfocusable.test( elem.nodeName ) ||
7320						rclickable.test( elem.nodeName ) && elem.href ?
7321							0 :
7322							-1;
7323			}
7324		}
7325	},
7326
7327	propFix: {
7328		"for": "htmlFor",
7329		"class": "className"
7330	}
7331} );
7332
7333// Support: IE <=11 only
7334// Accessing the selectedIndex property
7335// forces the browser to respect setting selected
7336// on the option
7337// The getter ensures a default option is selected
7338// when in an optgroup
7339if ( !support.optSelected ) {
7340	jQuery.propHooks.selected = {
7341		get: function( elem ) {
7342			var parent = elem.parentNode;
7343			if ( parent && parent.parentNode ) {
7344				parent.parentNode.selectedIndex;
7345			}
7346			return null;
7347		},
7348		set: function( elem ) {
7349			var parent = elem.parentNode;
7350			if ( parent ) {
7351				parent.selectedIndex;
7352
7353				if ( parent.parentNode ) {
7354					parent.parentNode.selectedIndex;
7355				}
7356			}
7357		}
7358	};
7359}
7360
7361jQuery.each( [
7362	"tabIndex",
7363	"readOnly",
7364	"maxLength",
7365	"cellSpacing",
7366	"cellPadding",
7367	"rowSpan",
7368	"colSpan",
7369	"useMap",
7370	"frameBorder",
7371	"contentEditable"
7372], function() {
7373	jQuery.propFix[ this.toLowerCase() ] = this;
7374} );
7375
7376
7377
7378
7379var rclass = /[\t\r\n\f]/g;
7380
7381function getClass( elem ) {
7382	return elem.getAttribute && elem.getAttribute( "class" ) || "";
7383}
7384
7385jQuery.fn.extend( {
7386	addClass: function( value ) {
7387		var classes, elem, cur, curValue, clazz, j, finalValue,
7388			i = 0;
7389
7390		if ( jQuery.isFunction( value ) ) {
7391			return this.each( function( j ) {
7392				jQuery( this ).addClass( value.call( this, j, getClass( this ) ) );
7393			} );
7394		}
7395
7396		if ( typeof value === "string" && value ) {
7397			classes = value.match( rnotwhite ) || [];
7398
7399			while ( ( elem = this[ i++ ] ) ) {
7400				curValue = getClass( elem );
7401				cur = elem.nodeType === 1 &&
7402					( " " + curValue + " " ).replace( rclass, " " );
7403
7404				if ( cur ) {
7405					j = 0;
7406					while ( ( clazz = classes[ j++ ] ) ) {
7407						if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
7408							cur += clazz + " ";
7409						}
7410					}
7411
7412					// Only assign if different to avoid unneeded rendering.
7413					finalValue = jQuery.trim( cur );
7414					if ( curValue !== finalValue ) {
7415						elem.setAttribute( "class", finalValue );
7416					}
7417				}
7418			}
7419		}
7420
7421		return this;
7422	},
7423
7424	removeClass: function( value ) {
7425		var classes, elem, cur, curValue, clazz, j, finalValue,
7426			i = 0;
7427
7428		if ( jQuery.isFunction( value ) ) {
7429			return this.each( function( j ) {
7430				jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) );
7431			} );
7432		}
7433
7434		if ( !arguments.length ) {
7435			return this.attr( "class", "" );
7436		}
7437
7438		if ( typeof value === "string" && value ) {
7439			classes = value.match( rnotwhite ) || [];
7440
7441			while ( ( elem = this[ i++ ] ) ) {
7442				curValue = getClass( elem );
7443
7444				// This expression is here for better compressibility (see addClass)
7445				cur = elem.nodeType === 1 &&
7446					( " " + curValue + " " ).replace( rclass, " " );
7447
7448				if ( cur ) {
7449					j = 0;
7450					while ( ( clazz = classes[ j++ ] ) ) {
7451
7452						// Remove *all* instances
7453						while ( cur.indexOf( " " + clazz + " " ) > -1 ) {
7454							cur = cur.replace( " " + clazz + " ", " " );
7455						}
7456					}
7457
7458					// Only assign if different to avoid unneeded rendering.
7459					finalValue = jQuery.trim( cur );
7460					if ( curValue !== finalValue ) {
7461						elem.setAttribute( "class", finalValue );
7462					}
7463				}
7464			}
7465		}
7466
7467		return this;
7468	},
7469
7470	toggleClass: function( value, stateVal ) {
7471		var type = typeof value;
7472
7473		if ( typeof stateVal === "boolean" && type === "string" ) {
7474			return stateVal ? this.addClass( value ) : this.removeClass( value );
7475		}
7476
7477		if ( jQuery.isFunction( value ) ) {
7478			return this.each( function( i ) {
7479				jQuery( this ).toggleClass(
7480					value.call( this, i, getClass( this ), stateVal ),
7481					stateVal
7482				);
7483			} );
7484		}
7485
7486		return this.each( function() {
7487			var className, i, self, classNames;
7488
7489			if ( type === "string" ) {
7490
7491				// Toggle individual class names
7492				i = 0;
7493				self = jQuery( this );
7494				classNames = value.match( rnotwhite ) || [];
7495
7496				while ( ( className = classNames[ i++ ] ) ) {
7497
7498					// Check each className given, space separated list
7499					if ( self.hasClass( className ) ) {
7500						self.removeClass( className );
7501					} else {
7502						self.addClass( className );
7503					}
7504				}
7505
7506			// Toggle whole class name
7507			} else if ( value === undefined || type === "boolean" ) {
7508				className = getClass( this );
7509				if ( className ) {
7510
7511					// Store className if set
7512					dataPriv.set( this, "__className__", className );
7513				}
7514
7515				// If the element has a class name or if we're passed `false`,
7516				// then remove the whole classname (if there was one, the above saved it).
7517				// Otherwise bring back whatever was previously saved (if anything),
7518				// falling back to the empty string if nothing was stored.
7519				if ( this.setAttribute ) {
7520					this.setAttribute( "class",
7521						className || value === false ?
7522						"" :
7523						dataPriv.get( this, "__className__" ) || ""
7524					);
7525				}
7526			}
7527		} );
7528	},
7529
7530	hasClass: function( selector ) {
7531		var className, elem,
7532			i = 0;
7533
7534		className = " " + selector + " ";
7535		while ( ( elem = this[ i++ ] ) ) {
7536			if ( elem.nodeType === 1 &&
7537				( " " + getClass( elem ) + " " ).replace( rclass, " " )
7538					.indexOf( className ) > -1
7539			) {
7540				return true;
7541			}
7542		}
7543
7544		return false;
7545	}
7546} );
7547
7548
7549
7550
7551var rreturn = /\r/g,
7552	rspaces = /[\x20\t\r\n\f]+/g;
7553
7554jQuery.fn.extend( {
7555	val: function( value ) {
7556		var hooks, ret, isFunction,
7557			elem = this[ 0 ];
7558
7559		if ( !arguments.length ) {
7560			if ( elem ) {
7561				hooks = jQuery.valHooks[ elem.type ] ||
7562					jQuery.valHooks[ elem.nodeName.toLowerCase() ];
7563
7564				if ( hooks &&
7565					"get" in hooks &&
7566					( ret = hooks.get( elem, "value" ) ) !== undefined
7567				) {
7568					return ret;
7569				}
7570
7571				ret = elem.value;
7572
7573				return typeof ret === "string" ?
7574
7575					// Handle most common string cases
7576					ret.replace( rreturn, "" ) :
7577
7578					// Handle cases where value is null/undef or number
7579					ret == null ? "" : ret;
7580			}
7581
7582			return;
7583		}
7584
7585		isFunction = jQuery.isFunction( value );
7586
7587		return this.each( function( i ) {
7588			var val;
7589
7590			if ( this.nodeType !== 1 ) {
7591				return;
7592			}
7593
7594			if ( isFunction ) {
7595				val = value.call( this, i, jQuery( this ).val() );
7596			} else {
7597				val = value;
7598			}
7599
7600			// Treat null/undefined as ""; convert numbers to string
7601			if ( val == null ) {
7602				val = "";
7603
7604			} else if ( typeof val === "number" ) {
7605				val += "";
7606
7607			} else if ( jQuery.isArray( val ) ) {
7608				val = jQuery.map( val, function( value ) {
7609					return value == null ? "" : value + "";
7610				} );
7611			}
7612
7613			hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
7614
7615			// If set returns undefined, fall back to normal setting
7616			if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) {
7617				this.value = val;
7618			}
7619		} );
7620	}
7621} );
7622
7623jQuery.extend( {
7624	valHooks: {
7625		option: {
7626			get: function( elem ) {
7627
7628				var val = jQuery.find.attr( elem, "value" );
7629				return val != null ?
7630					val :
7631
7632					// Support: IE10-11+
7633					// option.text throws exceptions (#14686, #14858)
7634					// Strip and collapse whitespace
7635					// https://html.spec.whatwg.org/#strip-and-collapse-whitespace
7636					jQuery.trim( jQuery.text( elem ) ).replace( rspaces, " " );
7637			}
7638		},
7639		select: {
7640			get: function( elem ) {
7641				var value, option,
7642					options = elem.options,
7643					index = elem.selectedIndex,
7644					one = elem.type === "select-one" || index < 0,
7645					values = one ? null : [],
7646					max = one ? index + 1 : options.length,
7647					i = index < 0 ?
7648						max :
7649						one ? index : 0;
7650
7651				// Loop through all the selected options
7652				for ( ; i < max; i++ ) {
7653					option = options[ i ];
7654
7655					// IE8-9 doesn't update selected after form reset (#2551)
7656					if ( ( option.selected || i === index ) &&
7657
7658							// Don't return options that are disabled or in a disabled optgroup
7659							( support.optDisabled ?
7660								!option.disabled : option.getAttribute( "disabled" ) === null ) &&
7661							( !option.parentNode.disabled ||
7662								!jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
7663
7664						// Get the specific value for the option
7665						value = jQuery( option ).val();
7666
7667						// We don't need an array for one selects
7668						if ( one ) {
7669							return value;
7670						}
7671
7672						// Multi-Selects return an array
7673						values.push( value );
7674					}
7675				}
7676
7677				return values;
7678			},
7679
7680			set: function( elem, value ) {
7681				var optionSet, option,
7682					options = elem.options,
7683					values = jQuery.makeArray( value ),
7684					i = options.length;
7685
7686				while ( i-- ) {
7687					option = options[ i ];
7688					if ( option.selected =
7689						jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1
7690					) {
7691						optionSet = true;
7692					}
7693				}
7694
7695				// Force browsers to behave consistently when non-matching value is set
7696				if ( !optionSet ) {
7697					elem.selectedIndex = -1;
7698				}
7699				return values;
7700			}
7701		}
7702	}
7703} );
7704
7705// Radios and checkboxes getter/setter
7706jQuery.each( [ "radio", "checkbox" ], function() {
7707	jQuery.valHooks[ this ] = {
7708		set: function( elem, value ) {
7709			if ( jQuery.isArray( value ) ) {
7710				return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 );
7711			}
7712		}
7713	};
7714	if ( !support.checkOn ) {
7715		jQuery.valHooks[ this ].get = function( elem ) {
7716			return elem.getAttribute( "value" ) === null ? "on" : elem.value;
7717		};
7718	}
7719} );
7720
7721
7722
7723
7724// Return jQuery for attributes-only inclusion
7725
7726
7727var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/;
7728
7729jQuery.extend( jQuery.event, {
7730
7731	trigger: function( event, data, elem, onlyHandlers ) {
7732
7733		var i, cur, tmp, bubbleType, ontype, handle, special,
7734			eventPath = [ elem || document ],
7735			type = hasOwn.call( event, "type" ) ? event.type : event,
7736			namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : [];
7737
7738		cur = tmp = elem = elem || document;
7739
7740		// Don't do events on text and comment nodes
7741		if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
7742			return;
7743		}
7744
7745		// focus/blur morphs to focusin/out; ensure we're not firing them right now
7746		if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
7747			return;
7748		}
7749
7750		if ( type.indexOf( "." ) > -1 ) {
7751
7752			// Namespaced trigger; create a regexp to match event type in handle()
7753			namespaces = type.split( "." );
7754			type = namespaces.shift();
7755			namespaces.sort();
7756		}
7757		ontype = type.indexOf( ":" ) < 0 && "on" + type;
7758
7759		// Caller can pass in a jQuery.Event object, Object, or just an event type string
7760		event = event[ jQuery.expando ] ?
7761			event :
7762			new jQuery.Event( type, typeof event === "object" && event );
7763
7764		// Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
7765		event.isTrigger = onlyHandlers ? 2 : 3;
7766		event.namespace = namespaces.join( "." );
7767		event.rnamespace = event.namespace ?
7768			new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) :
7769			null;
7770
7771		// Clean up the event in case it is being reused
7772		event.result = undefined;
7773		if ( !event.target ) {
7774			event.target = elem;
7775		}
7776
7777		// Clone any incoming data and prepend the event, creating the handler arg list
7778		data = data == null ?
7779			[ event ] :
7780			jQuery.makeArray( data, [ event ] );
7781
7782		// Allow special events to draw outside the lines
7783		special = jQuery.event.special[ type ] || {};
7784		if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
7785			return;
7786		}
7787
7788		// Determine event propagation path in advance, per W3C events spec (#9951)
7789		// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
7790		if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
7791
7792			bubbleType = special.delegateType || type;
7793			if ( !rfocusMorph.test( bubbleType + type ) ) {
7794				cur = cur.parentNode;
7795			}
7796			for ( ; cur; cur = cur.parentNode ) {
7797				eventPath.push( cur );
7798				tmp = cur;
7799			}
7800
7801			// Only add window if we got to document (e.g., not plain obj or detached DOM)
7802			if ( tmp === ( elem.ownerDocument || document ) ) {
7803				eventPath.push( tmp.defaultView || tmp.parentWindow || window );
7804			}
7805		}
7806
7807		// Fire handlers on the event path
7808		i = 0;
7809		while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) {
7810
7811			event.type = i > 1 ?
7812				bubbleType :
7813				special.bindType || type;
7814
7815			// jQuery handler
7816			handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] &&
7817				dataPriv.get( cur, "handle" );
7818			if ( handle ) {
7819				handle.apply( cur, data );
7820			}
7821
7822			// Native handler
7823			handle = ontype && cur[ ontype ];
7824			if ( handle && handle.apply && acceptData( cur ) ) {
7825				event.result = handle.apply( cur, data );
7826				if ( event.result === false ) {
7827					event.preventDefault();
7828				}
7829			}
7830		}
7831		event.type = type;
7832
7833		// If nobody prevented the default action, do it now
7834		if ( !onlyHandlers && !event.isDefaultPrevented() ) {
7835
7836			if ( ( !special._default ||
7837				special._default.apply( eventPath.pop(), data ) === false ) &&
7838				acceptData( elem ) ) {
7839
7840				// Call a native DOM method on the target with the same name name as the event.
7841				// Don't do default actions on window, that's where global variables be (#6170)
7842				if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) {
7843
7844					// Don't re-trigger an onFOO event when we call its FOO() method
7845					tmp = elem[ ontype ];
7846
7847					if ( tmp ) {
7848						elem[ ontype ] = null;
7849					}
7850
7851					// Prevent re-triggering of the same event, since we already bubbled it above
7852					jQuery.event.triggered = type;
7853					elem[ type ]();
7854					jQuery.event.triggered = undefined;
7855
7856					if ( tmp ) {
7857						elem[ ontype ] = tmp;
7858					}
7859				}
7860			}
7861		}
7862
7863		return event.result;
7864	},
7865
7866	// Piggyback on a donor event to simulate a different one
7867	
7867simulate: function( type, elem, event ) {
7868		var e = jQuery.extend(
7869			new jQuery.Event(),
7870			event,
7871			{
7872				type: type,
7873				isSimulated: true
7874
7875				// Previously, `originalEvent: {}` was set here, so stopPropagation call
7876				// would not be triggered on donor event, since in our own
7877				// jQuery.event.stopPropagation function we had a check for existence of
7878				// originalEvent.stopPropagation method, so, consequently it would be a noop.
7879				//
7880				// But now, this "simulate" function is used only for events
7881				// for which stopPropagation() is noop, so there is no need for that anymore.
7882				//
7883				// For the 1.x branch though, guard for "click" and "submit"
7884				// events is still used, but was moved to jQuery.event.stopPropagation function
7885				// because `originalEvent` should point to the original event for the constancy
7886				// with other events and for more focused logic
7887			}
7888		);
7889
7890		jQuery.event.trigger( e, null, elem );
7891
7892		if ( e.isDefaultPrevented() ) {
7893			event.preventDefault();
7894		}
vendor: 40,185 bytes, lines 7894-9478
7894
7895	}
7896
7897} );
7898
7899jQuery.fn.extend( {
7900
7901	trigger: function( type, data ) {
7902		return this.each( function() {
7903			jQuery.event.trigger( type, data, this );
7904		} );
7905	},
7906	triggerHandler: function( type, data ) {
7907		var elem = this[ 0 ];
7908		if ( elem ) {
7909			return jQuery.event.trigger( type, data, elem, true );
7910		}
7911	}
7912} );
7913
7914
7915jQuery.each( ( "blur focus focusin focusout load resize scroll unload click dblclick " +
7916	"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
7917	"change select submit keydown keypress keyup error contextmenu" ).split( " " ),
7918	function( i, name ) {
7919
7920	// Handle event binding
7921	jQuery.fn[ name ] = function( data, fn ) {
7922		return arguments.length > 0 ?
7923			this.on( name, null, data, fn ) :
7924			this.trigger( name );
7925	};
7926} );
7927
7928jQuery.fn.extend( {
7929	hover: function( fnOver, fnOut ) {
7930		return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
7931	}
7932} );
7933
7934
7935
7936
7937support.focusin = "onfocusin" in window;
7938
7939
7940// Support: Firefox
7941// Firefox doesn't have focus(in | out) events
7942// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787
7943//
7944// Support: Chrome, Safari
7945// focus(in | out) events fire after focus & blur events,
7946// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order
7947// Related ticket - https://code.google.com/p/chromium/issues/detail?id=449857
7948if ( !support.focusin ) {
7949	jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) {
7950
7951		// Attach a single capturing handler on the document while someone wants focusin/focusout
7952		var handler = function( event ) {
7953			jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) );
7954		};
7955
7956		jQuery.event.special[ fix ] = {
7957			setup: function() {
7958				var doc = this.ownerDocument || this,
7959					attaches = dataPriv.access( doc, fix );
7960
7961				if ( !attaches ) {
7962					doc.addEventListener( orig, handler, true );
7963				}
7964				dataPriv.access( doc, fix, ( attaches || 0 ) + 1 );
7965			},
7966			teardown: function() {
7967				var doc = this.ownerDocument || this,
7968					attaches = dataPriv.access( doc, fix ) - 1;
7969
7970				if ( !attaches ) {
7971					doc.removeEventListener( orig, handler, true );
7972					dataPriv.remove( doc, fix );
7973
7974				} else {
7975					dataPriv.access( doc, fix, attaches );
7976				}
7977			}
7978		};
7979	} );
7980}
7981var location = window.location;
7982
7983var nonce = jQuery.now();
7984
7985var rquery = ( /\?/ );
7986
7987
7988
7989// Support: Android 2.3
7990// Workaround failure to string-cast null input
7991jQuery.parseJSON = function( data ) {
7992	return JSON.parse( data + "" );
7993};
7994
7995
7996// Cross-browser xml parsing
7997jQuery.parseXML = function( data ) {
7998	var xml;
7999	if ( !data || typeof data !== "string" ) {
8000		return null;
8001	}
8002
8003	// Support: IE9
8004	try {
8005		xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" );
8006	} catch ( e ) {
8007		xml = undefined;
8008	}
8009
8010	if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) {
8011		jQuery.error( "Invalid XML: " + data );
8012	}
8013	return xml;
8014};
8015
8016
8017var
8018	rhash = /#.*$/,
8019	rts = /([?&])_=[^&]*/,
8020	rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg,
8021
8022	// #7653, #8125, #8152: local protocol detection
8023	rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
8024	rnoContent = /^(?:GET|HEAD)$/,
8025	rprotocol = /^\/\//,
8026
8027	/* Prefilters
8028	 * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
8029	 * 2) These are called:
8030	 *    - BEFORE asking for a transport
8031	 *    - AFTER param serialization (s.data is a string if s.processData is true)
8032	 * 3) key is the dataType
8033	 * 4) the catchall symbol "*" can be used
8034	 * 5) execution will start with transport dataType and THEN continue down to "*" if needed
8035	 */
8036	prefilters = {},
8037
8038	/* Transports bindings
8039	 * 1) key is the dataType
8040	 * 2) the catchall symbol "*" can be used
8041	 * 3) selection will start with transport dataType and THEN go to "*" if needed
8042	 */
8043	transports = {},
8044
8045	// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
8046	allTypes = "*/".concat( "*" ),
8047
8048	// Anchor tag for parsing the document origin
8049	originAnchor = document.createElement( "a" );
8050	originAnchor.href = location.href;
8051
8052// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
8053function addToPrefiltersOrTransports( structure ) {
8054
8055	// dataTypeExpression is optional and defaults to "*"
8056	return function( dataTypeExpression, func ) {
8057
8058		if ( typeof dataTypeExpression !== "string" ) {
8059			func = dataTypeExpression;
8060			dataTypeExpression = "*";
8061		}
8062
8063		var dataType,
8064			i = 0,
8065			dataTypes = dataTypeExpression.toLowerCase().match( rnotwhite ) || [];
8066
8067		if ( jQuery.isFunction( func ) ) {
8068
8069			// For each dataType in the dataTypeExpression
8070			while ( ( dataType = dataTypes[ i++ ] ) ) {
8071
8072				// Prepend if requested
8073				if ( dataType[ 0 ] === "+" ) {
8074					dataType = dataType.slice( 1 ) || "*";
8075					( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func );
8076
8077				// Otherwise append
8078				} else {
8079					( structure[ dataType ] = structure[ dataType ] || [] ).push( func );
8080				}
8081			}
8082		}
8083	};
8084}
8085
8086// Base inspection function for prefilters and transports
8087function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
8088
8089	var inspected = {},
8090		seekingTransport = ( structure === transports );
8091
8092	function inspect( dataType ) {
8093		var selected;
8094		inspected[ dataType ] = true;
8095		jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
8096			var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
8097			if ( typeof dataTypeOrTransport === "string" &&
8098				!seekingTransport && !inspected[ dataTypeOrTransport ] ) {
8099
8100				options.dataTypes.unshift( dataTypeOrTransport );
8101				inspect( dataTypeOrTransport );
8102				return false;
8103			} else if ( seekingTransport ) {
8104				return !( selected = dataTypeOrTransport );
8105			}
8106		} );
8107		return selected;
8108	}
8109
8110	return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
8111}
8112
8113// A special extend for ajax options
8114// that takes "flat" options (not to be deep extended)
8115// Fixes #9887
8116function ajaxExtend( target, src ) {
8117	var key, deep,
8118		flatOptions = jQuery.ajaxSettings.flatOptions || {};
8119
8120	for ( key in src ) {
8121		if ( src[ key ] !== undefined ) {
8122			( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];
8123		}
8124	}
8125	if ( deep ) {
8126		jQuery.extend( true, target, deep );
8127	}
8128
8129	return target;
8130}
8131
8132/* Handles responses to an ajax request:
8133 * - finds the right dataType (mediates between content-type and expected dataType)
8134 * - returns the corresponding response
8135 */
8136function ajaxHandleResponses( s, jqXHR, responses ) {
8137
8138	var ct, type, finalDataType, firstDataType,
8139		contents = s.contents,
8140		dataTypes = s.dataTypes;
8141
8142	// Remove auto dataType and get content-type in the process
8143	while ( dataTypes[ 0 ] === "*" ) {
8144		dataTypes.shift();
8145		if ( ct === undefined ) {
8146			ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" );
8147		}
8148	}
8149
8150	// Check if we're dealing with a known content-type
8151	if ( ct ) {
8152		for ( type in contents ) {
8153			if ( contents[ type ] && contents[ type ].test( ct ) ) {
8154				dataTypes.unshift( type );
8155				break;
8156			}
8157		}
8158	}
8159
8160	// Check to see if we have a response for the expected dataType
8161	if ( dataTypes[ 0 ] in responses ) {
8162		finalDataType = dataTypes[ 0 ];
8163	} else {
8164
8165		// Try convertible dataTypes
8166		for ( type in responses ) {
8167			if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) {
8168				finalDataType = type;
8169				break;
8170			}
8171			if ( !firstDataType ) {
8172				firstDataType = type;
8173			}
8174		}
8175
8176		// Or just use first one
8177		finalDataType = finalDataType || firstDataType;
8178	}
8179
8180	// If we found a dataType
8181	// We add the dataType to the list if needed
8182	// and return the corresponding response
8183	if ( finalDataType ) {
8184		if ( finalDataType !== dataTypes[ 0 ] ) {
8185			dataTypes.unshift( finalDataType );
8186		}
8187		return responses[ finalDataType ];
8188	}
8189}
8190
8191/* Chain conversions given the request and the original response
8192 * Also sets the responseXXX fields on the jqXHR instance
8193 */
8194function ajaxConvert( s, response, jqXHR, isSuccess ) {
8195	var conv2, current, conv, tmp, prev,
8196		converters = {},
8197
8198		// Work with a copy of dataTypes in case we need to modify it for conversion
8199		dataTypes = s.dataTypes.slice();
8200
8201	// Create converters map with lowercased keys
8202	if ( dataTypes[ 1 ] ) {
8203		for ( conv in s.converters ) {
8204			converters[ conv.toLowerCase() ] = s.converters[ conv ];
8205		}
8206	}
8207
8208	current = dataTypes.shift();
8209
8210	// Convert to each sequential dataType
8211	while ( current ) {
8212
8213		if ( s.responseFields[ current ] ) {
8214			jqXHR[ s.responseFields[ current ] ] = response;
8215		}
8216
8217		// Apply the dataFilter if provided
8218		if ( !prev && isSuccess && s.dataFilter ) {
8219			response = s.dataFilter( response, s.dataType );
8220		}
8221
8222		prev = current;
8223		current = dataTypes.shift();
8224
8225		if ( current ) {
8226
8227		// There's only work to do if current dataType is non-auto
8228			if ( current === "*" ) {
8229
8230				current = prev;
8231
8232			// Convert response if prev dataType is non-auto and differs from current
8233			} else if ( prev !== "*" && prev !== current ) {
8234
8235				// Seek a direct converter
8236				conv = converters[ prev + " " + current ] || converters[ "* " + current ];
8237
8238				// If none found, seek a pair
8239				if ( !conv ) {
8240					for ( conv2 in converters ) {
8241
8242						// If conv2 outputs current
8243						tmp = conv2.split( " " );
8244						if ( tmp[ 1 ] === current ) {
8245
8246							// If prev can be converted to accepted input
8247							conv = converters[ prev + " " + tmp[ 0 ] ] ||
8248								converters[ "* " + tmp[ 0 ] ];
8249							if ( conv ) {
8250
8251								// Condense equivalence converters
8252								if ( conv === true ) {
8253									conv = converters[ conv2 ];
8254
8255								// Otherwise, insert the intermediate dataType
8256								} else if ( converters[ conv2 ] !== true ) {
8257									current = tmp[ 0 ];
8258									dataTypes.unshift( tmp[ 1 ] );
8259								}
8260								break;
8261							}
8262						}
8263					}
8264				}
8265
8266				// Apply converter (if not an equivalence)
8267				if ( conv !== true ) {
8268
8269					// Unless errors are allowed to bubble, catch and return them
8270					if ( conv && s.throws ) {
8271						response = conv( response );
8272					} else {
8273						try {
8274							response = conv( response );
8275						} catch ( e ) {
8276							return {
8277								state: "parsererror",
8278								error: conv ? e : "No conversion from " + prev + " to " + current
8279							};
8280						}
8281					}
8282				}
8283			}
8284		}
8285	}
8286
8287	return { state: "success", data: response };
8288}
8289
8290jQuery.extend( {
8291
8292	// Counter for holding the number of active queries
8293	active: 0,
8294
8295	// Last-Modified header cache for next request
8296	lastModified: {},
8297	etag: {},
8298
8299	ajaxSettings: {
8300		url: location.href,
8301		type: "GET",
8302		isLocal: rlocalProtocol.test( location.protocol ),
8303		global: true,
8304		processData: true,
8305		async: true,
8306		contentType: "application/x-www-form-urlencoded; charset=UTF-8",
8307		/*
8308		timeout: 0,
8309		data: null,
8310		dataType: null,
8311		username: null,
8312		password: null,
8313		cache: null,
8314		throws: false,
8315		traditional: false,
8316		headers: {},
8317		*/
8318
8319		accepts: {
8320			"*": allTypes,
8321			text: "text/plain",
8322			html: "text/html",
8323			xml: "application/xml, text/xml",
8324			json: "application/json, text/javascript"
8325		},
8326
8327		contents: {
8328			xml: /\bxml\b/,
8329			html: /\bhtml/,
8330			json: /\bjson\b/
8331		},
8332
8333		responseFields: {
8334			xml: "responseXML",
8335			text: "responseText",
8336			json: "responseJSON"
8337		},
8338
8339		// Data converters
8340		// Keys separate source (or catchall "*") and destination types with a single space
8341		converters: {
8342
8343			// Convert anything to text
8344			"* text": String,
8345
8346			// Text to html (true = no transformation)
8347			"text html": true,
8348
8349			// Evaluate text as a json expression
8350			"text json": jQuery.parseJSON,
8351
8352			// Parse text as xml
8353			"text xml": jQuery.parseXML
8354		},
8355
8356		// For options that shouldn't be deep extended:
8357		// you can add your own custom options here if
8358		// and when you create one that shouldn't be
8359		// deep extended (see ajaxExtend)
8360		flatOptions: {
8361			url: true,
8362			context: true
8363		}
8364	},
8365
8366	// Creates a full fledged settings object into target
8367	// with both ajaxSettings and settings fields.
8368	// If target is omitted, writes into ajaxSettings.
8369	ajaxSetup: function( target, settings ) {
8370		return settings ?
8371
8372			// Building a settings object
8373			ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
8374
8375			// Extending ajaxSettings
8376			ajaxExtend( jQuery.ajaxSettings, target );
8377	},
8378
8379	ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
8380	ajaxTransport: addToPrefiltersOrTransports( transports ),
8381
8382	// Main method
8383	ajax: function( url, options ) {
8384
8385		// If url is an object, simulate pre-1.5 signature
8386		if ( typeof url === "object" ) {
8387			options = url;
8388			url = undefined;
8389		}
8390
8391		// Force options to be an object
8392		options = options || {};
8393
8394		var transport,
8395
8396			// URL without anti-cache param
8397			cacheURL,
8398
8399			// Response headers
8400			responseHeadersString,
8401			responseHeaders,
8402
8403			// timeout handle
8404			timeoutTimer,
8405
8406			// Url cleanup var
8407			urlAnchor,
8408
8409			// To know if global events are to be dispatched
8410			fireGlobals,
8411
8412			// Loop variable
8413			i,
8414
8415			// Create the final options object
8416			s = jQuery.ajaxSetup( {}, options ),
8417
8418			// Callbacks context
8419			callbackContext = s.context || s,
8420
8421			// Context for global events is callbackContext if it is a DOM node or jQuery collection
8422			globalEventContext = s.context &&
8423				( callbackContext.nodeType || callbackContext.jquery ) ?
8424					jQuery( callbackContext ) :
8425					jQuery.event,
8426
8427			// Deferreds
8428			deferred = jQuery.Deferred(),
8429			completeDeferred = jQuery.Callbacks( "once memory" ),
8430
8431			// Status-dependent callbacks
8432			statusCode = s.statusCode || {},
8433
8434			// Headers (they are sent all at once)
8435			requestHeaders = {},
8436			requestHeadersNames = {},
8437
8438			// The jqXHR state
8439			state = 0,
8440
8441			// Default abort message
8442			strAbort = "canceled",
8443
8444			// Fake xhr
8445			jqXHR = {
8446				readyState: 0,
8447
8448				// Builds headers hashtable if needed
8449				getResponseHeader: function( key ) {
8450					var match;
8451					if ( state === 2 ) {
8452						if ( !responseHeaders ) {
8453							responseHeaders = {};
8454							while ( ( match = rheaders.exec( responseHeadersString ) ) ) {
8455								responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ];
8456							}
8457						}
8458						match = responseHeaders[ key.toLowerCase() ];
8459					}
8460					return match == null ? null : match;
8461				},
8462
8463				// Raw string
8464				getAllResponseHeaders: function() {
8465					return state === 2 ? responseHeadersString : null;
8466				},
8467
8468				// Caches the header
8469				setRequestHeader: function( name, value ) {
8470					var lname = name.toLowerCase();
8471					if ( !state ) {
8472						name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
8473						requestHeaders[ name ] = value;
8474					}
8475					return this;
8476				},
8477
8478				// Overrides response content-type header
8479				overrideMimeType: function( type ) {
8480					if ( !state ) {
8481						s.mimeType = type;
8482					}
8483					return this;
8484				},
8485
8486				// Status-dependent callbacks
8487				statusCode: function( map ) {
8488					var code;
8489					if ( map ) {
8490						if ( state < 2 ) {
8491							for ( code in map ) {
8492
8493								// Lazy-add the new callback in a way that preserves old ones
8494								statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
8495							}
8496						} else {
8497
8498							// Execute the appropriate callbacks
8499							jqXHR.always( map[ jqXHR.status ] );
8500						}
8501					}
8502					return this;
8503				},
8504
8505				// Cancel the request
8506				abort: function( statusText ) {
8507					var finalText = statusText || strAbort;
8508					if ( transport ) {
8509						transport.abort( finalText );
8510					}
8511					done( 0, finalText );
8512					return this;
8513				}
8514			};
8515
8516		// Attach deferreds
8517		deferred.promise( jqXHR ).complete = completeDeferred.add;
8518		jqXHR.success = jqXHR.done;
8519		jqXHR.error = jqXHR.fail;
8520
8521		// Remove hash character (#7531: and string promotion)
8522		// Add protocol if not provided (prefilters might expect it)
8523		// Handle falsy url in the settings object (#10093: consistency with old signature)
8524		// We also use the url parameter if available
8525		s.url = ( ( url || s.url || location.href ) + "" ).replace( rhash, "" )
8526			.replace( rprotocol, location.protocol + "//" );
8527
8528		// Alias method option to type as per ticket #12004
8529		s.type = options.method || options.type || s.method || s.type;
8530
8531		// Extract dataTypes list
8532		s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( rnotwhite ) || [ "" ];
8533
8534		// A cross-domain request is in order when the origin doesn't match the current origin.
8535		if ( s.crossDomain == null ) {
8536			urlAnchor = document.createElement( "a" );
8537
8538			// Support: IE8-11+
8539			// IE throws exception if url is malformed, e.g. http://example.com:80x/
8540			try {
8541				urlAnchor.href = s.url;
8542
8543				// Support: IE8-11+
8544				// Anchor's host property isn't correctly set when s.url is relative
8545				urlAnchor.href = urlAnchor.href;
8546				s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !==
8547					urlAnchor.protocol + "//" + urlAnchor.host;
8548			} catch ( e ) {
8549
8550				// If there is an error parsing the URL, assume it is crossDomain,
8551				// it can be rejected by the transport if it is invalid
8552				s.crossDomain = true;
8553			}
8554		}
8555
8556		// Convert data if not already a string
8557		if ( s.data && s.processData && typeof s.data !== "string" ) {
8558			s.data = jQuery.param( s.data, s.traditional );
8559		}
8560
8561		// Apply prefilters
8562		inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
8563
8564		// If request was aborted inside a prefilter, stop there
8565		if ( state === 2 ) {
8566			return jqXHR;
8567		}
8568
8569		// We can fire global events as of now if asked to
8570		// Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118)
8571		fireGlobals = jQuery.event && s.global;
8572
8573		// Watch for a new set of requests
8574		if ( fireGlobals && jQuery.active++ === 0 ) {
8575			jQuery.event.trigger( "ajaxStart" );
8576		}
8577
8578		// Uppercase the type
8579		s.type = s.type.toUpperCase();
8580
8581		// Determine if request has content
8582		s.hasContent = !rnoContent.test( s.type );
8583
8584		// Save the URL in case we're toying with the If-Modified-Since
8585		// and/or If-None-Match header later on
8586		cacheURL = s.url;
8587
8588		// More options handling for requests with no content
8589		if ( !s.hasContent ) {
8590
8591			// If data is available, append data to url
8592			if ( s.data ) {
8593				cacheURL = ( s.url += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data );
8594
8595				// #9682: remove data so that it's not used in an eventual retry
8596				delete s.data;
8597			}
8598
8599			// Add anti-cache in url if needed
8600			if ( s.cache === false ) {
8601				s.url = rts.test( cacheURL ) ?
8602
8603					// If there is already a '_' parameter, set its value
8604					cacheURL.replace( rts, "$1_=" + nonce++ ) :
8605
8606					// Otherwise add one to the end
8607					cacheURL + ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + nonce++;
8608			}
8609		}
8610
8611		// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
8612		if ( s.ifModified ) {
8613			if ( jQuery.lastModified[ cacheURL ] ) {
8614				jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
8615			}
8616			if ( jQuery.etag[ cacheURL ] ) {
8617				jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
8618			}
8619		}
8620
8621		// Set the correct header, if data is being sent
8622		if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
8623			jqXHR.setRequestHeader( "Content-Type", s.contentType );
8624		}
8625
8626		// Set the Accepts header for the server, depending on the dataType
8627		jqXHR.setRequestHeader(
8628			"Accept",
8629			s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ?
8630				s.accepts[ s.dataTypes[ 0 ] ] +
8631					( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
8632				s.accepts[ "*" ]
8633		);
8634
8635		// Check for headers option
8636		for ( i in s.headers ) {
8637			jqXHR.setRequestHeader( i, s.headers[ i ] );
8638		}
8639
8640		// Allow custom headers/mimetypes and early abort
8641		if ( s.beforeSend &&
8642			( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
8643
8644			// Abort if not done already and return
8645			return jqXHR.abort();
8646		}
8647
8648		// Aborting is no longer a cancellation
8649		strAbort = "abort";
8650
8651		// Install callbacks on deferreds
8652		for ( i in { success: 1, error: 1, complete: 1 } ) {
8653			jqXHR[ i ]( s[ i ] );
8654		}
8655
8656		// Get transport
8657		transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
8658
8659		// If no transport, we auto-abort
8660		if ( !transport ) {
8661			done( -1, "No Transport" );
8662		} else {
8663			jqXHR.readyState = 1;
8664
8665			// Send global event
8666			if ( fireGlobals ) {
8667				globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
8668			}
8669
8670			// If request was aborted inside ajaxSend, stop there
8671			if ( state === 2 ) {
8672				return jqXHR;
8673			}
8674
8675			// Timeout
8676			if ( s.async && s.timeout > 0 ) {
8677				timeoutTimer = window.setTimeout( function() {
8678					jqXHR.abort( "timeout" );
8679				}, s.timeout );
8680			}
8681
8682			try {
8683				state = 1;
8684				transport.send( requestHeaders, done );
8685			} catch ( e ) {
8686
8687				// Propagate exception as error if not done
8688				if ( state < 2 ) {
8689					done( -1, e );
8690
8691				// Simply rethrow otherwise
8692				} else {
8693					throw e;
8694				}
8695			}
8696		}
8697
8698		// Callback for when everything is done
8699		function done( status, nativeStatusText, responses, headers ) {
8700			var isSuccess, success, error, response, modified,
8701				statusText = nativeStatusText;
8702
8703			// Called once
8704			if ( state === 2 ) {
8705				return;
8706			}
8707
8708			// State is "done" now
8709			state = 2;
8710
8711			// Clear timeout if it exists
8712			if ( timeoutTimer ) {
8713				window.clearTimeout( timeoutTimer );
8714			}
8715
8716			// Dereference transport for early garbage collection
8717			// (no matter how long the jqXHR object will be used)
8718			transport = undefined;
8719
8720			// Cache response headers
8721			responseHeadersString = headers || "";
8722
8723			// Set readyState
8724			jqXHR.readyState = status > 0 ? 4 : 0;
8725
8726			// Determine if successful
8727			isSuccess = status >= 200 && status < 300 || status === 304;
8728
8729			// Get response data
8730			if ( responses ) {
8731				response = ajaxHandleResponses( s, jqXHR, responses );
8732			}
8733
8734			// Convert no matter what (that way responseXXX fields are always set)
8735			response = ajaxConvert( s, response, jqXHR, isSuccess );
8736
8737			// If successful, handle type chaining
8738			if ( isSuccess ) {
8739
8740				// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
8741				if ( s.ifModified ) {
8742					modified = jqXHR.getResponseHeader( "Last-Modified" );
8743					if ( modified ) {
8744						jQuery.lastModified[ cacheURL ] = modified;
8745					}
8746					modified = jqXHR.getResponseHeader( "etag" );
8747					if ( modified ) {
8748						jQuery.etag[ cacheURL ] = modified;
8749					}
8750				}
8751
8752				// if no content
8753				if ( status === 204 || s.type === "HEAD" ) {
8754					statusText = "nocontent";
8755
8756				// if not modified
8757				} else if ( status === 304 ) {
8758					statusText = "notmodified";
8759
8760				// If we have data, let's convert it
8761				} else {
8762					statusText = response.state;
8763					success = response.data;
8764					error = response.error;
8765					isSuccess = !error;
8766				}
8767			} else {
8768
8769				// Extract error from statusText and normalize for non-aborts
8770				error = statusText;
8771				if ( status || !statusText ) {
8772					statusText = "error";
8773					if ( status < 0 ) {
8774						status = 0;
8775					}
8776				}
8777			}
8778
8779			// Set data for the fake xhr object
8780			jqXHR.status = status;
8781			jqXHR.statusText = ( nativeStatusText || statusText ) + "";
8782
8783			// Success/Error
8784			if ( isSuccess ) {
8785				deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
8786			} else {
8787				deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
8788			}
8789
8790			// Status-dependent callbacks
8791			jqXHR.statusCode( statusCode );
8792			statusCode = undefined;
8793
8794			if ( fireGlobals ) {
8795				globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
8796					[ jqXHR, s, isSuccess ? success : error ] );
8797			}
8798
8799			// Complete
8800			completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
8801
8802			if ( fireGlobals ) {
8803				globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
8804
8805				// Handle the global AJAX counter
8806				if ( !( --jQuery.active ) ) {
8807					jQuery.event.trigger( "ajaxStop" );
8808				}
8809			}
8810		}
8811
8812		return jqXHR;
8813	},
8814
8815	getJSON: function( url, data, callback ) {
8816		return jQuery.get( url, data, callback, "json" );
8817	},
8818
8819	getScript: function( url, callback ) {
8820		return jQuery.get( url, undefined, callback, "script" );
8821	}
8822} );
8823
8824jQuery.each( [ "get", "post" ], function( i, method ) {
8825	jQuery[ method ] = function( url, data, callback, type ) {
8826
8827		// Shift arguments if data argument was omitted
8828		if ( jQuery.isFunction( data ) ) {
8829			type = type || callback;
8830			callback = data;
8831			data = undefined;
8832		}
8833
8834		// The url can be an options object (which then must have .url)
8835		return jQuery.ajax( jQuery.extend( {
8836			url: url,
8837			type: method,
8838			dataType: type,
8839			data: data,
8840			success: callback
8841		}, jQuery.isPlainObject( url ) && url ) );
8842	};
8843} );
8844
8845
8846jQuery._evalUrl = function( url ) {
8847	return jQuery.ajax( {
8848		url: url,
8849
8850		// Make this explicit, since user can override this through ajaxSetup (#11264)
8851		type: "GET",
8852		dataType: "script",
8853		async: false,
8854		global: false,
8855		"throws": true
8856	} );
8857};
8858
8859
8860jQuery.fn.extend( {
8861	wrapAll: function( html ) {
8862		var wrap;
8863
8864		if ( jQuery.isFunction( html ) ) {
8865			return this.each( function( i ) {
8866				jQuery( this ).wrapAll( html.call( this, i ) );
8867			} );
8868		}
8869
8870		if ( this[ 0 ] ) {
8871
8872			// The elements to wrap the target around
8873			wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );
8874
8875			if ( this[ 0 ].parentNode ) {
8876				wrap.insertBefore( this[ 0 ] );
8877			}
8878
8879			wrap.map( function() {
8880				var elem = this;
8881
8882				while ( elem.firstElementChild ) {
8883					elem = elem.firstElementChild;
8884				}
8885
8886				return elem;
8887			} ).append( this );
8888		}
8889
8890		return this;
8891	},
8892
8893	wrapInner: function( html ) {
8894		if ( jQuery.isFunction( html ) ) {
8895			return this.each( function( i ) {
8896				jQuery( this ).wrapInner( html.call( this, i ) );
8897			} );
8898		}
8899
8900		return this.each( function() {
8901			var self = jQuery( this ),
8902				contents = self.contents();
8903
8904			if ( contents.length ) {
8905				contents.wrapAll( html );
8906
8907			} else {
8908				self.append( html );
8909			}
8910		} );
8911	},
8912
8913	wrap: function( html ) {
8914		var isFunction = jQuery.isFunction( html );
8915
8916		return this.each( function( i ) {
8917			jQuery( this ).wrapAll( isFunction ? html.call( this, i ) : html );
8918		} );
8919	},
8920
8921	unwrap: function() {
8922		return this.parent().each( function() {
8923			if ( !jQuery.nodeName( this, "body" ) ) {
8924				jQuery( this ).replaceWith( this.childNodes );
8925			}
8926		} ).end();
8927	}
8928} );
8929
8930
8931jQuery.expr.filters.hidden = function( elem ) {
8932	return !jQuery.expr.filters.visible( elem );
8933};
8934jQuery.expr.filters.visible = function( elem ) {
8935
8936	// Support: Opera <= 12.12
8937	// Opera reports offsetWidths and offsetHeights less than zero on some elements
8938	// Use OR instead of AND as the element is not visible if either is true
8939	// See tickets #10406 and #13132
8940	return elem.offsetWidth > 0 || elem.offsetHeight > 0 || elem.getClientRects().length > 0;
8941};
8942
8943
8944
8945
8946var r20 = /%20/g,
8947	rbracket = /\[\]$/,
8948	rCRLF = /\r?\n/g,
8949	rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
8950	rsubmittable = /^(?:input|select|textarea|keygen)/i;
8951
8952function buildParams( prefix, obj, traditional, add ) {
8953	var name;
8954
8955	if ( jQuery.isArray( obj ) ) {
8956
8957		// Serialize array item.
8958		jQuery.each( obj, function( i, v ) {
8959			if ( traditional || rbracket.test( prefix ) ) {
8960
8961				// Treat each array item as a scalar.
8962				add( prefix, v );
8963
8964			} else {
8965
8966				// Item is non-scalar (array or object), encode its numeric index.
8967				buildParams(
8968					prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]",
8969					v,
8970					traditional,
8971					add
8972				);
8973			}
8974		} );
8975
8976	} else if ( !traditional && jQuery.type( obj ) === "object" ) {
8977
8978		// Serialize object item.
8979		for ( name in obj ) {
8980			buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
8981		}
8982
8983	} else {
8984
8985		// Serialize scalar item.
8986		add( prefix, obj );
8987	}
8988}
8989
8990// Serialize an array of form elements or a set of
8991// key/values into a query string
8992jQuery.param = function( a, traditional ) {
8993	var prefix,
8994		s = [],
8995		add = function( key, value ) {
8996
8997			// If value is a function, invoke it and return its value
8998			value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
8999			s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
9000		};
9001
9002	// Set traditional to true for jQuery <= 1.3.2 behavior.
9003	if ( traditional === undefined ) {
9004		traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
9005	}
9006
9007	// If an array was passed in, assume that it is an array of form elements.
9008	if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
9009
9010		// Serialize the form elements
9011		jQuery.each( a, function() {
9012			add( this.name, this.value );
9013		} );
9014
9015	} else {
9016
9017		// If traditional, encode the "old" way (the way 1.3.2 or older
9018		// did it), otherwise encode params recursively.
9019		for ( prefix in a ) {
9020			buildParams( prefix, a[ prefix ], traditional, add );
9021		}
9022	}
9023
9024	// Return the resulting serialization
9025	return s.join( "&" ).replace( r20, "+" );
9026};
9027
9028jQuery.fn.extend( {
9029	serialize: function() {
9030		return jQuery.param( this.serializeArray() );
9031	},
9032	serializeArray: function() {
9033		return this.map( function() {
9034
9035			// Can add propHook for "elements" to filter or add form elements
9036			var elements = jQuery.prop( this, "elements" );
9037			return elements ? jQuery.makeArray( elements ) : this;
9038		} )
9039		.filter( function() {
9040			var type = this.type;
9041
9042			// Use .is( ":disabled" ) so that fieldset[disabled] works
9043			return this.name && !jQuery( this ).is( ":disabled" ) &&
9044				rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
9045				( this.checked || !rcheckableType.test( type ) );
9046		} )
9047		.map( function( i, elem ) {
9048			var val = jQuery( this ).val();
9049
9050			return val == null ?
9051				null :
9052				jQuery.isArray( val ) ?
9053					jQuery.map( val, function( val ) {
9054						return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
9055					} ) :
9056					{ name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
9057		} ).get();
9058	}
9059} );
9060
9061
9062jQuery.ajaxSettings.xhr = function() {
9063	try {
9064		return new window.XMLHttpRequest();
9065	} catch ( e ) {}
9066};
9067
9068var xhrSuccessStatus = {
9069
9070		// File protocol always yields status code 0, assume 200
9071		0: 200,
9072
9073		// Support: IE9
9074		// #1450: sometimes IE returns 1223 when it should be 204
9075		1223: 204
9076	},
9077	xhrSupported = jQuery.ajaxSettings.xhr();
9078
9079support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
9080support.ajax = xhrSupported = !!xhrSupported;
9081
9082jQuery.ajaxTransport( function( options ) {
9083	var callback, errorCallback;
9084
9085	// Cross domain only allowed if supported through XMLHttpRequest
9086	if ( support.cors || xhrSupported && !options.crossDomain ) {
9087		return {
9088			send: function( headers, complete ) {
9089				var i,
9090					xhr = options.xhr();
9091
9092				xhr.open(
9093					options.type,
9094					options.url,
9095					options.async,
9096					options.username,
9097					options.password
9098				);
9099
9100				// Apply custom fields if provided
9101				if ( options.xhrFields ) {
9102					for ( i in options.xhrFields ) {
9103						xhr[ i ] = options.xhrFields[ i ];
9104					}
9105				}
9106
9107				// Override mime type if needed
9108				if ( options.mimeType && xhr.overrideMimeType ) {
9109					xhr.overrideMimeType( options.mimeType );
9110				}
9111
9112				// X-Requested-With header
9113				// For cross-domain requests, seeing as conditions for a preflight are
9114				// akin to a jigsaw puzzle, we simply never set it to be sure.
9115				// (it can always be set on a per-request basis or even using ajaxSetup)
9116				// For same-domain requests, won't change header if already provided.
9117				if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) {
9118					headers[ "X-Requested-With" ] = "XMLHttpRequest";
9119				}
9120
9121				// Set headers
9122				for ( i in headers ) {
9123					xhr.setRequestHeader( i, headers[ i ] );
9124				}
9125
9126				// Callback
9127				callback = function( type ) {
9128					return function() {
9129						if ( callback ) {
9130							callback = errorCallback = xhr.onload =
9131								xhr.onerror = xhr.onabort = xhr.onreadystatechange = null;
9132
9133							if ( type === "abort" ) {
9134								xhr.abort();
9135							} else if ( type === "error" ) {
9136
9137								// Support: IE9
9138								// On a manual native abort, IE9 throws
9139								// errors on any property access that is not readyState
9140								if ( typeof xhr.status !== "number" ) {
9141									complete( 0, "error" );
9142								} else {
9143									complete(
9144
9145										// File: protocol always yields status 0; see #8605, #14207
9146										xhr.status,
9147										xhr.statusText
9148									);
9149								}
9150							} else {
9151								complete(
9152									xhrSuccessStatus[ xhr.status ] || xhr.status,
9153									xhr.statusText,
9154
9155									// Support: IE9 only
9156									// IE9 has no XHR2 but throws on binary (trac-11426)
9157									// For XHR2 non-text, let the caller handle it (gh-2498)
9158									( xhr.responseType || "text" ) !== "text"  ||
9159									typeof xhr.responseText !== "string" ?
9160										{ binary: xhr.response } :
9161										{ text: xhr.responseText },
9162									xhr.getAllResponseHeaders()
9163								);
9164							}
9165						}
9166					};
9167				};
9168
9169				// Listen to events
9170				xhr.onload = callback();
9171				errorCallback = xhr.onerror = callback( "error" );
9172
9173				// Support: IE9
9174				// Use onreadystatechange to replace onabort
9175				// to handle uncaught aborts
9176				if ( xhr.onabort !== undefined ) {
9177					xhr.onabort = errorCallback;
9178				} else {
9179					xhr.onreadystatechange = function() {
9180
9181						// Check readyState before timeout as it changes
9182						if ( xhr.readyState === 4 ) {
9183
9184							// Allow onerror to be called first,
9185							// but that will not handle a native abort
9186							// Also, save errorCallback to a variable
9187							// as xhr.onerror cannot be accessed
9188							window.setTimeout( function() {
9189								if ( callback ) {
9190									errorCallback();
9191								}
9192							} );
9193						}
9194					};
9195				}
9196
9197				// Create the abort callback
9198				callback = callback( "abort" );
9199
9200				try {
9201
9202					// Do send the request (this may raise an exception)
9203					xhr.send( options.hasContent && options.data || null );
9204				} catch ( e ) {
9205
9206					// #14683: Only rethrow if this hasn't been notified as an error yet
9207					if ( callback ) {
9208						throw e;
9209					}
9210				}
9211			},
9212
9213			abort: function() {
9214				if ( callback ) {
9215					callback();
9216				}
9217			}
9218		};
9219	}
9220} );
9221
9222
9223
9224
9225// Install script dataType
9226jQuery.ajaxSetup( {
9227	accepts: {
9228		script: "text/javascript, application/javascript, " +
9229			"application/ecmascript, application/x-ecmascript"
9230	},
9231	contents: {
9232		script: /\b(?:java|ecma)script\b/
9233	},
9234	converters: {
9235		"text script": function( text ) {
9236			jQuery.globalEval( text );
9237			return text;
9238		}
9239	}
9240} );
9241
9242// Handle cache's special case and crossDomain
9243jQuery.ajaxPrefilter( "script", function( s ) {
9244	if ( s.cache === undefined ) {
9245		s.cache = false;
9246	}
9247	if ( s.crossDomain ) {
9248		s.type = "GET";
9249	}
9250} );
9251
9252// Bind script tag hack transport
9253jQuery.ajaxTransport( "script", function( s ) {
9254
9255	// This transport only deals with cross domain requests
9256	if ( s.crossDomain ) {
9257		var script, callback;
9258		return {
9259			send: function( _, complete ) {
9260				script = jQuery( "<script>" ).prop( {
9261					charset: s.scriptCharset,
9262					src: s.url
9263				} ).on(
9264					"load error",
9265					callback = function( evt ) {
9266						script.remove();
9267						callback = null;
9268						if ( evt ) {
9269							complete( evt.type === "error" ? 404 : 200, evt.type );
9270						}
9271					}
9272				);
9273
9274				// Use native DOM manipulation to avoid our domManip AJAX trickery
9275				document.head.appendChild( script[ 0 ] );
9276			},
9277			abort: function() {
9278				if ( callback ) {
9279					callback();
9280				}
9281			}
9282		};
9283	}
9284} );
9285
9286
9287
9288
9289var oldCallbacks = [],
9290	rjsonp = /(=)\?(?=&|$)|\?\?/;
9291
9292// Default jsonp settings
9293jQuery.ajaxSetup( {
9294	jsonp: "callback",
9295	jsonpCallback: function() {
9296		var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) );
9297		this[ callback ] = true;
9298		return callback;
9299	}
9300} );
9301
9302// Detect, normalize options and install callbacks for jsonp requests
9303jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
9304
9305	var callbackName, overwritten, responseContainer,
9306		jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
9307			"url" :
9308			typeof s.data === "string" &&
9309				( s.contentType || "" )
9310					.indexOf( "application/x-www-form-urlencoded" ) === 0 &&
9311				rjsonp.test( s.data ) && "data"
9312		);
9313
9314	// Handle iff the expected data type is "jsonp" or we have a parameter to set
9315	if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
9316
9317		// Get callback name, remembering preexisting value associated with it
9318		callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
9319			s.jsonpCallback() :
9320			s.jsonpCallback;
9321
9322		// Insert callback into url or form data
9323		if ( jsonProp ) {
9324			s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
9325		} else if ( s.jsonp !== false ) {
9326			s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
9327		}
9328
9329		// Use data converter to retrieve json after script execution
9330		s.converters[ "script json" ] = function() {
9331			if ( !responseContainer ) {
9332				jQuery.error( callbackName + " was not called" );
9333			}
9334			return responseContainer[ 0 ];
9335		};
9336
9337		// Force json dataType
9338		s.dataTypes[ 0 ] = "json";
9339
9340		// Install callback
9341		overwritten = window[ callbackName ];
9342		window[ callbackName ] = function() {
9343			responseContainer = arguments;
9344		};
9345
9346		// Clean-up function (fires after converters)
9347		jqXHR.always( function() {
9348
9349			// If previous value didn't exist - remove it
9350			if ( overwritten === undefined ) {
9351				jQuery( window ).removeProp( callbackName );
9352
9353			// Otherwise restore preexisting value
9354			} else {
9355				window[ callbackName ] = overwritten;
9356			}
9357
9358			// Save back as free
9359			if ( s[ callbackName ] ) {
9360
9361				// Make sure that re-using the options doesn't screw things around
9362				s.jsonpCallback = originalSettings.jsonpCallback;
9363
9364				// Save the callback name for future use
9365				oldCallbacks.push( callbackName );
9366			}
9367
9368			// Call if it was a function and we have a response
9369			if ( responseContainer && jQuery.isFunction( overwritten ) ) {
9370				overwritten( responseContainer[ 0 ] );
9371			}
9372
9373			responseContainer = overwritten = undefined;
9374		} );
9375
9376		// Delegate to script
9377		return "script";
9378	}
9379} );
9380
9381
9382
9383
9384// Argument "data" should be string of html
9385// context (optional): If specified, the fragment will be created in this context,
9386// defaults to document
9387// keepScripts (optional): If true, will include scripts passed in the html string
9388jQuery.parseHTML = function( data, context, keepScripts ) {
9389	if ( !data || typeof data !== "string" ) {
9390		return null;
9391	}
9392	if ( typeof context === "boolean" ) {
9393		keepScripts = context;
9394		context = false;
9395	}
9396	context = context || document;
9397
9398	var parsed = rsingleTag.exec( data ),
9399		scripts = !keepScripts && [];
9400
9401	// Single tag
9402	if ( parsed ) {
9403		return [ context.createElement( parsed[ 1 ] ) ];
9404	}
9405
9406	parsed = buildFragment( [ data ], context, scripts );
9407
9408	if ( scripts && scripts.length ) {
9409		jQuery( scripts ).remove();
9410	}
9411
9412	return jQuery.merge( [], parsed.childNodes );
9413};
9414
9415
9416// Keep a copy of the old load method
9417var _load = jQuery.fn.load;
9418
9419/**
9420 * Load a url into a page
9421 */
9422jQuery.fn.load = function( url, params, callback ) {
9423	if ( typeof url !== "string" && _load ) {
9424		return _load.apply( this, arguments );
9425	}
9426
9427	var selector, type, response,
9428		self = this,
9429		off = url.indexOf( " " );
9430
9431	if ( off > -1 ) {
9432		selector = jQuery.trim( url.slice( off ) );
9433		url = url.slice( 0, off );
9434	}
9435
9436	// If it's a function
9437	if ( jQuery.isFunction( params ) ) {
9438
9439		// We assume that it's the callback
9440		callback = params;
9441		params = undefined;
9442
9443	// Otherwise, build a param string
9444	} else if ( params && typeof params === "object" ) {
9445		type = "POST";
9446	}
9447
9448	// If we have elements to modify, make the request
9449	if ( self.length > 0 ) {
9450		jQuery.ajax( {
9451			url: url,
9452
9453			// If "type" variable is undefined, then "GET" method will be used.
9454			// Make value of this field explicit since
9455			// user can override it through ajaxSetup method
9456			type: type || "GET",
9457			dataType: "html",
9458			data: params
9459		} ).done( function( responseText ) {
9460
9461			// Save response for use in complete callback
9462			response = arguments;
9463
9464			self.html( selector ?
9465
9466				// If a selector was specified, locate the right elements in a dummy div
9467				// Exclude scripts to avoid IE 'Permission Denied' errors
9468				jQuery( "<div>" ).append( jQuery.parseHTML( responseText ) ).find( selector ) :
9469
9470				// Otherwise use the full result
9471				responseText );
9472
9473		// If the request succeeds, this function gets "data", "status", "jqXHR"
9474		// but they are ignored because response was set above.
9475		// If it fails, this function gets "jqXHR", "status", "error"
9476		} ).always( callback && function( jqXHR, status ) {
9477			self.each( function() {
9478				callback.apply( 
9478self
vendor: 9,975 bytes, lines 9478-9843
9478, response || [ jqXHR.responseText, status, jqXHR ] );
9479			} );
9480		} );
9481	}
9482
9483	return this;
9484};
9485
9486
9487
9488
9489// Attach a bunch of functions for handling common AJAX events
9490jQuery.each( [
9491	"ajaxStart",
9492	"ajaxStop",
9493	"ajaxComplete",
9494	"ajaxError",
9495	"ajaxSuccess",
9496	"ajaxSend"
9497], function( i, type ) {
9498	jQuery.fn[ type ] = function( fn ) {
9499		return this.on( type, fn );
9500	};
9501} );
9502
9503
9504
9505
9506jQuery.expr.filters.animated = function( elem ) {
9507	return jQuery.grep( jQuery.timers, function( fn ) {
9508		return elem === fn.elem;
9509	} ).length;
9510};
9511
9512
9513
9514
9515/**
9516 * Gets a window from an element
9517 */
9518function getWindow( elem ) {
9519	return jQuery.isWindow( elem ) ? elem : elem.nodeType === 9 && elem.defaultView;
9520}
9521
9522jQuery.offset = {
9523	setOffset: function( elem, options, i ) {
9524		var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,
9525			position = jQuery.css( elem, "position" ),
9526			curElem = jQuery( elem ),
9527			props = {};
9528
9529		// Set position first, in-case top/left are set even on static elem
9530		if ( position === "static" ) {
9531			elem.style.position = "relative";
9532		}
9533
9534		curOffset = curElem.offset();
9535		curCSSTop = jQuery.css( elem, "top" );
9536		curCSSLeft = jQuery.css( elem, "left" );
9537		calculatePosition = ( position === "absolute" || position === "fixed" ) &&
9538			( curCSSTop + curCSSLeft ).indexOf( "auto" ) > -1;
9539
9540		// Need to be able to calculate position if either
9541		// top or left is auto and position is either absolute or fixed
9542		if ( calculatePosition ) {
9543			curPosition = curElem.position();
9544			curTop = curPosition.top;
9545			curLeft = curPosition.left;
9546
9547		} else {
9548			curTop = parseFloat( curCSSTop ) || 0;
9549			curLeft = parseFloat( curCSSLeft ) || 0;
9550		}
9551
9552		if ( jQuery.isFunction( options ) ) {
9553
9554			// Use jQuery.extend here to allow modification of coordinates argument (gh-1848)
9555			options = options.call( elem, i, jQuery.extend( {}, curOffset ) );
9556		}
9557
9558		if ( options.top != null ) {
9559			props.top = ( options.top - curOffset.top ) + curTop;
9560		}
9561		if ( options.left != null ) {
9562			props.left = ( options.left - curOffset.left ) + curLeft;
9563		}
9564
9565		if ( "using" in options ) {
9566			options.using.call( elem, props );
9567
9568		} else {
9569			curElem.css( props );
9570		}
9571	}
9572};
9573
9574jQuery.fn.extend( {
9575	offset: function( options ) {
9576		if ( arguments.length ) {
9577			return options === undefined ?
9578				this :
9579				this.each( function( i ) {
9580					jQuery.offset.setOffset( this, options, i );
9581				} );
9582		}
9583
9584		var docElem, win,
9585			elem = this[ 0 ],
9586			box = { top: 0, left: 0 },
9587			doc = elem && elem.ownerDocument;
9588
9589		if ( !doc ) {
9590			return;
9591		}
9592
9593		docElem = doc.documentElement;
9594
9595		// Make sure it's not a disconnected DOM node
9596		if ( !jQuery.contains( docElem, elem ) ) {
9597			return box;
9598		}
9599
9600		box = elem.getBoundingClientRect();
9601		win = getWindow( doc );
9602		return {
9603			top: box.top + win.pageYOffset - docElem.clientTop,
9604			left: box.left + win.pageXOffset - docElem.clientLeft
9605		};
9606	},
9607
9608	position: function() {
9609		if ( !this[ 0 ] ) {
9610			return;
9611		}
9612
9613		var offsetParent, offset,
9614			elem = this[ 0 ],
9615			parentOffset = { top: 0, left: 0 };
9616
9617		// Fixed elements are offset from window (parentOffset = {top:0, left: 0},
9618		// because it is its only offset parent
9619		if ( jQuery.css( elem, "position" ) === "fixed" ) {
9620
9621			// Assume getBoundingClientRect is there when computed position is fixed
9622			offset = elem.getBoundingClientRect();
9623
9624		} else {
9625
9626			// Get *real* offsetParent
9627			offsetParent = this.offsetParent();
9628
9629			// Get correct offsets
9630			offset = this.offset();
9631			if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) {
9632				parentOffset = offsetParent.offset();
9633			}
9634
9635			// Add offsetParent borders
9636			parentOffset.top += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true );
9637			parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true );
9638		}
9639
9640		// Subtract parent offsets and element margins
9641		return {
9642			top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
9643			left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true )
9644		};
9645	},
9646
9647	// This method will return documentElement in the following cases:
9648	// 1) For the element inside the iframe without offsetParent, this method will return
9649	//    documentElement of the parent window
9650	// 2) For the hidden or detached element
9651	// 3) For body or html element, i.e. in case of the html node - it will return itself
9652	//
9653	// but those exceptions were never presented as a real life use-cases
9654	// and might be considered as more preferable results.
9655	//
9656	// This logic, however, is not guaranteed and can change at any point in the future
9657	offsetParent: function() {
9658		return this.map( function() {
9659			var offsetParent = this.offsetParent;
9660
9661			while ( offsetParent && jQuery.css( offsetParent, "position" ) === "static" ) {
9662				offsetParent = offsetParent.offsetParent;
9663			}
9664
9665			return offsetParent || documentElement;
9666		} );
9667	}
9668} );
9669
9670// Create scrollLeft and scrollTop methods
9671jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) {
9672	var top = "pageYOffset" === prop;
9673
9674	jQuery.fn[ method ] = function( val ) {
9675		return access( this, function( elem, method, val ) {
9676			var win = getWindow( elem );
9677
9678			if ( val === undefined ) {
9679				return win ? win[ prop ] : elem[ method ];
9680			}
9681
9682			if ( win ) {
9683				win.scrollTo(
9684					!top ? val : win.pageXOffset,
9685					top ? val : win.pageYOffset
9686				);
9687
9688			} else {
9689				elem[ method ] = val;
9690			}
9691		}, method, val, arguments.length );
9692	};
9693} );
9694
9695// Support: Safari<7-8+, Chrome<37-44+
9696// Add the top/left cssHooks using jQuery.fn.position
9697// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
9698// Blink bug: https://code.google.com/p/chromium/issues/detail?id=229280
9699// getComputedStyle returns percent when specified for top/left/bottom/right;
9700// rather than make the css module depend on the offset module, just check for it here
9701jQuery.each( [ "top", "left" ], function( i, prop ) {
9702	jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,
9703		function( elem, computed ) {
9704			if ( computed ) {
9705				computed = curCSS( elem, prop );
9706
9707				// If curCSS returns percentage, fallback to offset
9708				return rnumnonpx.test( computed ) ?
9709					jQuery( elem ).position()[ prop ] + "px" :
9710					computed;
9711			}
9712		}
9713	);
9714} );
9715
9716
9717// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
9718jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
9719	jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name },
9720		function( defaultExtra, funcName ) {
9721
9722		// Margin is only for outerHeight, outerWidth
9723		jQuery.fn[ funcName ] = function( margin, value ) {
9724			var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
9725				extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
9726
9727			return access( this, function( elem, type, value ) {
9728				var doc;
9729
9730				if ( jQuery.isWindow( elem ) ) {
9731
9732					// As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
9733					// isn't a whole lot we can do. See pull request at this URL for discussion:
9734					// https://github.com/jquery/jquery/pull/764
9735					return elem.document.documentElement[ "client" + name ];
9736				}
9737
9738				// Get document width or height
9739				if ( elem.nodeType === 9 ) {
9740					doc = elem.documentElement;
9741
9742					// Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],
9743					// whichever is greatest
9744					return Math.max(
9745						elem.body[ "scroll" + name ], doc[ "scroll" + name ],
9746						elem.body[ "offset" + name ], doc[ "offset" + name ],
9747						doc[ "client" + name ]
9748					);
9749				}
9750
9751				return value === undefined ?
9752
9753					// Get width or height on the element, requesting but not forcing parseFloat
9754					jQuery.css( elem, type, extra ) :
9755
9756					// Set width or height on the element
9757					jQuery.style( elem, type, value, extra );
9758			}, type, chainable ? margin : undefined, chainable, null );
9759		};
9760	} );
9761} );
9762
9763
9764jQuery.fn.extend( {
9765
9766	bind: function( types, data, fn ) {
9767		return this.on( types, null, data, fn );
9768	},
9769	unbind: function( types, fn ) {
9770		return this.off( types, null, fn );
9771	},
9772
9773	delegate: function( selector, types, data, fn ) {
9774		return this.on( types, selector, data, fn );
9775	},
9776	undelegate: function( selector, types, fn ) {
9777
9778		// ( namespace ) or ( selector, types [, fn] )
9779		return arguments.length === 1 ?
9780			this.off( selector, "**" ) :
9781			this.off( types, selector || "**", fn );
9782	},
9783	size: function() {
9784		return this.length;
9785	}
9786} );
9787
9788jQuery.fn.andSelf = jQuery.fn.addBack;
9789
9790
9791
9792
9793// Register as a named AMD module, since jQuery can be concatenated with other
9794// files that may use define, but not via a proper concatenation script that
9795// understands anonymous AMD modules. A named AMD is safest and most robust
9796// way to register. Lowercase jquery is used because AMD module names are
9797// derived from file names, and jQuery is normally delivered in a lowercase
9798// file name. Do this after creating the global so that if an AMD module wants
9799// to call noConflict to hide this version of jQuery, it will work.
9800
9801// Note that for maximum portability, libraries that are not jQuery should
9802// declare themselves as anonymous modules, and avoid setting a global if an
9803// AMD loader is present. jQuery is a special case. For more information, see
9804// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon
9805
9806if ( typeof define === "function" && define.amd ) {
9807	define( "jquery", [], function() {
9808		return jQuery;
9809	} );
9810}
9811
9812
9813
9814var
9815
9816	// Map over jQuery in case of overwrite
9817	_jQuery = window.jQuery,
9818
9819	// Map over the $ in case of overwrite
9820	_$ = window.$;
9821
9822jQuery.noConflict = function( deep ) {
9823	if ( window.$ === jQuery ) {
9824		window.$ = _$;
9825	}
9826
9827	if ( deep && window.jQuery === jQuery ) {
9828		window.jQuery = _jQuery;
9829	}
9830
9831	return jQuery;
9832};
9833
9834// Expose jQuery and $ identifiers, even in AMD
9835// (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
9836// and CommonJS for browser emulators (#13566)
9837if ( !noGlobal ) {
9838	window.jQuery = window.$ = jQuery;
9839}
9840
9841return jQuery;
9842}));
9843
vendor: 4,163 bytes, lines 9844-9989
9844/*!
9845 * Bootstrap v3.3.6 (http://getbootstrap.com)
9846 * Copyright 2011-2015 Twitter, Inc.
9847 * Licensed under the MIT license
9848 */
9849
9850if (typeof jQuery === 'undefined') {
9851  throw new Error('Bootstrap\'s JavaScript requires jQuery')
9852}
9853
9854+function ($) {
9855  'use strict';
9856  var version = $.fn.jquery.split(' ')[0].split('.')
9857  if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1) || (version[0] > 2)) {
9858    throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher, but lower than version 3')
9859  }
9860}(jQuery);
9861
9862/* ========================================================================
9863 * Bootstrap: transition.js v3.3.6
9864 * http://getbootstrap.com/javascript/#transitions
9865 * ========================================================================
9866 * Copyright 2011-2015 Twitter, Inc.
9867 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
9868 * ======================================================================== */
9869
9870
9871+function ($) {
9872  'use strict';
9873
9874  // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
9875  // ============================================================
9876
9877  function transitionEnd() {
9878    var el = document.createElement('bootstrap')
9879
9880    var transEndEventNames = {
9881      WebkitTransition : 'webkitTransitionEnd',
9882      MozTransition    : 'transitionend',
9883      OTransition      : 'oTransitionEnd otransitionend',
9884      transition       : 'transitionend'
9885    }
9886
9887    for (var name in transEndEventNames) {
9888      if (el.style[name] !== undefined) {
9889        return { end: transEndEventNames[name] }
9890      }
9891    }
9892
9893    return false // explicit for ie8 (  ._.)
9894  }
9895
9896  // http://blog.alexmaccaw.com/css-transitions
9897  $.fn.emulateTransitionEnd = function (duration) {
9898    var called = false
9899    var $el = this
9900    $(this).one('bsTransitionEnd', function () { called = true })
9901    var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
9902    setTimeout(callback, duration)
9903    return this
9904  }
9905
9906  $(function () {
9907    $.support.transition = transitionEnd()
9908
9909    if (!$.support.transition) return
9910
9911    $.event.special.bsTransitionEnd = {
9912      bindType: $.support.transition.end,
9913      delegateType: $.support.transition.end,
9914      handle: function (e) {
9915        if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments)
9916      }
9917    }
9918  })
9919
9920}(jQuery);
9921
9922/* ========================================================================
9923 * Bootstrap: alert.js v3.3.6
9924 * http://getbootstrap.com/javascript/#alerts
9925 * ========================================================================
9926 * Copyright 2011-2015 Twitter, Inc.
9927 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
9928 * ======================================================================== */
9929
9930
9931+function ($) {
9932  'use strict';
9933
9934  // ALERT CLASS DEFINITION
9935  // ======================
9936
9937  var dismiss = '[data-dismiss="alert"]'
9938  var Alert   = function (el) {
9939    $(el).on('click', dismiss, this.close)
9940  }
9941
9942  Alert.VERSION = '3.3.6'
9943
9944  Alert.TRANSITION_DURATION = 150
9945
9946  Alert.prototype.close = function (e) {
9947    var $this    = $(this)
9948    var selector = $this.attr('data-target')
9949
9950    if (!selector) {
9951      selector = $this.attr('href')
9952      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
9953    }
9954
9955    var $parent = $(selector)
9956
9957    if (e) e.preventDefault()
9958
9959    if (!$parent.length) {
9960      $parent = $this.closest('.alert')
9961    }
9962
9963    $parent.trigger(e = $.Event('close.bs.alert'))
9964
9965    if (e.isDefaultPrevented()) return
9966
9967    $parent.removeClass('in')
9968
9969    function removeElement() {
9970      // detach from parent, fire event then clean up data
9971      $parent.detach().trigger('closed.bs.alert').remove()
9972    }
9973
9974    $.support.transition && $parent.hasClass('fade') ?
9975      $parent
9976        .one('bsTransitionEnd', removeElement)
9977        .emulateTransitionEnd(Alert.TRANSITION_DURATION) :
9978      removeElement()
9979  }
9980
9981
9982  // ALERT PLUGIN DEFINITION
9983  // =======================
9984
9985  function Plugin(option) {
9986    return this.each(function () {
9987      var $this = $(this)
9988      var data  = $this.data('bs.alert')
9989
vendor: 4,197 bytes, lines 9990-10140
9990      if (!data) $this.data('bs.alert', (data = new Alert(this)))
9991      if (typeof option == 'string') data[option].call($this)
9992    })
9993  }
9994
9995  var old = $.fn.alert
9996
9997  $.fn.alert             = Plugin
9998  $.fn.alert.Constructor = Alert
9999
10000
10001  // ALERT NO CONFLICT
10002  // =================
10003
10004  $.fn.alert.noConflict = function () {
10005    $.fn.alert = old
10006    return this
10007  }
10008
10009
10010  // ALERT DATA-API
10011  // ==============
10012
10013  $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)
10014
10015}(jQuery);
10016
10017/* ========================================================================
10018 * Bootstrap: button.js v3.3.6
10019 * http://getbootstrap.com/javascript/#buttons
10020 * ========================================================================
10021 * Copyright 2011-2015 Twitter, Inc.
10022 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
10023 * ======================================================================== */
10024
10025
10026+function ($) {
10027  'use strict';
10028
10029  // BUTTON PUBLIC CLASS DEFINITION
10030  // ==============================
10031
10032  var Button = function (element, options) {
10033    this.$element  = $(element)
10034    this.options   = $.extend({}, Button.DEFAULTS, options)
10035    this.isLoading = false
10036  }
10037
10038  Button.VERSION  = '3.3.6'
10039
10040  Button.DEFAULTS = {
10041    loadingText: 'loading...'
10042  }
10043
10044  Button.prototype.setState = function (state) {
10045    var d    = 'disabled'
10046    var $el  = this.$element
10047    var val  = $el.is('input') ? 'val' : 'html'
10048    var data = $el.data()
10049
10050    state += 'Text'
10051
10052    if (data.resetText == null) $el.data('resetText', $el[val]())
10053
10054    // push to event loop to allow forms to submit
10055    setTimeout($.proxy(function () {
10056      $el[val](data[state] == null ? this.options[state] : data[state])
10057
10058      if (state == 'loadingText') {
10059        this.isLoading = true
10060        $el.addClass(d).attr(d, d)
10061      } else if (this.isLoading) {
10062        this.isLoading = false
10063        $el.removeClass(d).removeAttr(d)
10064      }
10065    }, this), 0)
10066  }
10067
10068  Button.prototype.toggle = function () {
10069    var changed = true
10070    var $parent = this.$element.closest('[data-toggle="buttons"]')
10071
10072    if ($parent.length) {
10073      var $input = this.$element.find('input')
10074      if ($input.prop('type') == 'radio') {
10075        if ($input.prop('checked')) changed = false
10076        $parent.find('.active').removeClass('active')
10077        this.$element.addClass('active')
10078      } else if ($input.prop('type') == 'checkbox') {
10079        if (($input.prop('checked')) !== this.$element.hasClass('active')) changed = false
10080        this.$element.toggleClass('active')
10081      }
10082      $input.prop('checked', this.$element.hasClass('active'))
10083      if (changed) $input.trigger('change')
10084    } else {
10085      this.$element.attr('aria-pressed', !this.$element.hasClass('active'))
10086      this.$element.toggleClass('active')
10087    }
10088  }
10089
10090
10091  // BUTTON PLUGIN DEFINITION
10092  // ========================
10093
10094  function Plugin(option) {
10095    return this.each(function () {
10096      var $this   = $(this)
10097      var data    = $this.data('bs.button')
10098      var options = typeof option == 'object' && option
10099
10100      if (!data) $this.data('bs.button', (data = new Button(this, options)))
10101
10102      if (option == 'toggle') data.toggle()
10103      else if (option) data.setState(option)
10104    })
10105  }
10106
10107  var old = $.fn.button
10108
10109  $.fn.button             = Plugin
10110  $.fn.button.Constructor = Button
10111
10112
10113  // BUTTON NO CONFLICT
10114  // ==================
10115
10116  $.fn.button.noConflict = function () {
10117    $.fn.button = old
10118    return this
10119  }
10120
10121
10122  // BUTTON DATA-API
10123  // ===============
10124
10125  $(document)
10126    .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) {
10127      var $btn = $(e.target)
10128      if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
10129      Plugin.call($btn, 'toggle')
10130      if (!($(e.target).is('input[type="radio"]') || $(e.target).is('input[type="checkbox"]'))) e.preventDefault()
10131    })
10132    .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) {
10133      $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type))
10134    })
10135
10136}(jQuery);
10137
10138/* ========================================================================
10139 * Bootstrap: carousel.js v3.3.6
10140 * http://getbootstrap.com/javascript/#carousel
vendor: 4,375 bytes, lines 10141-10281
10141 * ========================================================================
10142 * Copyright 2011-2015 Twitter, Inc.
10143 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
10144 * ======================================================================== */
10145
10146
10147+function ($) {
10148  'use strict';
10149
10150  // CAROUSEL CLASS DEFINITION
10151  // =========================
10152
10153  var Carousel = function (element, options) {
10154    this.$element    = $(element)
10155    this.$indicators = this.$element.find('.carousel-indicators')
10156    this.options     = options
10157    this.paused      = null
10158    this.sliding     = null
10159    this.interval    = null
10160    this.$active     = null
10161    this.$items      = null
10162
10163    this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this))
10164
10165    this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element
10166      .on('mouseenter.bs.carousel', $.proxy(this.pause, this))
10167      .on('mouseleave.bs.carousel', $.proxy(this.cycle, this))
10168  }
10169
10170  Carousel.VERSION  = '3.3.6'
10171
10172  Carousel.TRANSITION_DURATION = 600
10173
10174  Carousel.DEFAULTS = {
10175    interval: 5000,
10176    pause: 'hover',
10177    wrap: true,
10178    keyboard: true
10179  }
10180
10181  Carousel.prototype.keydown = function (e) {
10182    if (/input|textarea/i.test(e.target.tagName)) return
10183    switch (e.which) {
10184      case 37: this.prev(); break
10185      case 39: this.next(); break
10186      default: return
10187    }
10188
10189    e.preventDefault()
10190  }
10191
10192  Carousel.prototype.cycle = function (e) {
10193    e || (this.paused = false)
10194
10195    this.interval && clearInterval(this.interval)
10196
10197    this.options.interval
10198      && !this.paused
10199      && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
10200
10201    return this
10202  }
10203
10204  Carousel.prototype.getItemIndex = function (item) {
10205    this.$items = item.parent().children('.item')
10206    return this.$items.index(item || this.$active)
10207  }
10208
10209  Carousel.prototype.getItemForDirection = function (direction, active) {
10210    var activeIndex = this.getItemIndex(active)
10211    var willWrap = (direction == 'prev' && activeIndex === 0)
10212                || (direction == 'next' && activeIndex == (this.$items.length - 1))
10213    if (willWrap && !this.options.wrap) return active
10214    var delta = direction == 'prev' ? -1 : 1
10215    var itemIndex = (activeIndex + delta) % this.$items.length
10216    return this.$items.eq(itemIndex)
10217  }
10218
10219  Carousel.prototype.to = function (pos) {
10220    var that        = this
10221    var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active'))
10222
10223    if (pos > (this.$items.length - 1) || pos < 0) return
10224
10225    if (this.sliding)       return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid"
10226    if (activeIndex == pos) return this.pause().cycle()
10227
10228    return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos))
10229  }
10230
10231  Carousel.prototype.pause = function (e) {
10232    e || (this.paused = true)
10233
10234    if (this.$element.find('.next, .prev').length && $.support.transition) {
10235      this.$element.trigger($.support.transition.end)
10236      this.cycle(true)
10237    }
10238
10239    this.interval = clearInterval(this.interval)
10240
10241    return this
10242  }
10243
10244  Carousel.prototype.next = function () {
10245    if (this.sliding) return
10246    return this.slide('next')
10247  }
10248
10249  Carousel.prototype.prev = function () {
10250    if (this.sliding) return
10251    return this.slide('prev')
10252  }
10253
10254  Carousel.prototype.slide = function (type, next) {
10255    var $active   = this.$element.find('.item.active')
10256    var $next     = next || this.getItemForDirection(type, $active)
10257    var isCycling = this.interval
10258    var direction = type == 'next' ? 'left' : 'right'
10259    var that      = this
10260
10261    if ($next.hasClass('active')) return (this.sliding = false)
10262
10263    var relatedTarget = $next[0]
10264    var slideEvent = $.Event('slide.bs.carousel', {
10265      relatedTarget: relatedTarget,
10266      direction: direction
10267    })
10268    this.$element.trigger(slideEvent)
10269    if (slideEvent.isDefaultPrevented()) return
10270
10271    this.sliding = true
10272
10273    isCycling && this.pause()
10274
10275    if (this.$indicators.length) {
10276      this.$indicators.find('.active').removeClass('active')
10277      var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)])
10278      $nextIndicator && $nextIndicator.addClass('active')
10279    }
10280
10281    var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid"
vendor: 14,005 bytes, lines 10282-10772
10282    if ($.support.transition && this.$element.hasClass('slide')) {
10283      $next.addClass(type)
10284      $next[0].offsetWidth // force reflow
10285      $active.addClass(direction)
10286      $next.addClass(direction)
10287      $active
10288        .one('bsTransitionEnd', function () {
10289          $next.removeClass([type, direction].join(' ')).addClass('active')
10290          $active.removeClass(['active', direction].join(' '))
10291          that.sliding = false
10292          setTimeout(function () {
10293            that.$element.trigger(slidEvent)
10294          }, 0)
10295        })
10296        .emulateTransitionEnd(Carousel.TRANSITION_DURATION)
10297    } else {
10298      $active.removeClass('active')
10299      $next.addClass('active')
10300      this.sliding = false
10301      this.$element.trigger(slidEvent)
10302    }
10303
10304    isCycling && this.cycle()
10305
10306    return this
10307  }
10308
10309
10310  // CAROUSEL PLUGIN DEFINITION
10311  // ==========================
10312
10313  function Plugin(option) {
10314    return this.each(function () {
10315      var $this   = $(this)
10316      var data    = $this.data('bs.carousel')
10317      var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option)
10318      var action  = typeof option == 'string' ? option : options.slide
10319
10320      if (!data) $this.data('bs.carousel', (data = new Carousel(this, options)))
10321      if (typeof option == 'number') data.to(option)
10322      else if (action) data[action]()
10323      else if (options.interval) data.pause().cycle()
10324    })
10325  }
10326
10327  var old = $.fn.carousel
10328
10329  $.fn.carousel             = Plugin
10330  $.fn.carousel.Constructor = Carousel
10331
10332
10333  // CAROUSEL NO CONFLICT
10334  // ====================
10335
10336  $.fn.carousel.noConflict = function () {
10337    $.fn.carousel = old
10338    return this
10339  }
10340
10341
10342  // CAROUSEL DATA-API
10343  // =================
10344
10345  var clickHandler = function (e) {
10346    var href
10347    var $this   = $(this)
10348    var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7
10349    if (!$target.hasClass('carousel')) return
10350    var options = $.extend({}, $target.data(), $this.data())
10351    var slideIndex = $this.attr('data-slide-to')
10352    if (slideIndex) options.interval = false
10353
10354    Plugin.call($target, options)
10355
10356    if (slideIndex) {
10357      $target.data('bs.carousel').to(slideIndex)
10358    }
10359
10360    e.preventDefault()
10361  }
10362
10363  $(document)
10364    .on('click.bs.carousel.data-api', '[data-slide]', clickHandler)
10365    .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler)
10366
10367  $(window).on('load', function () {
10368    $('[data-ride="carousel"]').each(function () {
10369      var $carousel = $(this)
10370      Plugin.call($carousel, $carousel.data())
10371    })
10372  })
10373
10374}(jQuery);
10375
10376/* ========================================================================
10377 * Bootstrap: collapse.js v3.3.6
10378 * http://getbootstrap.com/javascript/#collapse
10379 * ========================================================================
10380 * Copyright 2011-2015 Twitter, Inc.
10381 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
10382 * ======================================================================== */
10383
10384
10385+function ($) {
10386  'use strict';
10387
10388  // COLLAPSE PUBLIC CLASS DEFINITION
10389  // ================================
10390
10391  var Collapse = function (element, options) {
10392    this.$element      = $(element)
10393    this.options       = $.extend({}, Collapse.DEFAULTS, options)
10394    this.$trigger      = $('[data-toggle="collapse"][href="#' + element.id + '"],' +
10395                           '[data-toggle="collapse"][data-target="#' + element.id + '"]')
10396    this.transitioning = null
10397
10398    if (this.options.parent) {
10399      this.$parent = this.getParent()
10400    } else {
10401      this.addAriaAndCollapsedClass(this.$element, this.$trigger)
10402    }
10403
10404    if (this.options.toggle) this.toggle()
10405  }
10406
10407  Collapse.VERSION  = '3.3.6'
10408
10409  Collapse.TRANSITION_DURATION = 350
10410
10411  Collapse.DEFAULTS = {
10412    toggle: true
10413  }
10414
10415  Collapse.prototype.dimension = function () {
10416    var hasWidth = this.$element.hasClass('width')
10417    return hasWidth ? 'width' : 'height'
10418  }
10419
10420  Collapse.prototype.show = function () {
10421    if (this.transitioning || this.$element.hasClass('in')) return
10422
10423    var activesData
10424    var actives = this.$parent && this.$parent.children('.panel').children('.in, .collapsing')
10425
10426    if (actives && actives.length) {
10427      activesData = actives.data('bs.collapse')
10428      if (activesData && activesData.transitioning) return
10429    }
10430
10431    var startEvent = $.Event('show.bs.collapse')
10432    this.$element.trigger(startEvent)
10433    if (startEvent.isDefaultPrevented()) return
10434
10435    if (actives && actives.length) {
10436      Plugin.call(actives, 'hide')
10437      activesData || actives.data('bs.collapse', null)
10438    }
10439
10440    var dimension = this.dimension()
10441
10442    this.$element
10443      .removeClass('collapse')
10444      .addClass('collapsing')[dimension](0)
10445      .attr('aria-expanded', true)
10446
10447    this.$trigger
10448      .removeClass('collapsed')
10449      .attr('aria-expanded', true)
10450
10451    this.transitioning = 1
10452
10453    var complete = function () {
10454      this.$element
10455        .removeClass('collapsing')
10456        .addClass('collapse in')[dimension]('')
10457      this.transitioning = 0
10458      this.$element
10459        .trigger('shown.bs.collapse')
10460    }
10461
10462    if (!$.support.transition) return complete.call(this)
10463
10464    var scrollSize = $.camelCase(['scroll', dimension].join('-'))
10465
10466    this.$element
10467      .one('bsTransitionEnd', $.proxy(complete, this))
10468      .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize])
10469  }
10470
10471  Collapse.prototype.hide = function () {
10472    if (this.transitioning || !this.$element.hasClass('in')) return
10473
10474    var startEvent = $.Event('hide.bs.collapse')
10475    this.$element.trigger(startEvent)
10476    if (startEvent.isDefaultPrevented()) return
10477
10478    var dimension = this.dimension()
10479
10480    this.$element[dimension](this.$element[dimension]())[0].offsetHeight
10481
10482    this.$element
10483      .addClass('collapsing')
10484      .removeClass('collapse in')
10485      .attr('aria-expanded', false)
10486
10487    this.$trigger
10488      .addClass('collapsed')
10489      .attr('aria-expanded', false)
10490
10491    this.transitioning = 1
10492
10493    var complete = function () {
10494      this.transitioning = 0
10495      this.$element
10496        .removeClass('collapsing')
10497        .addClass('collapse')
10498        .trigger('hidden.bs.collapse')
10499    }
10500
10501    if (!$.support.transition) return complete.call(this)
10502
10503    this.$element
10504      [dimension](0)
10505      .one('bsTransitionEnd', $.proxy(complete, this))
10506      .emulateTransitionEnd(Collapse.TRANSITION_DURATION)
10507  }
10508
10509  Collapse.prototype.toggle = function () {
10510    this[this.$element.hasClass('in') ? 'hide' : 'show']()
10511  }
10512
10513  Collapse.prototype.getParent = function () {
10514    return $(this.options.parent)
10515      .find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]')
10516      .each($.proxy(function (i, element) {
10517        var $element = $(element)
10518        this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element)
10519      }, this))
10520      .end()
10521  }
10522
10523  Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) {
10524    var isOpen = $element.hasClass('in')
10525
10526    $element.attr('aria-expanded', isOpen)
10527    $trigger
10528      .toggleClass('collapsed', !isOpen)
10529      .attr('aria-expanded', isOpen)
10530  }
10531
10532  function getTargetFromTrigger($trigger) {
10533    var href
10534    var target = $trigger.attr('data-target')
10535      || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
10536
10537    return $(target)
10538  }
10539
10540
10541  // COLLAPSE PLUGIN DEFINITION
10542  // ==========================
10543
10544  function Plugin(option) {
10545    return this.each(function () {
10546      var $this   = $(this)
10547      var data    = $this.data('bs.collapse')
10548      var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
10549
10550      if (!data && options.toggle && /show|hide/.test(option)) options.toggle = false
10551      if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
10552      if (typeof option == 'string') data[option]()
10553    })
10554  }
10555
10556  var old = $.fn.collapse
10557
10558  $.fn.collapse             = Plugin
10559  $.fn.collapse.Constructor = Collapse
10560
10561
10562  // COLLAPSE NO CONFLICT
10563  // ====================
10564
10565  $.fn.collapse.noConflict = function () {
10566    $.fn.collapse = old
10567    return this
10568  }
10569
10570
10571  // COLLAPSE DATA-API
10572  // =================
10573
10574  $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) {
10575    var $this   = $(this)
10576
10577    if (!$this.attr('data-target')) e.preventDefault()
10578
10579    var $target = getTargetFromTrigger($this)
10580    var data    = $target.data('bs.collapse')
10581    var option  = data ? 'toggle' : $this.data()
10582
10583    Plugin.call($target, option)
10584  })
10585
10586}(jQuery);
10587
10588/* ========================================================================
10589 * Bootstrap: dropdown.js v3.3.6
10590 * http://getbootstrap.com/javascript/#dropdowns
10591 * ========================================================================
10592 * Copyright 2011-2015 Twitter, Inc.
10593 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
10594 * ======================================================================== */
10595
10596
10597+function ($) {
10598  'use strict';
10599
10600  // DROPDOWN CLASS DEFINITION
10601  // =========================
10602
10603  var backdrop = '.dropdown-backdrop'
10604  var toggle   = '[data-toggle="dropdown"]'
10605  var Dropdown = function (element) {
10606    $(element).on('click.bs.dropdown', this.toggle)
10607  }
10608
10609  Dropdown.VERSION = '3.3.6'
10610
10611  function getParent($this) {
10612    var selector = $this.attr('data-target')
10613
10614    if (!selector) {
10615      selector = $this.attr('href')
10616      selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
10617    }
10618
10619    var $parent = selector && $(selector)
10620
10621    return $parent && $parent.length ? $parent : $this.parent()
10622  }
10623
10624  function clearMenus(e) {
10625    if (e && e.which === 3) return
10626    $(backdrop).remove()
10627    $(toggle).each(function () {
10628      var $this         = $(this)
10629      var $parent       = getParent($this)
10630      var relatedTarget = { relatedTarget: this }
10631
10632      if (!$parent.hasClass('open')) return
10633
10634      if (e && e.type == 'click' && /input|textarea/i.test(e.target.tagName) && $.contains($parent[0], e.target)) return
10635
10636      $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
10637
10638      if (e.isDefaultPrevented()) return
10639
10640      $this.attr('aria-expanded', 'false')
10641      $parent.removeClass('open').trigger($.Event('hidden.bs.dropdown', relatedTarget))
10642    })
10643  }
10644
10645  Dropdown.prototype.toggle = function (e) {
10646    var $this = $(this)
10647
10648    if ($this.is('.disabled, :disabled')) return
10649
10650    var $parent  = getParent($this)
10651    var isActive = $parent.hasClass('open')
10652
10653    clearMenus()
10654
10655    if (!isActive) {
10656      if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
10657        // if mobile we use a backdrop because click events don't delegate
10658        $(document.createElement('div'))
10659          .addClass('dropdown-backdrop')
10660          .insertAfter($(this))
10661          .on('click', clearMenus)
10662      }
10663
10664      var relatedTarget = { relatedTarget: this }
10665      $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
10666
10667      if (e.isDefaultPrevented()) return
10668
10669      $this
10670        .trigger('focus')
10671        .attr('aria-expanded', 'true')
10672
10673      $parent
10674        .toggleClass('open')
10675        .trigger($.Event('shown.bs.dropdown', relatedTarget))
10676    }
10677
10678    return false
10679  }
10680
10681  Dropdown.prototype.keydown = function (e) {
10682    if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return
10683
10684    var $this = $(this)
10685
10686    e.preventDefault()
10687    e.stopPropagation()
10688
10689    if ($this.is('.disabled, :disabled')) return
10690
10691    var $parent  = getParent($this)
10692    var isActive = $parent.hasClass('open')
10693
10694    if (!isActive && e.which != 27 || isActive && e.which == 27) {
10695      if (e.which == 27) $parent.find(toggle).trigger('focus')
10696      return $this.trigger('click')
10697    }
10698
10699    var desc = ' li:not(.disabled):visible a'
10700    var $items = $parent.find('.dropdown-menu' + desc)
10701
10702    if (!$items.length) return
10703
10704    var index = $items.index(e.target)
10705
10706    if (e.which == 38 && index > 0)                 index--         // up
10707    if (e.which == 40 && index < $items.length - 1) index++         // down
10708    if (!~index)                                    index = 0
10709
10710    $items.eq(index).trigger('focus')
10711  }
10712
10713
10714  // DROPDOWN PLUGIN DEFINITION
10715  // ==========================
10716
10717  function Plugin(option) {
10718    return this.each(function () {
10719      var $this = $(this)
10720      var data  = $this.data('bs.dropdown')
10721
10722      if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))
10723      if (typeof option == 'string') data[option].call($this)
10724    })
10725  }
10726
10727  var old = $.fn.dropdown
10728
10729  $.fn.dropdown             = Plugin
10730  $.fn.dropdown.Constructor = Dropdown
10731
10732
10733  // DROPDOWN NO CONFLICT
10734  // ====================
10735
10736  $.fn.dropdown.noConflict = function () {
10737    $.fn.dropdown = old
10738    return this
10739  }
10740
10741
10742  // APPLY TO STANDARD DROPDOWN ELEMENTS
10743  // ===================================
10744
10745  $(document)
10746    .on('click.bs.dropdown.data-api', clearMenus)
10747    .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
10748    .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
10749    .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)
10750    .on('keydown.bs.dropdown.data-api', '.dropdown-menu', Dropdown.prototype.keydown)
10751
10752}(jQuery);
10753
10754/* ========================================================================
10755 * Bootstrap: modal.js v3.3.6
10756 * http://getbootstrap.com/javascript/#modals
10757 * ========================================================================
10758 * Copyright 2011-2015 Twitter, Inc.
10759 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
10760 * ======================================================================== */
10761
10762
10763+function ($) {
10764  'use strict';
10765
10766  // MODAL CLASS DEFINITION
10767  // ======================
10768
10769  var Modal = function (element, options) {
10770    this.options             = options
10771    this.$body               = $(document.body)
10772    this.$element            = $(element)
vendor: 10,154 bytes, lines 10773-11120
10773    this.$dialog             = this.$element.find('.modal-dialog')
10774    this.$backdrop           = null
10775    this.isShown             = null
10776    this.originalBodyPad     = null
10777    this.scrollbarWidth      = 0
10778    this.ignoreBackdropClick = false
10779
10780    if (this.options.remote) {
10781      this.$element
10782        .find('.modal-content')
10783        .load(this.options.remote, $.proxy(function () {
10784          this.$element.trigger('loaded.bs.modal')
10785        }, this))
10786    }
10787  }
10788
10789  Modal.VERSION  = '3.3.6'
10790
10791  Modal.TRANSITION_DURATION = 300
10792  Modal.BACKDROP_TRANSITION_DURATION = 150
10793
10794  Modal.DEFAULTS = {
10795    backdrop: true,
10796    keyboard: true,
10797    show: true
10798  }
10799
10800  Modal.prototype.toggle = function (_relatedTarget) {
10801    return this.isShown ? this.hide() : this.show(_relatedTarget)
10802  }
10803
10804  Modal.prototype.show = function (_relatedTarget) {
10805    var that = this
10806    var e    = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
10807
10808    this.$element.trigger(e)
10809
10810    if (this.isShown || e.isDefaultPrevented()) return
10811
10812    this.isShown = true
10813
10814    this.checkScrollbar()
10815    this.setScrollbar()
10816    this.$body.addClass('modal-open')
10817
10818    this.escape()
10819    this.resize()
10820
10821    this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
10822
10823    this.$dialog.on('mousedown.dismiss.bs.modal', function () {
10824      that.$element.one('mouseup.dismiss.bs.modal', function (e) {
10825        if ($(e.target).is(that.$element)) that.ignoreBackdropClick = true
10826      })
10827    })
10828
10829    this.backdrop(function () {
10830      var transition = $.support.transition && that.$element.hasClass('fade')
10831
10832      if (!that.$element.parent().length) {
10833        that.$element.appendTo(that.$body) // don't move modals dom position
10834      }
10835
10836      that.$element
10837        .show()
10838        .scrollTop(0)
10839
10840      that.adjustDialog()
10841
10842      if (transition) {
10843        that.$element[0].offsetWidth // force reflow
10844      }
10845
10846      that.$element.addClass('in')
10847
10848      that.enforceFocus()
10849
10850      var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
10851
10852      transition ?
10853        that.$dialog // wait for modal to slide in
10854          .one('bsTransitionEnd', function () {
10855            that.$element.trigger('focus').trigger(e)
10856          })
10857          .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
10858        that.$element.trigger('focus').trigger(e)
10859    })
10860  }
10861
10862  Modal.prototype.hide = function (e) {
10863    if (e) e.preventDefault()
10864
10865    e = $.Event('hide.bs.modal')
10866
10867    this.$element.trigger(e)
10868
10869    if (!this.isShown || e.isDefaultPrevented()) return
10870
10871    this.isShown = false
10872
10873    this.escape()
10874    this.resize()
10875
10876    $(document).off('focusin.bs.modal')
10877
10878    this.$element
10879      .removeClass('in')
10880      .off('click.dismiss.bs.modal')
10881      .off('mouseup.dismiss.bs.modal')
10882
10883    this.$dialog.off('mousedown.dismiss.bs.modal')
10884
10885    $.support.transition && this.$element.hasClass('fade') ?
10886      this.$element
10887        .one('bsTransitionEnd', $.proxy(this.hideModal, this))
10888        .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
10889      this.hideModal()
10890  }
10891
10892  Modal.prototype.enforceFocus = function () {
10893    $(document)
10894      .off('focusin.bs.modal') // guard against infinite focus loop
10895      .on('focusin.bs.modal', $.proxy(function (e) {
10896        if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {
10897          this.$element.trigger('focus')
10898        }
10899      }, this))
10900  }
10901
10902  Modal.prototype.escape = function () {
10903    if (this.isShown && this.options.keyboard) {
10904      this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {
10905        e.which == 27 && this.hide()
10906      }, this))
10907    } else if (!this.isShown) {
10908      this.$element.off('keydown.dismiss.bs.modal')
10909    }
10910  }
10911
10912  Modal.prototype.resize = function () {
10913    if (this.isShown) {
10914      $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this))
10915    } else {
10916      $(window).off('resize.bs.modal')
10917    }
10918  }
10919
10920  Modal.prototype.hideModal = function () {
10921    var that = this
10922    this.$element.hide()
10923    this.backdrop(function () {
10924      that.$body.removeClass('modal-open')
10925      that.resetAdjustments()
10926      that.resetScrollbar()
10927      that.$element.trigger('hidden.bs.modal')
10928    })
10929  }
10930
10931  Modal.prototype.removeBackdrop = function () {
10932    this.$backdrop && this.$backdrop.remove()
10933    this.$backdrop = null
10934  }
10935
10936  Modal.prototype.backdrop = function (callback) {
10937    var that = this
10938    var animate = this.$element.hasClass('fade') ? 'fade' : ''
10939
10940    if (this.isShown && this.options.backdrop) {
10941      var doAnimate = $.support.transition && animate
10942
10943      this.$backdrop = $(document.createElement('div'))
10944        .addClass('modal-backdrop ' + animate)
10945        .appendTo(this.$body)
10946
10947      this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {
10948        if (this.ignoreBackdropClick) {
10949          this.ignoreBackdropClick = false
10950          return
10951        }
10952        if (e.target !== e.currentTarget) return
10953        this.options.backdrop == 'static'
10954          ? this.$element[0].focus()
10955          : this.hide()
10956      }, this))
10957
10958      if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
10959
10960      this.$backdrop.addClass('in')
10961
10962      if (!callback) return
10963
10964      doAnimate ?
10965        this.$backdrop
10966          .one('bsTransitionEnd', callback)
10967          .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
10968        callback()
10969
10970    } else if (!this.isShown && this.$backdrop) {
10971      this.$backdrop.removeClass('in')
10972
10973      var callbackRemove = function () {
10974        that.removeBackdrop()
10975        callback && callback()
10976      }
10977      $.support.transition && this.$element.hasClass('fade') ?
10978        this.$backdrop
10979          .one('bsTransitionEnd', callbackRemove)
10980          .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
10981        callbackRemove()
10982
10983    } else if (callback) {
10984      callback()
10985    }
10986  }
10987
10988  // these following methods are used to handle overflowing modals
10989
10990  Modal.prototype.handleUpdate = function () {
10991    this.adjustDialog()
10992  }
10993
10994  Modal.prototype.adjustDialog = function () {
10995    var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight
10996
10997    this.$element.css({
10998      paddingLeft:  !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '',
10999      paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : ''
11000    })
11001  }
11002
11003  Modal.prototype.resetAdjustments = function () {
11004    this.$element.css({
11005      paddingLeft: '',
11006      paddingRight: ''
11007    })
11008  }
11009
11010  Modal.prototype.checkScrollbar = function () {
11011    var fullWindowWidth = window.innerWidth
11012    if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8
11013      var documentElementRect = document.documentElement.getBoundingClientRect()
11014      fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left)
11015    }
11016    this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth
11017    this.scrollbarWidth = this.measureScrollbar()
11018  }
11019
11020  Modal.prototype.setScrollbar = function () {
11021    var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
11022    this.originalBodyPad = document.body.style.paddingRight || ''
11023    if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)
11024  }
11025
11026  Modal.prototype.resetScrollbar = function () {
11027    this.$body.css('padding-right', this.originalBodyPad)
11028  }
11029
11030  Modal.prototype.measureScrollbar = function () { // thx walsh
11031    var scrollDiv = document.createElement('div')
11032    scrollDiv.className = 'modal-scrollbar-measure'
11033    this.$body.append(scrollDiv)
11034    var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth
11035    this.$body[0].removeChild(scrollDiv)
11036    return scrollbarWidth
11037  }
11038
11039
11040  // MODAL PLUGIN DEFINITION
11041  // =======================
11042
11043  function Plugin(option, _relatedTarget) {
11044    return this.each(function () {
11045      var $this   = $(this)
11046      var data    = $this.data('bs.modal')
11047      var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)
11048
11049      if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
11050      if (typeof option == 'string') data[option](_relatedTarget)
11051      else if (options.show) data.show(_relatedTarget)
11052    })
11053  }
11054
11055  var old = $.fn.modal
11056
11057  $.fn.modal             = Plugin
11058  $.fn.modal.Constructor = Modal
11059
11060
11061  // MODAL NO CONFLICT
11062  // =================
11063
11064  $.fn.modal.noConflict = function () {
11065    $.fn.modal = old
11066    return this
11067  }
11068
11069
11070  // MODAL DATA-API
11071  // ==============
11072
11073  $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
11074    var $this   = $(this)
11075    var href    = $this.attr('href')
11076    var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7
11077    var option  = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
11078
11079    if ($this.is('a')) e.preventDefault()
11080
11081    $target.one('show.bs.modal', function (showEvent) {
11082      if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown
11083      $target.one('hidden.bs.modal', function () {
11084        $this.is(':visible') && $this.trigger('focus')
11085      })
11086    })
11087    Plugin.call($target, option, this)
11088  })
11089
11090}(jQuery);
11091
11092/* ========================================================================
11093 * Bootstrap: tooltip.js v3.3.6
11094 * http://getbootstrap.com/javascript/#tooltip
11095 * Inspired by the original jQuery.tipsy by Jason Frame
11096 * ========================================================================
11097 * Copyright 2011-2015 Twitter, Inc.
11098 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
11099 * ======================================================================== */
11100
11101
11102+function ($) {
11103  'use strict';
11104
11105  // TOOLTIP PUBLIC CLASS DEFINITION
11106  // ===============================
11107
11108  var Tooltip = function (element, options) {
11109    this.type       = null
11110    this.options    = null
11111    this.enabled    = null
11112    this.timeout    = null
11113    this.hoverState = null
11114    this.$element   = null
11115    this.inState    = null
11116
11117    this.init('tooltip', element, options)
11118  }
11119
11120  Tooltip.VERSION  = '3.3.6
vendor: 15,550 bytes, lines 11120-11608
11120'
11121
11122  Tooltip.TRANSITION_DURATION = 150
11123
11124  Tooltip.DEFAULTS = {
11125    animation: true,
11126    placement: 'top',
11127    selector: false,
11128    template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
11129    trigger: 'hover focus',
11130    title: '',
11131    delay: 0,
11132    html: false,
11133    container: false,
11134    viewport: {
11135      selector: 'body',
11136      padding: 0
11137    }
11138  }
11139
11140  Tooltip.prototype.init = function (type, element, options) {
11141    this.enabled   = true
11142    this.type      = type
11143    this.$element  = $(element)
11144    this.options   = this.getOptions(options)
11145    this.$viewport = this.options.viewport && $($.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : (this.options.viewport.selector || this.options.viewport))
11146    this.inState   = { click: false, hover: false, focus: false }
11147
11148    if (this.$element[0] instanceof document.constructor && !this.options.selector) {
11149      throw new Error('`selector` option must be specified when initializing ' + this.type + ' on the window.document object!')
11150    }
11151
11152    var triggers = this.options.trigger.split(' ')
11153
11154    for (var i = triggers.length; i--;) {
11155      var trigger = triggers[i]
11156
11157      if (trigger == 'click') {
11158        this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
11159      } else if (trigger != 'manual') {
11160        var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin'
11161        var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
11162
11163        this.$element.on(eventIn  + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
11164        this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
11165      }
11166    }
11167
11168    this.options.selector ?
11169      (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
11170      this.fixTitle()
11171  }
11172
11173  Tooltip.prototype.getDefaults = function () {
11174    return Tooltip.DEFAULTS
11175  }
11176
11177  Tooltip.prototype.getOptions = function (options) {
11178    options = $.extend({}, this.getDefaults(), this.$element.data(), options)
11179
11180    if (options.delay && typeof options.delay == 'number') {
11181      options.delay = {
11182        show: options.delay,
11183        hide: options.delay
11184      }
11185    }
11186
11187    return options
11188  }
11189
11190  Tooltip.prototype.getDelegateOptions = function () {
11191    var options  = {}
11192    var defaults = this.getDefaults()
11193
11194    this._options && $.each(this._options, function (key, value) {
11195      if (defaults[key] != value) options[key] = value
11196    })
11197
11198    return options
11199  }
11200
11201  Tooltip.prototype.enter = function (obj) {
11202    var self = obj instanceof this.constructor ?
11203      obj : $(obj.currentTarget).data('bs.' + this.type)
11204
11205    if (!self) {
11206      self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
11207      $(obj.currentTarget).data('bs.' + this.type, self)
11208    }
11209
11210    if (obj instanceof $.Event) {
11211      self.inState[obj.type == 'focusin' ? 'focus' : 'hover'] = true
11212    }
11213
11214    if (self.tip().hasClass('in') || self.hoverState == 'in') {
11215      self.hoverState = 'in'
11216      return
11217    }
11218
11219    clearTimeout(self.timeout)
11220
11221    self.hoverState = 'in'
11222
11223    if (!self.options.delay || !self.options.delay.show) return self.show()
11224
11225    self.timeout = setTimeout(function () {
11226      if (self.hoverState == 'in') self.show()
11227    }, self.options.delay.show)
11228  }
11229
11230  Tooltip.prototype.isInStateTrue = function () {
11231    for (var key in this.inState) {
11232      if (this.inState[key]) return true
11233    }
11234
11235    return false
11236  }
11237
11238  Tooltip.prototype.leave = function (obj) {
11239    var self = obj instanceof this.constructor ?
11240      obj : $(obj.currentTarget).data('bs.' + this.type)
11241
11242    if (!self) {
11243      self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
11244      $(obj.currentTarget).data('bs.' + this.type, self)
11245    }
11246
11247    if (obj instanceof $.Event) {
11248      self.inState[obj.type == 'focusout' ? 'focus' : 'hover'] = false
11249    }
11250
11251    if (self.isInStateTrue()) return
11252
11253    clearTimeout(self.timeout)
11254
11255    self.hoverState = 'out'
11256
11257    if (!self.options.delay || !self.options.delay.hide) return self.hide()
11258
11259    self.timeout = setTimeout(function () {
11260      if (self.hoverState == 'out') self.hide()
11261    }, self.options.delay.hide)
11262  }
11263
11264  Tooltip.prototype.show = function () {
11265    var e = $.Event('show.bs.' + this.type)
11266
11267    if (this.hasContent() && this.enabled) {
11268      this.$element.trigger(e)
11269
11270      var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0])
11271      if (e.isDefaultPrevented() || !inDom) return
11272      var that = this
11273
11274      var $tip = this.tip()
11275
11276      var tipId = this.getUID(this.type)
11277
11278      this.setContent()
11279      $tip.attr('id', tipId)
11280      this.$element.attr('aria-describedby', tipId)
11281
11282      if (this.options.animation) $tip.addClass('fade')
11283
11284      var placement = typeof this.options.placement == 'function' ?
11285        this.options.placement.call(this, $tip[0], this.$element[0]) :
11286        this.options.placement
11287
11288      var autoToken = /\s?auto?\s?/i
11289      var autoPlace = autoToken.test(placement)
11290      if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
11291
11292      $tip
11293        .detach()
11294        .css({ top: 0, left: 0, display: 'block' })
11295        .addClass(placement)
11296        .data('bs.' + this.type, this)
11297
11298      this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
11299      this.$element.trigger('inserted.bs.' + this.type)
11300
11301      var pos          = this.getPosition()
11302      var actualWidth  = $tip[0].offsetWidth
11303      var actualHeight = $tip[0].offsetHeight
11304
11305      if (autoPlace) {
11306        var orgPlacement = placement
11307        var viewportDim = this.getPosition(this.$viewport)
11308
11309        placement = placement == 'bottom' && pos.bottom + actualHeight > viewportDim.bottom ? 'top'    :
11310                    placement == 'top'    && pos.top    - actualHeight < viewportDim.top    ? 'bottom' :
11311                    placement == 'right'  && pos.right  + actualWidth  > viewportDim.width  ? 'left'   :
11312                    placement == 'left'   && pos.left   - actualWidth  < viewportDim.left   ? 'right'  :
11313                    placement
11314
11315        $tip
11316          .removeClass(orgPlacement)
11317          .addClass(placement)
11318      }
11319
11320      var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
11321
11322      this.applyPlacement(calculatedOffset, placement)
11323
11324      var complete = function () {
11325        var prevHoverState = that.hoverState
11326        that.$element.trigger('shown.bs.' + that.type)
11327        that.hoverState = null
11328
11329        if (prevHoverState == 'out') that.leave(that)
11330      }
11331
11332      $.support.transition && this.$tip.hasClass('fade') ?
11333        $tip
11334          .one('bsTransitionEnd', complete)
11335          .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
11336        complete()
11337    }
11338  }
11339
11340  Tooltip.prototype.applyPlacement = function (offset, placement) {
11341    var $tip   = this.tip()
11342    var width  = $tip[0].offsetWidth
11343    var height = $tip[0].offsetHeight
11344
11345    // manually read margins because getBoundingClientRect includes difference
11346    var marginTop = parseInt($tip.css('margin-top'), 10)
11347    var marginLeft = parseInt($tip.css('margin-left'), 10)
11348
11349    // we must check for NaN for ie 8/9
11350    if (isNaN(marginTop))  marginTop  = 0
11351    if (isNaN(marginLeft)) marginLeft = 0
11352
11353    offset.top  += marginTop
11354    offset.left += marginLeft
11355
11356    // $.fn.offset doesn't round pixel values
11357    // so we use setOffset directly with our own function B-0
11358    $.offset.setOffset($tip[0], $.extend({
11359      using: function (props) {
11360        $tip.css({
11361          top: Math.round(props.top),
11362          left: Math.round(props.left)
11363        })
11364      }
11365    }, offset), 0)
11366
11367    $tip.addClass('in')
11368
11369    // check to see if placing tip in new offset caused the tip to resize itself
11370    var actualWidth  = $tip[0].offsetWidth
11371    var actualHeight = $tip[0].offsetHeight
11372
11373    if (placement == 'top' && actualHeight != height) {
11374      offset.top = offset.top + height - actualHeight
11375    }
11376
11377    var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)
11378
11379    if (delta.left) offset.left += delta.left
11380    else offset.top += delta.top
11381
11382    var isVertical          = /top|bottom/.test(placement)
11383    var arrowDelta          = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
11384    var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight'
11385
11386    $tip.offset(offset)
11387    this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical)
11388  }
11389
11390  Tooltip.prototype.replaceArrow = function (delta, dimension, isVertical) {
11391    this.arrow()
11392      .css(isVertical ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')
11393      .css(isVertical ? 'top' : 'left', '')
11394  }
11395
11396  Tooltip.prototype.setContent = function () {
11397    var $tip  = this.tip()
11398    var title = this.getTitle()
11399
11400    $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
11401    $tip.removeClass('fade in top bottom left right')
11402  }
11403
11404  Tooltip.prototype.hide = function (callback) {
11405    var that = this
11406    var $tip = $(this.$tip)
11407    var e    = $.Event('hide.bs.' + this.type)
11408
11409    function complete() {
11410      if (that.hoverState != 'in') $tip.detach()
11411      that.$element
11412        .removeAttr('aria-describedby')
11413        .trigger('hidden.bs.' + that.type)
11414      callback && callback()
11415    }
11416
11417    this.$element.trigger(e)
11418
11419    if (e.isDefaultPrevented()) return
11420
11421    $tip.removeClass('in')
11422
11423    $.support.transition && $tip.hasClass('fade') ?
11424      $tip
11425        .one('bsTransitionEnd', complete)
11426        .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
11427      complete()
11428
11429    this.hoverState = null
11430
11431    return this
11432  }
11433
11434  Tooltip.prototype.fixTitle = function () {
11435    var $e = this.$element
11436    if ($e.attr('title') || typeof $e.attr('data-original-title') != 'string') {
11437      $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
11438    }
11439  }
11440
11441  Tooltip.prototype.hasContent = function () {
11442    return this.getTitle()
11443  }
11444
11445  Tooltip.prototype.getPosition = function ($element) {
11446    $element   = $element || this.$element
11447
11448    var el     = $element[0]
11449    var isBody = el.tagName == 'BODY'
11450
11451    var elRect    = el.getBoundingClientRect()
11452    if (elRect.width == null) {
11453      // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093
11454      elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top })
11455    }
11456    var elOffset  = isBody ? { top: 0, left: 0 } : $element.offset()
11457    var scroll    = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() }
11458    var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null
11459
11460    return $.extend({}, elRect, scroll, outerDims, elOffset)
11461  }
11462
11463  Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
11464    return placement == 'bottom' ? { top: pos.top + pos.height,   left: pos.left + pos.width / 2 - actualWidth / 2 } :
11465           placement == 'top'    ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :
11466           placement == 'left'   ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
11467        /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }
11468
11469  }
11470
11471  Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {
11472    var delta = { top: 0, left: 0 }
11473    if (!this.$viewport) return delta
11474
11475    var viewportPadding = this.options.viewport && this.options.viewport.padding || 0
11476    var viewportDimensions = this.getPosition(this.$viewport)
11477
11478    if (/right|left/.test(placement)) {
11479      var topEdgeOffset    = pos.top - viewportPadding - viewportDimensions.scroll
11480      var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight
11481      if (topEdgeOffset < viewportDimensions.top) { // top overflow
11482        delta.top = viewportDimensions.top - topEdgeOffset
11483      } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow
11484        delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset
11485      }
11486    } else {
11487      var leftEdgeOffset  = pos.left - viewportPadding
11488      var rightEdgeOffset = pos.left + viewportPadding + actualWidth
11489      if (leftEdgeOffset < viewportDimensions.left) { // left overflow
11490        delta.left = viewportDimensions.left - leftEdgeOffset
11491      } else if (rightEdgeOffset > viewportDimensions.right) { // right overflow
11492        delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
11493      }
11494    }
11495
11496    return delta
11497  }
11498
11499  Tooltip.prototype.getTitle = function () {
11500    var title
11501    var $e = this.$element
11502    var o  = this.options
11503
11504    title = $e.attr('data-original-title')
11505      || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)
11506
11507    return title
11508  }
11509
11510  Tooltip.prototype.getUID = function (prefix) {
11511    do prefix += ~~(Math.random() * 1000000)
11512    while (document.getElementById(prefix))
11513    return prefix
11514  }
11515
11516  Tooltip.prototype.tip = function () {
11517    if (!this.$tip) {
11518      this.$tip = $(this.options.template)
11519      if (this.$tip.length != 1) {
11520        throw new Error(this.type + ' `template` option must consist of exactly 1 top-level element!')
11521      }
11522    }
11523    return this.$tip
11524  }
11525
11526  Tooltip.prototype.arrow = function () {
11527    return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))
11528  }
11529
11530  Tooltip.prototype.enable = function () {
11531    this.enabled = true
11532  }
11533
11534  Tooltip.prototype.disable = function () {
11535    this.enabled = false
11536  }
11537
11538  Tooltip.prototype.toggleEnabled = function () {
11539    this.enabled = !this.enabled
11540  }
11541
11542  Tooltip.prototype.toggle = function (e) {
11543    var self = this
11544    if (e) {
11545      self = $(e.currentTarget).data('bs.' + this.type)
11546      if (!self) {
11547        self = new this.constructor(e.currentTarget, this.getDelegateOptions())
11548        $(e.currentTarget).data('bs.' + this.type, self)
11549      }
11550    }
11551
11552    if (e) {
11553      self.inState.click = !self.inState.click
11554      if (self.isInStateTrue()) self.enter(self)
11555      else self.leave(self)
11556    } else {
11557      self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
11558    }
11559  }
11560
11561  Tooltip.prototype.destroy = function () {
11562    var that = this
11563    clearTimeout(this.timeout)
11564    this.hide(function () {
11565      that.$element.off('.' + that.type).removeData('bs.' + that.type)
11566      if (that.$tip) {
11567        that.$tip.detach()
11568      }
11569      that.$tip = null
11570      that.$arrow = null
11571      that.$viewport = null
11572    })
11573  }
11574
11575
11576  // TOOLTIP PLUGIN DEFINITION
11577  // =========================
11578
11579  function Plugin(option) {
11580    return this.each(function () {
11581      var $this   = $(this)
11582      var data    = $this.data('bs.tooltip')
11583      var options = typeof option == 'object' && option
11584
11585      if (!data && /destroy|hide/.test(option)) return
11586      if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
11587      if (typeof option == 'string') data[option]()
11588    })
11589  }
11590
11591  var old = $.fn.tooltip
11592
11593  $.fn.tooltip             = Plugin
11594  $.fn.tooltip.Constructor = Tooltip
11595
11596
11597  // TOOLTIP NO CONFLICT
11598  // ===================
11599
11600  $.fn.tooltip.noConflict = function () {
11601    $.fn.tooltip = old
11602    return this
11603  }
11604
11605}(jQuery);
11606
11607/* ========================================================================
11608 * Bootstrap: popover.js v3.3.
vendor: 14,729 bytes, lines 11608-12130
116086
11609 * http://getbootstrap.com/javascript/#popovers
11610 * ========================================================================
11611 * Copyright 2011-2015 Twitter, Inc.
11612 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
11613 * ======================================================================== */
11614
11615
11616+function ($) {
11617  'use strict';
11618
11619  // POPOVER PUBLIC CLASS DEFINITION
11620  // ===============================
11621
11622  var Popover = function (element, options) {
11623    this.init('popover', element, options)
11624  }
11625
11626  if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
11627
11628  Popover.VERSION  = '3.3.6'
11629
11630  Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
11631    placement: 'right',
11632    trigger: 'click',
11633    content: '',
11634    template: '<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
11635  })
11636
11637
11638  // NOTE: POPOVER EXTENDS tooltip.js
11639  // ================================
11640
11641  Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)
11642
11643  Popover.prototype.constructor = Popover
11644
11645  Popover.prototype.getDefaults = function () {
11646    return Popover.DEFAULTS
11647  }
11648
11649  Popover.prototype.setContent = function () {
11650    var $tip    = this.tip()
11651    var title   = this.getTitle()
11652    var content = this.getContent()
11653
11654    $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
11655    $tip.find('.popover-content').children().detach().end()[ // we use append for html objects to maintain js events
11656      this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'
11657    ](content)
11658
11659    $tip.removeClass('fade top bottom left right in')
11660
11661    // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
11662    // this manually by checking the contents.
11663    if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()
11664  }
11665
11666  Popover.prototype.hasContent = function () {
11667    return this.getTitle() || this.getContent()
11668  }
11669
11670  Popover.prototype.getContent = function () {
11671    var $e = this.$element
11672    var o  = this.options
11673
11674    return $e.attr('data-content')
11675      || (typeof o.content == 'function' ?
11676            o.content.call($e[0]) :
11677            o.content)
11678  }
11679
11680  Popover.prototype.arrow = function () {
11681    return (this.$arrow = this.$arrow || this.tip().find('.arrow'))
11682  }
11683
11684
11685  // POPOVER PLUGIN DEFINITION
11686  // =========================
11687
11688  function Plugin(option) {
11689    return this.each(function () {
11690      var $this   = $(this)
11691      var data    = $this.data('bs.popover')
11692      var options = typeof option == 'object' && option
11693
11694      if (!data && /destroy|hide/.test(option)) return
11695      if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
11696      if (typeof option == 'string') data[option]()
11697    })
11698  }
11699
11700  var old = $.fn.popover
11701
11702  $.fn.popover             = Plugin
11703  $.fn.popover.Constructor = Popover
11704
11705
11706  // POPOVER NO CONFLICT
11707  // ===================
11708
11709  $.fn.popover.noConflict = function () {
11710    $.fn.popover = old
11711    return this
11712  }
11713
11714}(jQuery);
11715
11716/* ========================================================================
11717 * Bootstrap: scrollspy.js v3.3.6
11718 * http://getbootstrap.com/javascript/#scrollspy
11719 * ========================================================================
11720 * Copyright 2011-2015 Twitter, Inc.
11721 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
11722 * ======================================================================== */
11723
11724
11725+function ($) {
11726  'use strict';
11727
11728  // SCROLLSPY CLASS DEFINITION
11729  // ==========================
11730
11731  function ScrollSpy(element, options) {
11732    this.$body          = $(document.body)
11733    this.$scrollElement = $(element).is(document.body) ? $(window) : $(element)
11734    this.options        = $.extend({}, ScrollSpy.DEFAULTS, options)
11735    this.selector       = (this.options.target || '') + ' .nav li > a'
11736    this.offsets        = []
11737    this.targets        = []
11738    this.activeTarget   = null
11739    this.scrollHeight   = 0
11740
11741    this.$scrollElement.on('scroll.bs.scrollspy', $.proxy(this.process, this))
11742    this.refresh()
11743    this.process()
11744  }
11745
11746  ScrollSpy.VERSION  = '3.3.6'
11747
11748  ScrollSpy.DEFAULTS = {
11749    offset: 10
11750  }
11751
11752  ScrollSpy.prototype.getScrollHeight = function () {
11753    return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight)
11754  }
11755
11756  ScrollSpy.prototype.refresh = function () {
11757    var that          = this
11758    var offsetMethod  = 'offset'
11759    var offsetBase    = 0
11760
11761    this.offsets      = []
11762    this.targets      = []
11763    this.scrollHeight = this.getScrollHeight()
11764
11765    if (!$.isWindow(this.$scrollElement[0])) {
11766      offsetMethod = 'position'
11767      offsetBase   = this.$scrollElement.scrollTop()
11768    }
11769
11770    this.$body
11771      .find(this.selector)
11772      .map(function () {
11773        var $el   = $(this)
11774        var href  = $el.data('target') || $el.attr('href')
11775        var $href = /^#./.test(href) && $(href)
11776
11777        return ($href
11778          && $href.length
11779          && $href.is(':visible')
11780          && [[$href[offsetMethod]().top + offsetBase, href]]) || null
11781      })
11782      .sort(function (a, b) { return a[0] - b[0] })
11783      .each(function () {
11784        that.offsets.push(this[0])
11785        that.targets.push(this[1])
11786      })
11787  }
11788
11789  ScrollSpy.prototype.process = function () {
11790    var scrollTop    = this.$scrollElement.scrollTop() + this.options.offset
11791    var scrollHeight = this.getScrollHeight()
11792    var maxScroll    = this.options.offset + scrollHeight - this.$scrollElement.height()
11793    var offsets      = this.offsets
11794    var targets      = this.targets
11795    var activeTarget = this.activeTarget
11796    var i
11797
11798    if (this.scrollHeight != scrollHeight) {
11799      this.refresh()
11800    }
11801
11802    if (scrollTop >= maxScroll) {
11803      return activeTarget != (i = targets[targets.length - 1]) && this.activate(i)
11804    }
11805
11806    if (activeTarget && scrollTop < offsets[0]) {
11807      this.activeTarget = null
11808      return this.clear()
11809    }
11810
11811    for (i = offsets.length; i--;) {
11812      activeTarget != targets[i]
11813        && scrollTop >= offsets[i]
11814        && (offsets[i + 1] === undefined || scrollTop < offsets[i + 1])
11815        && this.activate(targets[i])
11816    }
11817  }
11818
11819  ScrollSpy.prototype.activate = function (target) {
11820    this.activeTarget = target
11821
11822    this.clear()
11823
11824    var selector = this.selector +
11825      '[data-target="' + target + '"],' +
11826      this.selector + '[href="' + target + '"]'
11827
11828    var active = $(selector)
11829      .parents('li')
11830      .addClass('active')
11831
11832    if (active.parent('.dropdown-menu').length) {
11833      active = active
11834        .closest('li.dropdown')
11835        .addClass('active')
11836    }
11837
11838    active.trigger('activate.bs.scrollspy')
11839  }
11840
11841  ScrollSpy.prototype.clear = function () {
11842    $(this.selector)
11843      .parentsUntil(this.options.target, '.active')
11844      .removeClass('active')
11845  }
11846
11847
11848  // SCROLLSPY PLUGIN DEFINITION
11849  // ===========================
11850
11851  function Plugin(option) {
11852    return this.each(function () {
11853      var $this   = $(this)
11854      var data    = $this.data('bs.scrollspy')
11855      var options = typeof option == 'object' && option
11856
11857      if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))
11858      if (typeof option == 'string') data[option]()
11859    })
11860  }
11861
11862  var old = $.fn.scrollspy
11863
11864  $.fn.scrollspy             = Plugin
11865  $.fn.scrollspy.Constructor = ScrollSpy
11866
11867
11868  // SCROLLSPY NO CONFLICT
11869  // =====================
11870
11871  $.fn.scrollspy.noConflict = function () {
11872    $.fn.scrollspy = old
11873    return this
11874  }
11875
11876
11877  // SCROLLSPY DATA-API
11878  // ==================
11879
11880  $(window).on('load.bs.scrollspy.data-api', function () {
11881    $('[data-spy="scroll"]').each(function () {
11882      var $spy = $(this)
11883      Plugin.call($spy, $spy.data())
11884    })
11885  })
11886
11887}(jQuery);
11888
11889/* ========================================================================
11890 * Bootstrap: tab.js v3.3.6
11891 * http://getbootstrap.com/javascript/#tabs
11892 * ========================================================================
11893 * Copyright 2011-2015 Twitter, Inc.
11894 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
11895 * ======================================================================== */
11896
11897
11898+function ($) {
11899  'use strict';
11900
11901  // TAB CLASS DEFINITION
11902  // ====================
11903
11904  var Tab = function (element) {
11905    // jscs:disable requireDollarBeforejQueryAssignment
11906    this.element = $(element)
11907    // jscs:enable requireDollarBeforejQueryAssignment
11908  }
11909
11910  Tab.VERSION = '3.3.6'
11911
11912  Tab.TRANSITION_DURATION = 150
11913
11914  Tab.prototype.show = function () {
11915    var $this    = this.element
11916    var $ul      = $this.closest('ul:not(.dropdown-menu)')
11917    var selector = $this.data('target')
11918
11919    if (!selector) {
11920      selector = $this.attr('href')
11921      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
11922    }
11923
11924    if ($this.parent('li').hasClass('active')) return
11925
11926    var $previous = $ul.find('.active:last a')
11927    var hideEvent = $.Event('hide.bs.tab', {
11928      relatedTarget: $this[0]
11929    })
11930    var showEvent = $.Event('show.bs.tab', {
11931      relatedTarget: $previous[0]
11932    })
11933
11934    $previous.trigger(hideEvent)
11935    $this.trigger(showEvent)
11936
11937    if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return
11938
11939    var $target = $(selector)
11940
11941    this.activate($this.closest('li'), $ul)
11942    this.activate($target, $target.parent(), function () {
11943      $previous.trigger({
11944        type: 'hidden.bs.tab',
11945        relatedTarget: $this[0]
11946      })
11947      $this.trigger({
11948        type: 'shown.bs.tab',
11949        relatedTarget: $previous[0]
11950      })
11951    })
11952  }
11953
11954  Tab.prototype.activate = function (element, container, callback) {
11955    var $active    = container.find('> .active')
11956    var transition = callback
11957      && $.support.transition
11958      && ($active.length && $active.hasClass('fade') || !!container.find('> .fade').length)
11959
11960    function next() {
11961      $active
11962        .removeClass('active')
11963        .find('> .dropdown-menu > .active')
11964          .removeClass('active')
11965        .end()
11966        .find('[data-toggle="tab"]')
11967          .attr('aria-expanded', false)
11968
11969      element
11970        .addClass('active')
11971        .find('[data-toggle="tab"]')
11972          .attr('aria-expanded', true)
11973
11974      if (transition) {
11975        element[0].offsetWidth // reflow for transition
11976        element.addClass('in')
11977      } else {
11978        element.removeClass('fade')
11979      }
11980
11981      if (element.parent('.dropdown-menu').length) {
11982        element
11983          .closest('li.dropdown')
11984            .addClass('active')
11985          .end()
11986          .find('[data-toggle="tab"]')
11987            .attr('aria-expanded', true)
11988      }
11989
11990      callback && callback()
11991    }
11992
11993    $active.length && transition ?
11994      $active
11995        .one('bsTransitionEnd', next)
11996        .emulateTransitionEnd(Tab.TRANSITION_DURATION) :
11997      next()
11998
11999    $active.removeClass('in')
12000  }
12001
12002
12003  // TAB PLUGIN DEFINITION
12004  // =====================
12005
12006  function Plugin(option) {
12007    return this.each(function () {
12008      var $this = $(this)
12009      var data  = $this.data('bs.tab')
12010
12011      if (!data) $this.data('bs.tab', (data = new Tab(this)))
12012      if (typeof option == 'string') data[option]()
12013    })
12014  }
12015
12016  var old = $.fn.tab
12017
12018  $.fn.tab             = Plugin
12019  $.fn.tab.Constructor = Tab
12020
12021
12022  // TAB NO CONFLICT
12023  // ===============
12024
12025  $.fn.tab.noConflict = function () {
12026    $.fn.tab = old
12027    return this
12028  }
12029
12030
12031  // TAB DATA-API
12032  // ============
12033
12034  var clickHandler = function (e) {
12035    e.preventDefault()
12036    Plugin.call($(this), 'show')
12037  }
12038
12039  $(document)
12040    .on('click.bs.tab.data-api', '[data-toggle="tab"]', clickHandler)
12041    .on('click.bs.tab.data-api', '[data-toggle="pill"]', clickHandler)
12042
12043}(jQuery);
12044
12045/* ========================================================================
12046 * Bootstrap: affix.js v3.3.6
12047 * http://getbootstrap.com/javascript/#affix
12048 * ========================================================================
12049 * Copyright 2011-2015 Twitter, Inc.
12050 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
12051 * ======================================================================== */
12052
12053
12054+function ($) {
12055  'use strict';
12056
12057  // AFFIX CLASS DEFINITION
12058  // ======================
12059
12060  var Affix = function (element, options) {
12061    this.options = $.extend({}, Affix.DEFAULTS, options)
12062
12063    this.$target = $(this.options.target)
12064      .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))
12065      .on('click.bs.affix.data-api',  $.proxy(this.checkPositionWithEventLoop, this))
12066
12067    this.$element     = $(element)
12068    this.affixed      = null
12069    this.unpin        = null
12070    this.pinnedOffset = null
12071
12072    this.checkPosition()
12073  }
12074
12075  Affix.VERSION  = '3.3.6'
12076
12077  Affix.RESET    = 'affix affix-top affix-bottom'
12078
12079  Affix.DEFAULTS = {
12080    offset: 0,
12081    target: window
12082  }
12083
12084  Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) {
12085    var scrollTop    = this.$target.scrollTop()
12086    var position     = this.$element.offset()
12087    var targetHeight = this.$target.height()
12088
12089    if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false
12090
12091    if (this.affixed == 'bottom') {
12092      if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom'
12093      return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom'
12094    }
12095
12096    var initializing   = this.affixed == null
12097    var colliderTop    = initializing ? scrollTop : position.top
12098    var colliderHeight = initializing ? targetHeight : height
12099
12100    if (offsetTop != null && scrollTop <= offsetTop) return 'top'
12101    if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom'
12102
12103    return false
12104  }
12105
12106  Affix.prototype.getPinnedOffset = function () {
12107    if (this.pinnedOffset) return this.pinnedOffset
12108    this.$element.removeClass(Affix.RESET).addClass('affix')
12109    var scrollTop = this.$target.scrollTop()
12110    var position  = this.$element.offset()
12111    return (this.pinnedOffset = position.top - scrollTop)
12112  }
12113
12114  Affix.prototype.checkPositionWithEventLoop = function () {
12115    setTimeout($.proxy(this.checkPosition, this), 1)
12116  }
12117
12118  Affix.prototype.checkPosition = function () {
12119    if (!this.$element.is(':visible')) return
12120
12121    var height       = this.$element.height()
12122    var offset       = this.options.offset
12123    var offsetTop    = offset.top
12124    var offsetBottom = offset.bottom
12125    var scrollHeight = Math.max($(document).height(), $(document.body).height())
12126
12127    if (typeof offset != 'object')         offsetBottom = offsetTop = offset
12128    if (typeof offsetTop == 'function')    offsetTop    = offset.top(this.$element)
12129    if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)
12130
12131    var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom)
12132
12133    if (this.affixed != affix) {
12134      if (this.unpin != null) this.$element.css('top', '')
12135
12136      var affixType = 'affix' + (affix ? '-' + affix : '')
12137      var e         = $.Event(affixType + '.bs.affix')
12138
12139      this.$element.trigger(e)
12140
12141      if (e.isDefaultPrevented()) return
12142
12143      this.affixed = affix
12144      this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null
12145
12146      this.$element
12147        .removeClass(Affix.RESET)
12148        .addClass(affixType)
12149        .trigger(affixType.replace('affix', 'affixed') + '.bs.affix')
12150    }
12151
12152    if (affix == 'bottom') {
12153      this.$element.offset({
12154        top: scrollHeight - height - offsetBottom
12155      })
12156    }
12157  }
12158
12159
12160  // AFFIX PLUGIN DEFINITION
12161  // =======================
12162
12163  function Plugin(option) {
12164    return this.each(function () {
12165      var $this   = $(this)
12166      var data    = $this.data('bs.affix')
12167      var options = typeof option == 'object' && option
12168
12169      if (!data) $this.data('bs.affix', (data = new Affix(this, options)))
12170      if (typeof option == 'string') data[option]()
12171    })
12172  }
12173
12174  var old = $.fn.affix
12175
12176  $.fn.affix             = Plugin
12177  $.fn.affix.Constructor = Affix
12178
12179
12180  // AFFIX NO CONFLICT
12181  // =================
12182
12183  $.fn.affix.noConflict = function () {
12184    $.fn.affix = old
12185    return this
12186  }
12187
12188
12189  // AFFIX DATA-API
12190  // ==============
12191
12192  $(window).on('load', function () {
12193    $('[data-spy="affix"]').each(function () {
12194      var $spy = $(this)
12195      var data = $spy.data()
12196
12197      data.offset = data.offset || {}
12198
12199      if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom
12200      if (data.offsetTop    != null) data.offset.top    = data.offsetTop
12201
12202      Plugin.call($spy, data)
12203    })
12204  })
12205
12206}(jQuery);
12207
12208// Generated by CoffeeScript 1.8.0
12209
12210/*
12211jQuery Credit Card Validator 1.0
12212
12213Copyright 2012-2015 Pawel Decowski
12214
12215Permission is hereby granted, free of charge, to any person obtaining a copy
12216of this software and associated documentation files (the "Software"), to deal
12217in the Software without restriction, including without limitation the rights
12218to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12219copies of the Software, and to permit persons to whom the Software
12220is furnished to do so, subject to the following conditions:
12221
12222The above copyright notice and this permission notice shall be included
12223in all copies or substantial portions of the Software.
12224
12225THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12226OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12227FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
12228THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
12229LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
12230OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
12231IN THE SOFTWARE.
12232 */
12233
12234(function() {
12235  var $,
12236    __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
12237
12238  $ = jQuery;
12239
12240  $.fn.validateCreditCard = function(callback, options) {
12241    var bind, card, card_type, card_types, get_card_type, is_valid_length, is_valid_luhn, normalize, validate, validate_number, _i, _len, _ref;
12242    card_types = [
12243      {
12244        name: 'amex',
12245        pattern: /^3[47]/,
12246        valid_length: [15]
12247      }, {
12248        name: 'diners_club_carte_blanche',
12249        pattern: /^30[0-5]/,
12250        valid_length: [14]
12251      }, {
12252        name: 'diners_club_international',
12253        pattern: /^36/,
12254        valid_length: [14]
12255      }, {
12256        name: 'jcb',
12257        pattern: /^35(2[89]|[3-8][0-9])/,
12258        valid_length: [16]
12259      }, {
12260        name: 'laser',
12261        pattern: /^(6304|670[69]|6771)/,
12262        valid_length: [16, 17, 18, 19]
12263      }, {
12264        name: 'visa_electron',
12265        pattern: /^(4026|417500|4508|4844|491(3|7))/,
12266        valid_length: [16]
12267      }, {
12268        name: 'visa',
12269        pattern: /^4/,
12270        valid_length: [16]
12271      }, {
12272        name: 'mastercard',
12273        pattern: /^5[1-5]/,
12274        valid_length: [16]
12275      }, {
12276        name: 'maestro',
12277        pattern: /^(5018|5020|5038|6304|6759|676[1-3])/,
12278        valid_length: [12, 13, 14, 15, 16, 17, 18, 19]
12279      }, {
12280        name: 'discover',
12281        pattern: /^(6011|622(12[6-9]|1[3-9][0-9]|[2-8][0-9]{2}|9[0-1][0-9]|92[0-5]|64[4-9])|65)/,
12282        valid_length: [16]
12283      }
12284    ];
12285    bind = false;
12286    if (callback) {
12287      if (typeof callback === 'object') {
12288        options = callback;
12289        bind = false;
12290        callback = null;
12291      } else if (typeof callback === 'function') {
12292        bind = true;
12293      }
12294    }
12295    if (options == null) {
12296      options = {};
12297    }
12298    if (options.accept == null) {
12299      options.accept = (function() {
12300        var _i, _len, _results;
12301        _results = [];
12302        for (_i = 0, _len = card_types.length; _i < _len; _i++) {
12303          card = card_types[_i];
12304          _results.push(card.name);
12305        }
12306        return _results;
12307      })();
12308    }
12309    _ref = options.accept;
12310    for (_i = 0, _len = _ref.length; _i < _len; _i++) {
12311      card_type = _ref[_i];
12312      if (__indexOf.call((function() {
12313        var _j, _len1, _results;
12314        _results = [];
12315        for (_j = 0, _len1 = card_types.length; _j < _len1; _j++) {
12316          card = card_types[_j];
12317          _results.push(card.name);
12318        }
12319        return _results;
12320      })(), card_type) < 0) {
12321        throw "Credit card type '" + card_type + "' is not supported";
12322      }
12323    }
12324    get_card_type = function(number) {
12325      var _j, _len1, _ref1;
12326      _ref1 = (function() {
12327        var _k, _len1, _ref1, _results;
12328        _results = [];
12329        for (_k = 0, _len1 = card_types.length; _k < _len1; _k++) {
12330          card = card_types[_k];
12331          if (_ref1 = card.name, __indexOf.call(options.accept, _ref1) >= 0) {
12332            _results.push(card);
12333          }
12334        }
12335        return _results;
12336      })();
12337      for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
12338        card_type = _ref1[_j];
12339        if (number.match(card_type.pattern)) {
12340          return card_type;
12341        }
12342      }
12343      return null;
12344    };
12345    is_valid_luhn = function(number) {
12346      var digit, n, sum, _j, _len1, _ref1;
12347      sum = 0;
12348      _ref1 = number.split('').reverse();
12349      for (n = _j = 0, _len1 = _ref1.length; _j < _len1; n = ++_j) {
12350        digit = _ref1[n];
12351        digit = +digit;
12352        if (n % 2) {
12353          digit *= 2;
12354          if (digit < 10) {
12355            sum += digit;
12356          } else {
12357            sum += digit - 9;
12358          }
12359        } else {
12360          sum += digit;
12361        }
12362      }
12363      return sum % 10 === 0;
12364    };
12365    is_valid_length = function(number, card_type) {
12366      var _ref1;
12367      return _ref1 = number.length, __indexOf.call(card_type.valid_length, _ref1) >= 0;
12368    };
12369    validate_number = (function(_this) {
12370      return function(number) {
12371        var length_valid, luhn_valid;
12372        card_type = get_card_type(number);
12373        luhn_valid = false;
12374        length_valid = false;
12375        if (card_type != null) {
12376          luhn_valid = is_valid_luhn(number);
12377          length_valid = is_valid_length(number, card_type);
12378        }
12379        return {
12380          card_type: card_type,
12381          valid: luhn_valid && length_valid,
12382          luhn_valid: luhn_valid,
12383          length_valid: length_valid
12384        };
12385      };
12386    })(this);
12387    validate = (function(_this) {
12388      return function() {
12389        var number;
12390        number = normalize($(_this).val());
12391        return validate_number(number);
12392      };
12393    })(this);
12394    normalize = function(number) {
12395      return number.replace(/[ -]/g, '');
12396    };
12397    if (!bind) {
12398      return validate();
12399    }
12400    this.on('input.jccv', (function(_this) {
12401      return function() {
12402        $(_this).off('keyup.jccv');
12403        return callback.call(_this, validate());
12404      };
12405    })(this));
12406    this.on('keyup.jccv', (function(_this) {
12407      return function() {
12408        return callback.call(_this, validate());
12409      };
12410    })(this));
12411    callback.call(this, validate());
12412    return this;
12413  };
12414
12415}).call(this);
12416
12417/**
12418 * EvEmitter v1.0.2
12419 * Lil' event emitter
12420 * MIT License
12421 */
12422
12423/* jshint unused: true, undef: true, strict: true */
12424
12425( function( global, factory ) {
12426  // universal module definition
12427  /* jshint strict: false */ /* globals define, module */
12428  if ( typeof define == 'function' && define.amd ) {
12429    // AMD - RequireJS
12430    define( factory );
12431  } else if ( typeof module == 'object' && module.exports ) {
12432    // CommonJS - Browserify, Webpack
12433    module.exports = factory();
12434  } else {
12435    // Browser globals
12436    global.EvEmitter = factory();
12437  }
12438
12439}( this, function() {
12440
12441"use strict";
12442
12443function EvEmitter() {}
12444
12445var proto = EvEmitter.prototype;
12446
12447proto.on = function( eventName, listener ) {
12448  if ( !eventName || !listener ) {
12449    return;
12450  }
12451  // set events hash
12452  var events = this._events = this._events || {};
12453  // set listeners array
12454  var listeners = events[ eventName ] = events[ eventName ] || [];
12455  // only add once
12456  if ( listeners.indexOf( listener ) == -1 ) {
12457    listeners.push( listener );
12458  }
12459
12460  return this;
12461};
12462
12463proto.once = function( eventName, listener ) {
12464  if ( !eventName || !listener ) {
12465    return;
12466  }
12467  // add event
12468  this.on( eventName, listener );
12469  // set once flag
12470  // set onceEvents hash
12471  var onceEvents = this._onceEvents = this._onceEvents || {};
12472  // set onceListeners object
12473  var onceListeners = onceEvents[ eventName ] = onceEvents[ eventName ] || {};
12474  // set flag
12475  onceListeners[ listener ] = true;
12476
12477  return this;
12478};
12479
12480proto.off = function( eventName, listener ) {
12481  var listeners = this._events && this._events[ eventName ];
12482  if ( !listeners || !listeners.length ) {
12483    return;
12484  }
12485  var index = listeners.indexOf( listener );
12486  if ( index != -1 ) {
12487    listeners.splice( index, 1 );
12488  }
12489
12490  return this;
12491};
12492
12493proto.emitEvent = function( eventName, args ) {
12494  var listeners = this._events && this._events[ eventName ];
12495  if ( !listeners || !listeners.length ) {
12496    return;
12497  }
12498  var i = 0;
12499  var listener = listeners[i];
12500  args = args || [];
12501  // once stuff
12502  var onceListeners = this._onceEvents && this._onceEvents[ eventName ];
12503
12504  while ( listener ) {
12505    var isOnce = onceListeners && onceListeners[ listener ];
12506    if ( isOnce ) {
12507      // remove listener
12508      // remove before trigger to prevent recursion
12509      this.off( eventName, listener );
12510      // unset once flag
12511      delete onceListeners[ listener ];
12512    }
12513    // trigger listener
12514    listener.apply( this, args );
12515    // get next listener
12516    i += isOnce ? 0 : 1;
12517    listener = listeners[i];
12518  }
12519
12520  return this;
12521};
12522
12523return EvEmitter;
12524
12525}));
12526
12527/*!
12528 * Select2 4.0.1
12529 * https://select2.github.io
12530 *
12531 * Released under the MIT license
12532 * https://github.com/select2/select2/blob/master/LICENSE.md
12533 */
12534(function (factory) {
12535  if (typeof define === 'function' && define.amd) {
12536    // AMD. Register as an anonymous module.
12537    define(['jquery'], factory);
12538  } else if (typeof exports === 'object') {
12539    // Node/CommonJS
12540    factory(require('jquery'));
12541  } else {
12542    // Browser globals
12543    factory(jQuery);
12544  }
12545}(function (jQuery) {
12546  // This is needed so we can catch the AMD loader configuration and use it
12547  // The inner file should be wrapped (by `banner.start.js`) in a function that
12548  // returns the AMD loader references.
12549  var S2 =
12550(function () {
12551  // Restore the Select2 AMD loader so it can be used
12552  // Needed mostly in the language files, where the loader is not inserted
12553  if (jQuery && jQuery.fn && jQuery.fn.select2 && jQuery.fn.select2.amd) {
12554    var S2 = jQuery.fn.select2.amd;
12555  }
12556var S2;(function () { if (!S2 || !S2.requirejs) {
12557if (!S2) { S2 = {}; } else { require = S2; }
12558/**
12559 * @license almond 0.3.1 Copyright (c) 2011-2014, The Dojo Foundation All Rights Reserved.
12560 * Available via the MIT or new BSD license.
12561 * see: http://github.com/jrburke/almond for details
12562 */
12563//Going sloppy to avoid 'use strict' string cost, but strict practices should
12564//be followed.
12565/*jslint sloppy: true */
12566/*global setTimeout: false */
12567
12568var requirejs, require, define;
12569(function (undef) {
12570    var main, req, makeMap, handlers,
12571        defined = {},
12572        waiting = {},
12573        config = {},
12574        defining = {},
12575        hasOwn = Object.prototype.hasOwnProperty,
12576        aps = [].slice,
12577        jsSuffixRegExp = /\.js$/;
12578
12579    function hasProp(obj, prop) {
12580        return hasOwn.call(obj, prop);
12581    }
12582
12583    /**
12584     * Given a relative module name, like ./something, normalize it to
12585     * a real name that can be mapped to a path.
12586     * @param {String} name the relative name
12587     * @param {String} baseName a real name that the name arg is relative
12588     * to.
12589     * @returns {String} normalized name
12590     */
12591    function normalize(name, baseName) {
12592        var nameParts, nameSegment, mapValue, foundMap, lastIndex,
12593            foundI, foundStarMap, starI, i, j, part,
12594            baseParts = baseName && baseName.split("/"),
12595            map = config.map,
12596            starMap = (map && map['*']) || {};
12597
12598        //Adjust any relative paths.
12599        if (name && name.charAt(0) === ".") {
12600            //If have a base name, try to normalize against it,
12601            //otherwise, assume it is a top-level require that will
12602            //be relative to baseUrl in the end.
12603            if (baseName) {
12604                name = name.split('/');
12605                lastIndex = name.length - 1;
12606
12607                // Node .js allowance:
12608                if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) {
12609                    name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, '');
12610                }
12611
12612                //Lop off the last part of baseParts, so that . matches the
12613                //"directory" and not name of the baseName's module. For instance,
12614                //baseName of "one/two/three", maps to "one/two/three.js", but we
12615                //want the directory, "one/two" for this normalization.
12616                name = baseParts.slice(0, baseParts.length - 1).concat(name);
12617
12618                //start trimDots
12619                for (i = 0; i < name.length; i += 1) {
12620                    part = name[i];
12621                    if (part === ".") {
12622                        name.splice(i, 1);
12623                        i -= 1;
12624                    } else if (part === "..") {
12625                        if (i === 1 && (name[2] === '..' || name[0] === '..')) {
12626                            //End of the line. Keep at least one non-dot
12627                            //path segment at the front so it can be mapped
12628                            //correctly to disk. Otherwise, there is likely
12629                            //no path mapping for a path starting with '..'.
12630                            //This can still fail, but catches the most reasonable
12631                            //uses of ..
12632                            break;
12633                        } else if (i > 0) {
12634                            name.splice(i - 1, 2);
12635                            i -= 2;
12636                        }
12637                    }
12638                }
12639                //end trimDots
12640
12641                name = name.join("/");
12642            } else if (name.indexOf('./') === 0) {
12643                // No baseName, so this is ID is resolved relative
12644                // to baseUrl, pull off the leading dot.
12645                name = name.substring(2);
12646            }
12647        }
12648
12649        //Apply map config if available.
12650        if ((baseParts || starMap) && map) {
vendor: 8,882 bytes, lines 12651-12904
12651            nameParts = name.split('/');
12652
12653            for (i = nameParts.length; i > 0; i -= 1) {
12654                nameSegment = nameParts.slice(0, i).join("/");
12655
12656                if (baseParts) {
12657                    //Find the longest baseName segment match in the config.
12658                    //So, do joins on the biggest to smallest lengths of baseParts.
12659                    for (j = baseParts.length; j > 0; j -= 1) {
12660                        mapValue = map[baseParts.slice(0, j).join('/')];
12661
12662                        //baseName segment has  config, find if it has one for
12663                        //this name.
12664                        if (mapValue) {
12665                            mapValue = mapValue[nameSegment];
12666                            if (mapValue) {
12667                                //Match, update name to the new value.
12668                                foundMap = mapValue;
12669                                foundI = i;
12670                                break;
12671                            }
12672                        }
12673                    }
12674                }
12675
12676                if (foundMap) {
12677                    break;
12678                }
12679
12680                //Check for a star map match, but just hold on to it,
12681                //if there is a shorter segment match later in a matching
12682                //config, then favor over this star map.
12683                if (!foundStarMap && starMap && starMap[nameSegment]) {
12684                    foundStarMap = starMap[nameSegment];
12685                    starI = i;
12686                }
12687            }
12688
12689            if (!foundMap && foundStarMap) {
12690                foundMap = foundStarMap;
12691                foundI = starI;
12692            }
12693
12694            if (foundMap) {
12695                nameParts.splice(0, foundI, foundMap);
12696                name = nameParts.join('/');
12697            }
12698        }
12699
12700        return name;
12701    }
12702
12703    function makeRequire(relName, forceSync) {
12704        return function () {
12705            //A version of a require function that passes a moduleName
12706            //value for items that may need to
12707            //look up paths relative to the moduleName
12708            var args = aps.call(arguments, 0);
12709
12710            //If first arg is not require('string'), and there is only
12711            //one arg, it is the array form without a callback. Insert
12712            //a null so that the following concat is correct.
12713            if (typeof args[0] !== 'string' && args.length === 1) {
12714                args.push(null);
12715            }
12716            return req.apply(undef, args.concat([relName, forceSync]));
12717        };
12718    }
12719
12720    function makeNormalize(relName) {
12721        return function (name) {
12722            return normalize(name, relName);
12723        };
12724    }
12725
12726    function makeLoad(depName) {
12727        return function (value) {
12728            defined[depName] = value;
12729        };
12730    }
12731
12732    function callDep(name) {
12733        if (hasProp(waiting, name)) {
12734            var args = waiting[name];
12735            delete waiting[name];
12736            defining[name] = true;
12737            main.apply(undef, args);
12738        }
12739
12740        if (!hasProp(defined, name) && !hasProp(defining, name)) {
12741            throw new Error('No ' + name);
12742        }
12743        return defined[name];
12744    }
12745
12746    //Turns a plugin!resource to [plugin, resource]
12747    //with the plugin being undefined if the name
12748    //did not have a plugin prefix.
12749    function splitPrefix(name) {
12750        var prefix,
12751            index = name ? name.indexOf('!') : -1;
12752        if (index > -1) {
12753            prefix = name.substring(0, index);
12754            name = name.substring(index + 1, name.length);
12755        }
12756        return [prefix, name];
12757    }
12758
12759    /**
12760     * Makes a name map, normalizing the name, and using a plugin
12761     * for normalization if necessary. Grabs a ref to plugin
12762     * too, as an optimization.
12763     */
12764    makeMap = function (name, relName) {
12765        var plugin,
12766            parts = splitPrefix(name),
12767            prefix = parts[0];
12768
12769        name = parts[1];
12770
12771        if (prefix) {
12772            prefix = normalize(prefix, relName);
12773            plugin = callDep(prefix);
12774        }
12775
12776        //Normalize according
12777        if (prefix) {
12778            if (plugin && plugin.normalize) {
12779                name = plugin.normalize(name, makeNormalize(relName));
12780            } else {
12781                name = normalize(name, relName);
12782            }
12783        } else {
12784            name = normalize(name, relName);
12785            parts = splitPrefix(name);
12786            prefix = parts[0];
12787            name = parts[1];
12788            if (prefix) {
12789                plugin = callDep(prefix);
12790            }
12791        }
12792
12793        //Using ridiculous property names for space reasons
12794        return {
12795            f: prefix ? prefix + '!' + name : name, //fullName
12796            n: name,
12797            pr: prefix,
12798            p: plugin
12799        };
12800    };
12801
12802    function makeConfig(name) {
12803        return function () {
12804            return (config && config.config && config.config[name]) || {};
12805        };
12806    }
12807
12808    handlers = {
12809        require: function (name) {
12810            return makeRequire(name);
12811        },
12812        exports: function (name) {
12813            var e = defined[name];
12814            if (typeof e !== 'undefined') {
12815                return e;
12816            } else {
12817                return (defined[name] = {});
12818            }
12819        },
12820        module: function (name) {
12821            return {
12822                id: name,
12823                uri: '',
12824                exports: defined[name],
12825                config: makeConfig(name)
12826            };
12827        }
12828    };
12829
12830    main = function (name, deps, callback, relName) {
12831        var cjsModule, depName, ret, map, i,
12832            args = [],
12833            callbackType = typeof callback,
12834            usingExports;
12835
12836        //Use name if no relName
12837        relName = relName || name;
12838
12839        //Call the callback to define the module, if necessary.
12840        if (callbackType === 'undefined' || callbackType === 'function') {
12841            //Pull out the defined dependencies and pass the ordered
12842            //values to the callback.
12843            //Default to [require, exports, module] if no deps
12844            deps = !deps.length && callback.length ? ['require', 'exports', 'module'] : deps;
12845            for (i = 0; i < deps.length; i += 1) {
12846                map = makeMap(deps[i], relName);
12847                depName = map.f;
12848
12849                //Fast path CommonJS standard dependencies.
12850                if (depName === "require") {
12851                    args[i] = handlers.require(name);
12852                } else if (depName === "exports") {
12853                    //CommonJS module spec 1.1
12854                    args[i] = handlers.exports(name);
12855                    usingExports = true;
12856                } else if (depName === "module") {
12857                    //CommonJS module spec 1.1
12858                    cjsModule = args[i] = handlers.module(name);
12859                } else if (hasProp(defined, depName) ||
12860                           hasProp(waiting, depName) ||
12861                           hasProp(defining, depName)) {
12862                    args[i] = callDep(depName);
12863                } else if (map.p) {
12864                    map.p.load(map.n, makeRequire(relName, true), makeLoad(depName), {});
12865                    args[i] = defined[depName];
12866                } else {
12867                    throw new Error(name + ' missing ' + depName);
12868                }
12869            }
12870
12871            ret = callback ? callback.apply(defined[name], args) : undefined;
12872
12873            if (name) {
12874                //If setting exports via "module" is in play,
12875                //favor that over return value and exports. After that,
12876                //favor a non-undefined return value over exports use.
12877                if (cjsModule && cjsModule.exports !== undef &&
12878                        cjsModule.exports !== defined[name]) {
12879                    defined[name] = cjsModule.exports;
12880                } else if (ret !== undef || !usingExports) {
12881                    //Use the return value from the function.
12882                    defined[name] = ret;
12883                }
12884            }
12885        } else if (name) {
12886            //May just be an object definition for the module. Only
12887            //worry about defining if have a module name.
12888            defined[name] = callback;
12889        }
12890    };
12891
12892    requirejs = require = req = function (deps, callback, relName, forceSync, alt) {
12893        if (typeof deps === "string") {
12894            if (handlers[deps]) {
12895                //callback in this case is really relName
12896                return handlers[deps](callback);
12897            }
12898            //Just return the module wanted. In this scenario, the
12899            //deps arg is the module name, and second arg (if passed)
12900            //is just the relName.
12901            //Normalize module name, if it contains . or ..
12902            return callDep(makeMap(deps, callback).f);
12903        } else if (!deps.splice) {
12904            //deps is a config object, not an array.
vendor: 38,023 bytes, lines 12905-14414
12905            config = deps;
12906            if (config.deps) {
12907                req(config.deps, config.callback);
12908            }
12909            if (!callback) {
12910                return;
12911            }
12912
12913            if (callback.splice) {
12914                //callback is an array, which means it is a dependency list.
12915                //Adjust args if there are dependencies
12916                deps = callback;
12917                callback = relName;
12918                relName = null;
12919            } else {
12920                deps = undef;
12921            }
12922        }
12923
12924        //Support require(['a'])
12925        callback = callback || function () {};
12926
12927        //If relName is a function, it is an errback handler,
12928        //so remove it.
12929        if (typeof relName === 'function') {
12930            relName = forceSync;
12931            forceSync = alt;
12932        }
12933
12934        //Simulate async callback;
12935        if (forceSync) {
12936            main(undef, deps, callback, relName);
12937        } else {
12938            //Using a non-zero value because of concern for what old browsers
12939            //do, and latest browsers "upgrade" to 4 if lower value is used:
12940            //http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#dom-windowtimers-settimeout:
12941            //If want a value immediately, use require('id') instead -- something
12942            //that works in almond on the global level, but not guaranteed and
12943            //unlikely to work in other AMD implementations.
12944            setTimeout(function () {
12945                main(undef, deps, callback, relName);
12946            }, 4);
12947        }
12948
12949        return req;
12950    };
12951
12952    /**
12953     * Just drops the config on the floor, but returns req in case
12954     * the config return value is used.
12955     */
12956    req.config = function (cfg) {
12957        return req(cfg);
12958    };
12959
12960    /**
12961     * Expose module registry for debugging and tooling
12962     */
12963    requirejs._defined = defined;
12964
12965    define = function (name, deps, callback) {
12966        if (typeof name !== 'string') {
12967            throw new Error('See almond README: incorrect module build, no module name');
12968        }
12969
12970        //This module may not have dependencies
12971        if (!deps.splice) {
12972            //deps is not an array, so probably means
12973            //an object literal or factory function for
12974            //the value. Adjust args.
12975            callback = deps;
12976            deps = [];
12977        }
12978
12979        if (!hasProp(defined, name) && !hasProp(waiting, name)) {
12980            waiting[name] = [name, deps, callback];
12981        }
12982    };
12983
12984    define.amd = {
12985        jQuery: true
12986    };
12987}());
12988
12989S2.requirejs = requirejs;S2.require = require;S2.define = define;
12990}
12991}());
12992S2.define("almond", function(){});
12993
12994/* global jQuery:false, $:false */
12995S2.define('jquery',[],function () {
12996  var _$ = jQuery || $;
12997
12998  if (_$ == null && console && console.error) {
12999    console.error(
13000      'Select2: An instance of jQuery or a jQuery-compatible library was not ' +
13001      'found. Make sure that you are including jQuery before Select2 on your ' +
13002      'web page.'
13003    );
13004  }
13005
13006  return _$;
13007});
13008
13009S2.define('select2/utils',[
13010  'jquery'
13011], function ($) {
13012  var Utils = {};
13013
13014  Utils.Extend = function (ChildClass, SuperClass) {
13015    var __hasProp = {}.hasOwnProperty;
13016
13017    function BaseConstructor () {
13018      this.constructor = ChildClass;
13019    }
13020
13021    for (var key in SuperClass) {
13022      if (__hasProp.call(SuperClass, key)) {
13023        ChildClass[key] = SuperClass[key];
13024      }
13025    }
13026
13027    BaseConstructor.prototype = SuperClass.prototype;
13028    ChildClass.prototype = new BaseConstructor();
13029    ChildClass.__super__ = SuperClass.prototype;
13030
13031    return ChildClass;
13032  };
13033
13034  function getMethods (theClass) {
13035    var proto = theClass.prototype;
13036
13037    var methods = [];
13038
13039    for (var methodName in proto) {
13040      var m = proto[methodName];
13041
13042      if (typeof m !== 'function') {
13043        continue;
13044      }
13045
13046      if (methodName === 'constructor') {
13047        continue;
13048      }
13049
13050      methods.push(methodName);
13051    }
13052
13053    return methods;
13054  }
13055
13056  Utils.Decorate = function (SuperClass, DecoratorClass) {
13057    var decoratedMethods = getMethods(DecoratorClass);
13058    var superMethods = getMethods(SuperClass);
13059
13060    function DecoratedClass () {
13061      var unshift = Array.prototype.unshift;
13062
13063      var argCount = DecoratorClass.prototype.constructor.length;
13064
13065      var calledConstructor = SuperClass.prototype.constructor;
13066
13067      if (argCount > 0) {
13068        unshift.call(arguments, SuperClass.prototype.constructor);
13069
13070        calledConstructor = DecoratorClass.prototype.constructor;
13071      }
13072
13073      calledConstructor.apply(this, arguments);
13074    }
13075
13076    DecoratorClass.displayName = SuperClass.displayName;
13077
13078    function ctr () {
13079      this.constructor = DecoratedClass;
13080    }
13081
13082    DecoratedClass.prototype = new ctr();
13083
13084    for (var m = 0; m < superMethods.length; m++) {
13085        var superMethod = superMethods[m];
13086
13087        DecoratedClass.prototype[superMethod] =
13088          SuperClass.prototype[superMethod];
13089    }
13090
13091    var calledMethod = function (methodName) {
13092      // Stub out the original method if it's not decorating an actual method
13093      var originalMethod = function () {};
13094
13095      if (methodName in DecoratedClass.prototype) {
13096        originalMethod = DecoratedClass.prototype[methodName];
13097      }
13098
13099      var decoratedMethod = DecoratorClass.prototype[methodName];
13100
13101      return function () {
13102        var unshift = Array.prototype.unshift;
13103
13104        unshift.call(arguments, originalMethod);
13105
13106        return decoratedMethod.apply(this, arguments);
13107      };
13108    };
13109
13110    for (var d = 0; d < decoratedMethods.length; d++) {
13111      var decoratedMethod = decoratedMethods[d];
13112
13113      DecoratedClass.prototype[decoratedMethod] = calledMethod(decoratedMethod);
13114    }
13115
13116    return DecoratedClass;
13117  };
13118
13119  var Observable = function () {
13120    this.listeners = {};
13121  };
13122
13123  Observable.prototype.on = function (event, callback) {
13124    this.listeners = this.listeners || {};
13125
13126    if (event in this.listeners) {
13127      this.listeners[event].push(callback);
13128    } else {
13129      this.listeners[event] = [callback];
13130    }
13131  };
13132
13133  Observable.prototype.trigger = function (event) {
13134    var slice = Array.prototype.slice;
13135
13136    this.listeners = this.listeners || {};
13137
13138    if (event in this.listeners) {
13139      this.invoke(this.listeners[event], slice.call(arguments, 1));
13140    }
13141
13142    if ('*' in this.listeners) {
13143      this.invoke(this.listeners['*'], arguments);
13144    }
13145  };
13146
13147  Observable.prototype.invoke = function (listeners, params) {
13148    for (var i = 0, len = listeners.length; i < len; i++) {
13149      listeners[i].apply(this, params);
13150    }
13151  };
13152
13153  Utils.Observable = Observable;
13154
13155  Utils.generateChars = function (length) {
13156    var chars = '';
13157
13158    for (var i = 0; i < length; i++) {
13159      var randomChar = Math.floor(Math.random() * 36);
13160      chars += randomChar.toString(36);
13161    }
13162
13163    return chars;
13164  };
13165
13166  Utils.bind = function (func, context) {
13167    return function () {
13168      func.apply(context, arguments);
13169    };
13170  };
13171
13172  Utils._convertData = function (data) {
13173    for (var originalKey in data) {
13174      var keys = originalKey.split('-');
13175
13176      var dataLevel = data;
13177
13178      if (keys.length === 1) {
13179        continue;
13180      }
13181
13182      for (var k = 0; k < keys.length; k++) {
13183        var key = keys[k];
13184
13185        // Lowercase the first letter
13186        // By default, dash-separated becomes camelCase
13187        key = key.substring(0, 1).toLowerCase() + key.substring(1);
13188
13189        if (!(key in dataLevel)) {
13190          dataLevel[key] = {};
13191        }
13192
13193        if (k == keys.length - 1) {
13194          dataLevel[key] = data[originalKey];
13195        }
13196
13197        dataLevel = dataLevel[key];
13198      }
13199
13200      delete data[originalKey];
13201    }
13202
13203    return data;
13204  };
13205
13206  Utils.hasScroll = function (index, el) {
13207    // Adapted from the function created by @ShadowScripter
13208    // and adapted by @BillBarry on the Stack Exchange Code Review website.
13209    // The original code can be found at
13210    // http://codereview.stackexchange.com/q/13338
13211    // and was designed to be used with the Sizzle selector engine.
13212
13213    var $el = $(el);
13214    var overflowX = el.style.overflowX;
13215    var overflowY = el.style.overflowY;
13216
13217    //Check both x and y declarations
13218    if (overflowX === overflowY &&
13219        (overflowY === 'hidden' || overflowY === 'visible')) {
13220      return false;
13221    }
13222
13223    if (overflowX === 'scroll' || overflowY === 'scroll') {
13224      return true;
13225    }
13226
13227    return ($el.innerHeight() < el.scrollHeight ||
13228      $el.innerWidth() < el.scrollWidth);
13229  };
13230
13231  Utils.escapeMarkup = function (markup) {
13232    var replaceMap = {
13233      '\\': '&#92;',
13234      '&': '&amp;',
13235      '<': '&lt;',
13236      '>': '&gt;',
13237      '"': '&quot;',
13238      '\'': '&#39;',
13239      '/': '&#47;'
13240    };
13241
13242    // Do not try to escape the markup if it's not a string
13243    if (typeof markup !== 'string') {
13244      return markup;
13245    }
13246
13247    return String(markup).replace(/[&<>"'\/\\]/g, function (match) {
13248      return replaceMap[match];
13249    });
13250  };
13251
13252  // Append an array of jQuery nodes to a given element.
13253  Utils.appendMany = function ($element, $nodes) {
13254    // jQuery 1.7.x does not support $.fn.append() with an array
13255    // Fall back to a jQuery object collection using $.fn.add()
13256    if ($.fn.jquery.substr(0, 3) === '1.7') {
13257      var $jqNodes = $();
13258
13259      $.map($nodes, function (node) {
13260        $jqNodes = $jqNodes.add(node);
13261      });
13262
13263      $nodes = $jqNodes;
13264    }
13265
13266    $element.append($nodes);
13267  };
13268
13269  return Utils;
13270});
13271
13272S2.define('select2/results',[
13273  'jquery',
13274  './utils'
13275], function ($, Utils) {
13276  function Results ($element, options, dataAdapter) {
13277    this.$element = $element;
13278    this.data = dataAdapter;
13279    this.options = options;
13280
13281    Results.__super__.constructor.call(this);
13282  }
13283
13284  Utils.Extend(Results, Utils.Observable);
13285
13286  Results.prototype.render = function () {
13287    var $results = $(
13288      '<ul class="select2-results__options" role="tree"></ul>'
13289    );
13290
13291    if (this.options.get('multiple')) {
13292      $results.attr('aria-multiselectable', 'true');
13293    }
13294
13295    this.$results = $results;
13296
13297    return $results;
13298  };
13299
13300  Results.prototype.clear = function () {
13301    this.$results.empty();
13302  };
13303
13304  Results.prototype.displayMessage = function (params) {
13305    var escapeMarkup = this.options.get('escapeMarkup');
13306
13307    this.clear();
13308    this.hideLoading();
13309
13310    var $message = $(
13311      '<li role="treeitem" aria-live="assertive"' +
13312      ' class="select2-results__option"></li>'
13313    );
13314
13315    var message = this.options.get('translations').get(params.message);
13316
13317    $message.append(
13318      escapeMarkup(
13319        message(params.args)
13320      )
13321    );
13322
13323    $message[0].className += ' select2-results__message';
13324
13325    this.$results.append($message);
13326  };
13327
13328  Results.prototype.hideMessages = function () {
13329    this.$results.find('.select2-results__message').remove();
13330  };
13331
13332  Results.prototype.append = function (data) {
13333    this.hideLoading();
13334
13335    var $options = [];
13336
13337    if (data.results == null || data.results.length === 0) {
13338      if (this.$results.children().length === 0) {
13339        this.trigger('results:message', {
13340          message: 'noResults'
13341        });
13342      }
13343
13344      return;
13345    }
13346
13347    data.results = this.sort(data.results);
13348
13349    for (var d = 0; d < data.results.length; d++) {
13350      var item = data.results[d];
13351
13352      var $option = this.option(item);
13353
13354      $options.push($option);
13355    }
13356
13357    this.$results.append($options);
13358  };
13359
13360  Results.prototype.position = function ($results, $dropdown) {
13361    var $resultsContainer = $dropdown.find('.select2-results');
13362    $resultsContainer.append($results);
13363  };
13364
13365  Results.prototype.sort = function (data) {
13366    var sorter = this.options.get('sorter');
13367
13368    return sorter(data);
13369  };
13370
13371  Results.prototype.setClasses = function () {
13372    var self = this;
13373
13374    this.data.current(function (selected) {
13375      var selectedIds = $.map(selected, function (s) {
13376        return s.id.toString();
13377      });
13378
13379      var $options = self.$results
13380        .find('.select2-results__option[aria-selected]');
13381
13382      $options.each(function () {
13383        var $option = $(this);
13384
13385        var item = $.data(this, 'data');
13386
13387        // id needs to be converted to a string when comparing
13388        var id = '' + item.id;
13389
13390        if ((item.element != null && item.element.selected) ||
13391            (item.element == null && $.inArray(id, selectedIds) > -1)) {
13392          $option.attr('aria-selected', 'true');
13393        } else {
13394          $option.attr('aria-selected', 'false');
13395        }
13396      });
13397
13398      var $selected = $options.filter('[aria-selected=true]');
13399
13400      // Check if there are any selected options
13401      if ($selected.length > 0) {
13402        // If there are selected options, highlight the first
13403        $selected.first().trigger('mouseenter');
13404      } else {
13405        // If there are no selected options, highlight the first option
13406        // in the dropdown
13407        $options.first().trigger('mouseenter');
13408      }
13409    });
13410  };
13411
13412  Results.prototype.showLoading = function (params) {
13413    this.hideLoading();
13414
13415    var loadingMore = this.options.get('translations').get('searching');
13416
13417    var loading = {
13418      disabled: true,
13419      loading: true,
13420      text: loadingMore(params)
13421    };
13422    var $loading = this.option(loading);
13423    $loading.className += ' loading-results';
13424
13425    this.$results.prepend($loading);
13426  };
13427
13428  Results.prototype.hideLoading = function () {
13429    this.$results.find('.loading-results').remove();
13430  };
13431
13432  Results.prototype.option = function (data) {
13433    var option = document.createElement('li');
13434    option.className = 'select2-results__option';
13435
13436    var attrs = {
13437      'role': 'treeitem',
13438      'aria-selected': 'false'
13439    };
13440
13441    if (data.disabled) {
13442      delete attrs['aria-selected'];
13443      attrs['aria-disabled'] = 'true';
13444    }
13445
13446    if (data.id == null) {
13447      delete attrs['aria-selected'];
13448    }
13449
13450    if (data._resultId != null) {
13451      option.id = data._resultId;
13452    }
13453
13454    if (data.title) {
13455      option.title = data.title;
13456    }
13457
13458    if (data.children) {
13459      attrs.role = 'group';
13460      attrs['aria-label'] = data.text;
13461      delete attrs['aria-selected'];
13462    }
13463
13464    for (var attr in attrs) {
13465      var val = attrs[attr];
13466
13467      option.setAttribute(attr, val);
13468    }
13469
13470    if (data.children) {
13471      var $option = $(option);
13472
13473      var label = document.createElement('strong');
13474      label.className = 'select2-results__group';
13475
13476      var $label = $(label);
13477      this.template(data, label);
13478
13479      var $children = [];
13480
13481      for (var c = 0; c < data.children.length; c++) {
13482        var child = data.children[c];
13483
13484        var $child = this.option(child);
13485
13486        $children.push($child);
13487      }
13488
13489      var $childrenContainer = $('<ul></ul>', {
13490        'class': 'select2-results__options select2-results__options--nested'
13491      });
13492
13493      $childrenContainer.append($children);
13494
13495      $option.append(label);
13496      $option.append($childrenContainer);
13497    } else {
13498      this.template(data, option);
13499    }
13500
13501    $.data(option, 'data', data);
13502
13503    return option;
13504  };
13505
13506  Results.prototype.bind = function (container, $container) {
13507    var self = this;
13508
13509    var id = container.id + '-results';
13510
13511    this.$results.attr('id', id);
13512
13513    container.on('results:all', function (params) {
13514      self.clear();
13515      self.append(params.data);
13516
13517      if (container.isOpen()) {
13518        self.setClasses();
13519      }
13520    });
13521
13522    container.on('results:append', function (params) {
13523      self.append(params.data);
13524
13525      if (container.isOpen()) {
13526        self.setClasses();
13527      }
13528    });
13529
13530    container.on('query', function (params) {
13531      self.hideMessages();
13532      self.showLoading(params);
13533    });
13534
13535    container.on('select', function () {
13536      if (!container.isOpen()) {
13537        return;
13538      }
13539
13540      self.setClasses();
13541    });
13542
13543    container.on('unselect', function () {
13544      if (!container.isOpen()) {
13545        return;
13546      }
13547
13548      self.setClasses();
13549    });
13550
13551    container.on('open', function () {
13552      // When the dropdown is open, aria-expended="true"
13553      self.$results.attr('aria-expanded', 'true');
13554      self.$results.attr('aria-hidden', 'false');
13555
13556      self.setClasses();
13557      self.ensureHighlightVisible();
13558    });
13559
13560    container.on('close', function () {
13561      // When the dropdown is closed, aria-expended="false"
13562      self.$results.attr('aria-expanded', 'false');
13563      self.$results.attr('aria-hidden', 'true');
13564      self.$results.removeAttr('aria-activedescendant');
13565    });
13566
13567    container.on('results:toggle', function () {
13568      var $highlighted = self.getHighlightedResults();
13569
13570      if ($highlighted.length === 0) {
13571        return;
13572      }
13573
13574      $highlighted.trigger('mouseup');
13575    });
13576
13577    container.on('results:select', function () {
13578      var $highlighted = self.getHighlightedResults();
13579
13580      if ($highlighted.length === 0) {
13581        return;
13582      }
13583
13584      var data = $highlighted.data('data');
13585
13586      if ($highlighted.attr('aria-selected') == 'true') {
13587        self.trigger('close', {});
13588      } else {
13589        self.trigger('select', {
13590          data: data
13591        });
13592      }
13593    });
13594
13595    container.on('results:previous', function () {
13596      var $highlighted = self.getHighlightedResults();
13597
13598      var $options = self.$results.find('[aria-selected]');
13599
13600      var currentIndex = $options.index($highlighted);
13601
13602      // If we are already at te top, don't move further
13603      if (currentIndex === 0) {
13604        return;
13605      }
13606
13607      var nextIndex = currentIndex - 1;
13608
13609      // If none are highlighted, highlight the first
13610      if ($highlighted.length === 0) {
13611        nextIndex = 0;
13612      }
13613
13614      var $next = $options.eq(nextIndex);
13615
13616      $next.trigger('mouseenter');
13617
13618      var currentOffset = self.$results.offset().top;
13619      var nextTop = $next.offset().top;
13620      var nextOffset = self.$results.scrollTop() + (nextTop - currentOffset);
13621
13622      if (nextIndex === 0) {
13623        self.$results.scrollTop(0);
13624      } else if (nextTop - currentOffset < 0) {
13625        self.$results.scrollTop(nextOffset);
13626      }
13627    });
13628
13629    container.on('results:next', function () {
13630      var $highlighted = self.getHighlightedResults();
13631
13632      var $options = self.$results.find('[aria-selected]');
13633
13634      var currentIndex = $options.index($highlighted);
13635
13636      var nextIndex = currentIndex + 1;
13637
13638      // If we are at the last option, stay there
13639      if (nextIndex >= $options.length) {
13640        return;
13641      }
13642
13643      var $next = $options.eq(nextIndex);
13644
13645      $next.trigger('mouseenter');
13646
13647      var currentOffset = self.$results.offset().top +
13648        self.$results.outerHeight(false);
13649      var nextBottom = $next.offset().top + $next.outerHeight(false);
13650      var nextOffset = self.$results.scrollTop() + nextBottom - currentOffset;
13651
13652      if (nextIndex === 0) {
13653        self.$results.scrollTop(0);
13654      } else if (nextBottom > currentOffset) {
13655        self.$results.scrollTop(nextOffset);
13656      }
13657    });
13658
13659    container.on('results:focus', function (params) {
13660      params.element.addClass('select2-results__option--highlighted');
13661    });
13662
13663    container.on('results:message', function (params) {
13664      self.displayMessage(params);
13665    });
13666
13667    if ($.fn.mousewheel) {
13668      // this.$results.on('mousewheel', function (e) {
13669      //   var top = self.$results.scrollTop();
13670      //
13671      //   var bottom = (
13672      //     self.$results.get(0).scrollHeight -
13673      //     self.$results.scrollTop() +
13674      //     e.deltaY
13675      //   );
13676      //
13677      //   var isAtTop = e.deltaY > 0 && top - e.deltaY <= 0;
13678      //   var isAtBottom = e.deltaY < 0 && bottom <= self.$results.height();
13679      //
13680      //   if (isAtTop) {
13681      //     self.$results.scrollTop(0);
13682      //
13683      //     e.preventDefault();
13684      //     e.stopPropagation();
13685      //   } else if (isAtBottom) {
13686      //     self.$results.scrollTop(
13687      //       self.$results.get(0).scrollHeight - self.$results.height()
13688      //     );
13689      //
13690      //     e.preventDefault();
13691      //     e.stopPropagation();
13692      //   }
13693      // });
13694    }
13695
13696    this.$results.on('mouseup', '.select2-results__option[aria-selected]',
13697      function (evt) {
13698      var $this = $(this);
13699
13700      var data = $this.data('data');
13701
13702      if ($this.attr('aria-selected') === 'true') {
13703        if (self.options.get('multiple')) {
13704          self.trigger('unselect', {
13705            originalEvent: evt,
13706            data: data
13707          });
13708        } else {
13709          self.trigger('close', {});
13710        }
13711
13712        return;
13713      }
13714
13715      self.trigger('select', {
13716        originalEvent: evt,
13717        data: data
13718      });
13719    });
13720
13721    this.$results.on('mouseenter', '.select2-results__option[aria-selected]',
13722      function (evt) {
13723      var data = $(this).data('data');
13724
13725      self.getHighlightedResults()
13726          .removeClass('select2-results__option--highlighted');
13727
13728      self.trigger('results:focus', {
13729        data: data,
13730        element: $(this)
13731      });
13732    });
13733  };
13734
13735  Results.prototype.getHighlightedResults = function () {
13736    var $highlighted = this.$results
13737    .find('.select2-results__option--highlighted');
13738
13739    return $highlighted;
13740  };
13741
13742  Results.prototype.destroy = function () {
13743    this.$results.remove();
13744  };
13745
13746  Results.prototype.ensureHighlightVisible = function () {
13747    var $highlighted = this.getHighlightedResults();
13748
13749    if ($highlighted.length === 0) {
13750      return;
13751    }
13752
13753    var $options = this.$results.find('[aria-selected]');
13754
13755    var currentIndex = $options.index($highlighted);
13756
13757    var currentOffset = this.$results.offset().top;
13758    var nextTop = $highlighted.offset().top;
13759    var nextOffset = this.$results.scrollTop() + (nextTop - currentOffset);
13760
13761    var offsetDelta = nextTop - currentOffset;
13762    nextOffset -= $highlighted.outerHeight(false) * 2;
13763
13764    if (currentIndex <= 2) {
13765      this.$results.scrollTop(0);
13766    } else if (offsetDelta > this.$results.outerHeight() || offsetDelta < 0) {
13767      this.$results.scrollTop(nextOffset);
13768    }
13769  };
13770
13771  Results.prototype.template = function (result, container) {
13772    var template = this.options.get('templateResult');
13773    var escapeMarkup = this.options.get('escapeMarkup');
13774
13775    var content = template(result, container);
13776
13777    if (content == null) {
13778      container.style.display = 'none';
13779    } else if (typeof content === 'string') {
13780      container.innerHTML = escapeMarkup(content);
13781    } else {
13782      $(container).append(content);
13783    }
13784  };
13785
13786  return Results;
13787});
13788
13789S2.define('select2/keys',[
13790
13791], function () {
13792  var KEYS = {
13793    BACKSPACE: 8,
13794    TAB: 9,
13795    ENTER: 13,
13796    SHIFT: 16,
13797    CTRL: 17,
13798    ALT: 18,
13799    ESC: 27,
13800    SPACE: 32,
13801    PAGE_UP: 33,
13802    PAGE_DOWN: 34,
13803    END: 35,
13804    HOME: 36,
13805    LEFT: 37,
13806    UP: 38,
13807    RIGHT: 39,
13808    DOWN: 40,
13809    DELETE: 46
13810  };
13811
13812  return KEYS;
13813});
13814
13815S2.define('select2/selection/base',[
13816  'jquery',
13817  '../utils',
13818  '../keys'
13819], function ($, Utils, KEYS) {
13820  function BaseSelection ($element, options) {
13821    this.$element = $element;
13822    this.options = options;
13823
13824    BaseSelection.__super__.constructor.call(this);
13825  }
13826
13827  Utils.Extend(BaseSelection, Utils.Observable);
13828
13829  BaseSelection.prototype.render = function () {
13830    var $selection = $(
13831      '<span class="select2-selection" role="combobox" ' +
13832      ' aria-haspopup="true" aria-expanded="false">' +
13833      '</span>'
13834    );
13835
13836    this._tabindex = 0;
13837
13838    if (this.$element.data('old-tabindex') != null) {
13839      this._tabindex = this.$element.data('old-tabindex');
13840    } else if (this.$element.attr('tabindex') != null) {
13841      this._tabindex = this.$element.attr('tabindex');
13842    }
13843
13844    $selection.attr('title', this.$element.attr('title'));
13845    $selection.attr('tabindex', this._tabindex);
13846
13847    this.$selection = $selection;
13848
13849    return $selection;
13850  };
13851
13852  BaseSelection.prototype.bind = function (container, $container) {
13853    var self = this;
13854
13855    var id = container.id + '-container';
13856    var resultsId = container.id + '-results';
13857
13858    this.container = container;
13859
13860    this.$selection.on('focus', function (evt) {
13861      self.trigger('focus', evt);
13862    });
13863
13864    this.$selection.on('blur', function (evt) {
13865      self._handleBlur(evt);
13866    });
13867
13868    this.$selection.on('keydown', function (evt) {
13869      self.trigger('keypress', evt);
13870
13871      if (evt.which === KEYS.SPACE) {
13872        evt.preventDefault();
13873      }
13874    });
13875
13876    container.on('results:focus', function (params) {
13877      self.$selection.attr('aria-activedescendant', params.data._resultId);
13878    });
13879
13880    container.on('selection:update', function (params) {
13881      self.update(params.data);
13882    });
13883
13884    container.on('open', function () {
13885      // When the dropdown is open, aria-expanded="true"
13886      self.$selection.attr('aria-expanded', 'true');
13887      self.$selection.attr('aria-owns', resultsId);
13888
13889      self._attachCloseHandler(container);
13890    });
13891
13892    container.on('close', function () {
13893      // When the dropdown is closed, aria-expanded="false"
13894      self.$selection.attr('aria-expanded', 'false');
13895      self.$selection.removeAttr('aria-activedescendant');
13896      self.$selection.removeAttr('aria-owns');
13897
13898      self.$selection.focus();
13899
13900      self._detachCloseHandler(container);
13901    });
13902
13903    container.on('enable', function () {
13904      self.$selection.attr('tabindex', self._tabindex);
13905    });
13906
13907    container.on('disable', function () {
13908      self.$selection.attr('tabindex', '-1');
13909    });
13910  };
13911
13912  BaseSelection.prototype._handleBlur = function (evt) {
13913    var self = this;
13914
13915    // This needs to be delayed as the active element is the body when the tab
13916    // key is pressed, possibly along with others.
13917    window.setTimeout(function () {
13918      // Don't trigger `blur` if the focus is still in the selection
13919      if (
13920        (document.activeElement == self.$selection[0]) ||
13921        ($.contains(self.$selection[0], document.activeElement))
13922      ) {
13923        return;
13924      }
13925
13926      self.trigger('blur', evt);
13927    }, 1);
13928  };
13929
13930  BaseSelection.prototype._attachCloseHandler = function (container) {
13931    var self = this;
13932
13933    $(document.body).on('mousedown.select2.' + container.id, function (e) {
13934      var $target = $(e.target);
13935
13936      var $select = $target.closest('.select2');
13937
13938      var $all = $('.select2.select2-container--open');
13939
13940      $all.each(function () {
13941        var $this = $(this);
13942
13943        if (this == $select[0]) {
13944          return;
13945        }
13946
13947        var $element = $this.data('element');
13948
13949        $element.select2('close');
13950      });
13951    });
13952  };
13953
13954  BaseSelection.prototype._detachCloseHandler = function (container) {
13955    $(document.body).off('mousedown.select2.' + container.id);
13956  };
13957
13958  BaseSelection.prototype.position = function ($selection, $container) {
13959    var $selectionContainer = $container.find('.selection');
13960    $selectionContainer.append($selection);
13961  };
13962
13963  BaseSelection.prototype.destroy = function () {
13964    this._detachCloseHandler(this.container);
13965  };
13966
13967  BaseSelection.prototype.update = function (data) {
13968    throw new Error('The `update` method must be defined in child classes.');
13969  };
13970
13971  return BaseSelection;
13972});
13973
13974S2.define('select2/selection/single',[
13975  'jquery',
13976  './base',
13977  '../utils',
13978  '../keys'
13979], function ($, BaseSelection, Utils, KEYS) {
13980  function SingleSelection () {
13981    SingleSelection.__super__.constructor.apply(this, arguments);
13982  }
13983
13984  Utils.Extend(SingleSelection, BaseSelection);
13985
13986  SingleSelection.prototype.render = function () {
13987    var $selection = SingleSelection.__super__.render.call(this);
13988
13989    $selection.addClass('select2-selection--single');
13990
13991    $selection.html(
13992      '<span class="select2-selection__rendered"></span>' +
13993      '<span class="select2-selection__arrow" role="presentation">' +
13994        '<b role="presentation"></b>' +
13995      '</span>'
13996    );
13997
13998    return $selection;
13999  };
14000
14001  SingleSelection.prototype.bind = function (container, $container) {
14002    var self = this;
14003
14004    SingleSelection.__super__.bind.apply(this, arguments);
14005
14006    var id = container.id + '-container';
14007
14008    this.$selection.find('.select2-selection__rendered').attr('id', id);
14009    this.$selection.attr('aria-labelledby', id);
14010
14011    this.$selection.on('mousedown', function (evt) {
14012      // Only respond to left clicks
14013      if (evt.which !== 1) {
14014        return;
14015      }
14016
14017      self.trigger('toggle', {
14018        originalEvent: evt
14019      });
14020    });
14021
14022    this.$selection.on('focus', function (evt) {
14023      // User focuses on the container
14024    });
14025
14026    this.$selection.on('blur', function (evt) {
14027      // User exits the container
14028    });
14029
14030    container.on('selection:update', function (params) {
14031      self.update(params.data);
14032    });
14033  };
14034
14035  SingleSelection.prototype.clear = function () {
14036    this.$selection.find('.select2-selection__rendered').empty();
14037  };
14038
14039  SingleSelection.prototype.display = function (data, container) {
14040    var template = this.options.get('templateSelection');
14041    var escapeMarkup = this.options.get('escapeMarkup');
14042
14043    return escapeMarkup(template(data, container));
14044  };
14045
14046  SingleSelection.prototype.selectionContainer = function () {
14047    return $('<span></span>');
14048  };
14049
14050  SingleSelection.prototype.update = function (data) {
14051    if (data.length === 0) {
14052      this.clear();
14053      return;
14054    }
14055
14056    var selection = data[0];
14057
14058    var $rendered = this.$selection.find('.select2-selection__rendered');
14059    var formatted = this.display(selection, $rendered);
14060
14061    $rendered.empty().append(formatted);
14062    $rendered.prop('title', selection.title || selection.text);
14063  };
14064
14065  return SingleSelection;
14066});
14067
14068S2.define('select2/selection/multiple',[
14069  'jquery',
14070  './base',
14071  '../utils'
14072], function ($, BaseSelection, Utils) {
14073  function MultipleSelection ($element, options) {
14074    MultipleSelection.__super__.constructor.apply(this, arguments);
14075  }
14076
14077  Utils.Extend(MultipleSelection, BaseSelection);
14078
14079  MultipleSelection.prototype.render = function () {
14080    var $selection = MultipleSelection.__super__.render.call(this);
14081
14082    $selection.addClass('select2-selection--multiple');
14083
14084    $selection.html(
14085      '<ul class="select2-selection__rendered"></ul>'
14086    );
14087
14088    return $selection;
14089  };
14090
14091  MultipleSelection.prototype.bind = function (container, $container) {
14092    var self = this;
14093
14094    MultipleSelection.__super__.bind.apply(this, arguments);
14095
14096    this.$selection.on('click', function (evt) {
14097      self.trigger('toggle', {
14098        originalEvent: evt
14099      });
14100    });
14101
14102    this.$selection.on(
14103      'click',
14104      '.select2-selection__choice__remove',
14105      function (evt) {
14106        // Ignore the event if it is disabled
14107        if (self.options.get('disabled')) {
14108          return;
14109        }
14110
14111        var $remove = $(this);
14112        var $selection = $remove.parent();
14113
14114        var data = $selection.data('data');
14115
14116        self.trigger('unselect', {
14117          originalEvent: evt,
14118          data: data
14119        });
14120      }
14121    );
14122  };
14123
14124  MultipleSelection.prototype.clear = function () {
14125    this.$selection.find('.select2-selection__rendered').empty();
14126  };
14127
14128  MultipleSelection.prototype.display = function (data, container) {
14129    var template = this.options.get('templateSelection');
14130    var escapeMarkup = this.options.get('escapeMarkup');
14131
14132    return escapeMarkup(template(data, container));
14133  };
14134
14135  MultipleSelection.prototype.selectionContainer = function () {
14136    var $container = $(
14137      '<li class="select2-selection__choice">' +
14138        '<span class="select2-selection__choice__remove" role="presentation">' +
14139          '&times;' +
14140        '</span>' +
14141      '</li>'
14142    );
14143
14144    return $container;
14145  };
14146
14147  MultipleSelection.prototype.update = function (data) {
14148    this.clear();
14149
14150    if (data.length === 0) {
14151      return;
14152    }
14153
14154    var $selections = [];
14155
14156    for (var d = 0; d < data.length; d++) {
14157      var selection = data[d];
14158
14159      var $selection = this.selectionContainer();
14160      var formatted = this.display(selection, $selection);
14161
14162      $selection.append(formatted);
14163      $selection.prop('title', selection.title || selection.text);
14164
14165      $selection.data('data', selection);
14166
14167      $selections.push($selection);
14168    }
14169
14170    var $rendered = this.$selection.find('.select2-selection__rendered');
14171
14172    Utils.appendMany($rendered, $selections);
14173  };
14174
14175  return MultipleSelection;
14176});
14177
14178S2.define('select2/selection/placeholder',[
14179  '../utils'
14180], function (Utils) {
14181  function Placeholder (decorated, $element, options) {
14182    this.placeholder = this.normalizePlaceholder(options.get('placeholder'));
14183
14184    decorated.call(this, $element, options);
14185  }
14186
14187  Placeholder.prototype.normalizePlaceholder = function (_, placeholder) {
14188    if (typeof placeholder === 'string') {
14189      placeholder = {
14190        id: '',
14191        text: placeholder
14192      };
14193    }
14194
14195    return placeholder;
14196  };
14197
14198  Placeholder.prototype.createPlaceholder = function (decorated, placeholder) {
14199    var $placeholder = this.selectionContainer();
14200
14201    $placeholder.html(this.display(placeholder));
14202    $placeholder.addClass('select2-selection__placeholder')
14203                .removeClass('select2-selection__choice');
14204
14205    return $placeholder;
14206  };
14207
14208  Placeholder.prototype.update = function (decorated, data) {
14209    var singlePlaceholder = (
14210      data.length == 1 && data[0].id != this.placeholder.id
14211    );
14212    var multipleSelections = data.length > 1;
14213
14214    if (multipleSelections || singlePlaceholder) {
14215      return decorated.call(this, data);
14216    }
14217
14218    this.clear();
14219
14220    var $placeholder = this.createPlaceholder(this.placeholder);
14221
14222    this.$selection.find('.select2-selection__rendered').append($placeholder);
14223  };
14224
14225  return Placeholder;
14226});
14227
14228S2.define('select2/selection/allowClear',[
14229  'jquery',
14230  '../keys'
14231], function ($, KEYS) {
14232  function AllowClear () { }
14233
14234  AllowClear.prototype.bind = function (decorated, container, $container) {
14235    var self = this;
14236
14237    decorated.call(this, container, $container);
14238
14239    if (this.placeholder == null) {
14240      if (this.options.get('debug') && window.console && console.error) {
14241        console.error(
14242          'Select2: The `allowClear` option should be used in combination ' +
14243          'with the `placeholder` option.'
14244        );
14245      }
14246    }
14247
14248    this.$selection.on('mousedown', '.select2-selection__clear',
14249      function (evt) {
14250        self._handleClear(evt);
14251    });
14252
14253    container.on('keypress', function (evt) {
14254      self._handleKeyboardClear(evt, container);
14255    });
14256  };
14257
14258  AllowClear.prototype._handleClear = function (_, evt) {
14259    // Ignore the event if it is disabled
14260    if (this.options.get('disabled')) {
14261      return;
14262    }
14263
14264    var $clear = this.$selection.find('.select2-selection__clear');
14265
14266    // Ignore the event if nothing has been selected
14267    if ($clear.length === 0) {
14268      return;
14269    }
14270
14271    evt.stopPropagation();
14272
14273    var data = $clear.data('data');
14274
14275    for (var d = 0; d < data.length; d++) {
14276      var unselectData = {
14277        data: data[d]
14278      };
14279
14280      // Trigger the `unselect` event, so people can prevent it from being
14281      // cleared.
14282      this.trigger('unselect', unselectData);
14283
14284      // If the event was prevented, don't clear it out.
14285      if (unselectData.prevented) {
14286        return;
14287      }
14288    }
14289
14290    this.$element.val(this.placeholder.id).trigger('change');
14291
14292    this.trigger('toggle', {});
14293  };
14294
14295  AllowClear.prototype._handleKeyboardClear = function (_, evt, container) {
14296    if (container.isOpen()) {
14297      return;
14298    }
14299
14300    if (evt.which == KEYS.DELETE || evt.which == KEYS.BACKSPACE) {
14301      this._handleClear(evt);
14302    }
14303  };
14304
14305  AllowClear.prototype.update = function (decorated, data) {
14306    decorated.call(this, data);
14307
14308    if (this.$selection.find('.select2-selection__placeholder').length > 0 ||
14309        data.length === 0) {
14310      return;
14311    }
14312
14313    var $remove = $(
14314      '<span class="select2-selection__clear">' +
14315        '&times;' +
14316      '</span>'
14317    );
14318    $remove.data('data', data);
14319
14320    this.$selection.find('.select2-selection__rendered').prepend($remove);
14321  };
14322
14323  return AllowClear;
14324});
14325
14326S2.define('select2/selection/search',[
14327  'jquery',
14328  '../utils',
14329  '../keys'
14330], function ($, Utils, KEYS) {
14331  function Search (decorated, $element, options) {
14332    decorated.call(this, $element, options);
14333  }
14334
14335  Search.prototype.render = function (decorated) {
14336    var $search = $(
14337      '<li class="select2-search select2-search--inline">' +
14338        '<input class="select2-search__field" type="search" tabindex="-1"' +
14339        ' autocomplete="off" autocorrect="off" autocapitalize="off"' +
14340        ' spellcheck="false" role="textbox" aria-autocomplete="list" />' +
14341      '</li>'
14342    );
14343
14344    this.$searchContainer = $search;
14345    this.$search = $search.find('input');
14346
14347    var $rendered = decorated.call(this);
14348
14349    this._transferTabIndex();
14350
14351    return $rendered;
14352  };
14353
14354  Search.prototype.bind = function (decorated, container, $container) {
14355    var self = this;
14356
14357    decorated.call(this, container, $container);
14358
14359    container.on('open', function () {
14360      self.$search.trigger('focus');
14361    });
14362
14363    container.on('close', function () {
14364      self.$search.val('');
14365      self.$search.removeAttr('aria-activedescendant');
14366      self.$search.trigger('focus');
14367    });
14368
14369    container.on('enable', function () {
14370      self.$search.prop('disabled', false);
14371
14372      self._transferTabIndex();
14373    });
14374
14375    container.on('disable', function () {
14376      self.$search.prop('disabled', true);
14377    });
14378
14379    container.on('focus', function (evt) {
14380      self.$search.trigger('focus');
14381    });
14382
14383    container.on('results:focus', function (params) {
14384      self.$search.attr('aria-activedescendant', params.id);
14385    });
14386
14387    this.$selection.on('focusin', '.select2-search--inline', function (evt) {
14388      self.trigger('focus', evt);
14389    });
14390
14391    this.$selection.on('focusout', '.select2-search--inline', function (evt) {
14392      self._handleBlur(evt);
14393    });
14394
14395    this.$selection.on('keydown', '.select2-search--inline', function (evt) {
14396      evt.stopPropagation();
14397
14398      self.trigger('keypress', evt);
14399
14400      self._keyUpPrevented = evt.isDefaultPrevented();
14401
14402      var key = evt.which;
14403
14404      if (key === KEYS.BACKSPACE && self.$search.val() === '') {
14405        var $previousChoice = self.$searchContainer
14406          .prev('.select2-selection__choice');
14407
14408        if ($previousChoice.length > 0) {
14409          var item = $previousChoice.data('data');
14410
14411          self.searchRemoveChoice(item);
14412
14413          evt.preventDefault();
14414        }
vendor: 22,668 bytes, lines 14414-15506
14414
14415      }
14416    });
14417
14418    // Try to detect the IE version should the `documentMode` property that
14419    // is stored on the document. This is only implemented in IE and is
14420    // slightly cleaner than doing a user agent check.
14421    // This property is not available in Edge, but Edge also doesn't have
14422    // this bug.
14423    var msie = document.documentMode;
14424    var disableInputEvents = msie && msie <= 11;
14425
14426    // Workaround for browsers which do not support the `input` event
14427    // This will prevent double-triggering of events for browsers which support
14428    // both the `keyup` and `input` events.
14429    this.$selection.on(
14430      'input.searchcheck',
14431      '.select2-search--inline',
14432      function (evt) {
14433        // IE will trigger the `input` event when a placeholder is used on a
14434        // search box. To get around this issue, we are forced to ignore all
14435        // `input` events in IE and keep using `keyup`.
14436        if (disableInputEvents) {
14437          self.$selection.off('input.search input.searchcheck');
14438          return;
14439        }
14440
14441        // Unbind the duplicated `keyup` event
14442        self.$selection.off('keyup.search');
14443      }
14444    );
14445
14446    this.$selection.on(
14447      'keyup.search input.search',
14448      '.select2-search--inline',
14449      function (evt) {
14450        // IE will trigger the `input` event when a placeholder is used on a
14451        // search box. To get around this issue, we are forced to ignore all
14452        // `input` events in IE and keep using `keyup`.
14453        if (disableInputEvents && evt.type === 'input') {
14454          self.$selection.off('input.search input.searchcheck');
14455          return;
14456        }
14457
14458        var key = evt.which;
14459
14460        // We can freely ignore events from modifier keys
14461        if (key == KEYS.SHIFT || key == KEYS.CTRL || key == KEYS.ALT) {
14462          return;
14463        }
14464
14465        // Tabbing will be handled during the `keydown` phase
14466        if (key == KEYS.TAB) {
14467          return;
14468        }
14469
14470        self.handleSearch(evt);
14471      }
14472    );
14473  };
14474
14475  /**
14476   * This method will transfer the tabindex attribute from the rendered
14477   * selection to the search box. This allows for the search box to be used as
14478   * the primary focus instead of the selection container.
14479   *
14480   * @private
14481   */
14482  Search.prototype._transferTabIndex = function (decorated) {
14483    this.$search.attr('tabindex', this.$selection.attr('tabindex'));
14484    this.$selection.attr('tabindex', '-1');
14485  };
14486
14487  Search.prototype.createPlaceholder = function (decorated, placeholder) {
14488    this.$search.attr('placeholder', placeholder.text);
14489  };
14490
14491  Search.prototype.update = function (decorated, data) {
14492    var searchHadFocus = this.$search[0] == document.activeElement;
14493
14494    this.$search.attr('placeholder', '');
14495
14496    decorated.call(this, data);
14497
14498    this.$selection.find('.select2-selection__rendered')
14499                   .append(this.$searchContainer);
14500
14501    this.resizeSearch();
14502    if (searchHadFocus) {
14503      this.$search.focus();
14504    }
14505  };
14506
14507  Search.prototype.handleSearch = function () {
14508    this.resizeSearch();
14509
14510    if (!this._keyUpPrevented) {
14511      var input = this.$search.val();
14512
14513      this.trigger('query', {
14514        term: input
14515      });
14516    }
14517
14518    this._keyUpPrevented = false;
14519  };
14520
14521  Search.prototype.searchRemoveChoice = function (decorated, item) {
14522    this.trigger('unselect', {
14523      data: item
14524    });
14525
14526    this.$search.val(item.text);
14527    this.handleSearch();
14528  };
14529
14530  Search.prototype.resizeSearch = function () {
14531    this.$search.css('width', '25px');
14532
14533    var width = '';
14534
14535    if (this.$search.attr('placeholder') !== '') {
14536      width = this.$selection.find('.select2-selection__rendered').innerWidth();
14537    } else {
14538      var minimumWidth = this.$search.val().length + 1;
14539
14540      width = (minimumWidth * 0.75) + 'em';
14541    }
14542
14543    this.$search.css('width', width);
14544  };
14545
14546  return Search;
14547});
14548
14549S2.define('select2/selection/eventRelay',[
14550  'jquery'
14551], function ($) {
14552  function EventRelay () { }
14553
14554  EventRelay.prototype.bind = function (decorated, container, $container) {
14555    var self = this;
14556    var relayEvents = [
14557      'open', 'opening',
14558      'close', 'closing',
14559      'select', 'selecting',
14560      'unselect', 'unselecting'
14561    ];
14562
14563    var preventableEvents = ['opening', 'closing', 'selecting', 'unselecting'];
14564
14565    decorated.call(this, container, $container);
14566
14567    container.on('*', function (name, params) {
14568      // Ignore events that should not be relayed
14569      if ($.inArray(name, relayEvents) === -1) {
14570        return;
14571      }
14572
14573      // The parameters should always be an object
14574      params = params || {};
14575
14576      // Generate the jQuery event for the Select2 event
14577      var evt = $.Event('select2:' + name, {
14578        params: params
14579      });
14580
14581      self.$element.trigger(evt);
14582
14583      // Only handle preventable events if it was one
14584      if ($.inArray(name, preventableEvents) === -1) {
14585        return;
14586      }
14587
14588      params.prevented = evt.isDefaultPrevented();
14589    });
14590  };
14591
14592  return EventRelay;
14593});
14594
14595S2.define('select2/translation',[
14596  'jquery',
14597  'require'
14598], function ($, require) {
14599  function Translation (dict) {
14600    this.dict = dict || {};
14601  }
14602
14603  Translation.prototype.all = function () {
14604    return this.dict;
14605  };
14606
14607  Translation.prototype.get = function (key) {
14608    return this.dict[key];
14609  };
14610
14611  Translation.prototype.extend = function (translation) {
14612    this.dict = $.extend({}, translation.all(), this.dict);
14613  };
14614
14615  // Static functions
14616
14617  Translation._cache = {};
14618
14619  Translation.loadPath = function (path) {
14620    if (!(path in Translation._cache)) {
14621      var translations = require(path);
14622
14623      Translation._cache[path] = translations;
14624    }
14625
14626    return new Translation(Translation._cache[path]);
14627  };
14628
14629  return Translation;
14630});
14631
14632S2.define('select2/diacritics',[
14633
14634], function () {
14635  var diacritics = {
14636    '\u24B6': 'A',
14637    '\uFF21': 'A',
14638    '\u00C0': 'A',
14639    '\u00C1': 'A',
14640    '\u00C2': 'A',
14641    '\u1EA6': 'A',
14642    '\u1EA4': 'A',
14643    '\u1EAA': 'A',
14644    '\u1EA8': 'A',
14645    '\u00C3': 'A',
14646    '\u0100': 'A',
14647    '\u0102': 'A',
14648    '\u1EB0': 'A',
14649    '\u1EAE': 'A',
14650    '\u1EB4': 'A',
14651    '\u1EB2': 'A',
14652    '\u0226': 'A',
14653    '\u01E0': 'A',
14654    '\u00C4': 'A',
14655    '\u01DE': 'A',
14656    '\u1EA2': 'A',
14657    '\u00C5': 'A',
14658    '\u01FA': 'A',
14659    '\u01CD': 'A',
14660    '\u0200': 'A',
14661    '\u0202': 'A',
14662    '\u1EA0': 'A',
14663    '\u1EAC': 'A',
14664    '\u1EB6': 'A',
14665    '\u1E00': 'A',
14666    '\u0104': 'A',
14667    '\u023A': 'A',
14668    '\u2C6F': 'A',
14669    '\uA732': 'AA',
14670    '\u00C6': 'AE',
14671    '\u01FC': 'AE',
14672    '\u01E2': 'AE',
14673    '\uA734': 'AO',
14674    '\uA736': 'AU',
14675    '\uA738': 'AV',
14676    '\uA73A': 'AV',
14677    '\uA73C': 'AY',
14678    '\u24B7': 'B',
14679    '\uFF22': 'B',
14680    '\u1E02': 'B',
14681    '\u1E04': 'B',
14682    '\u1E06': 'B',
14683    '\u0243': 'B',
14684    '\u0182': 'B',
14685    '\u0181': 'B',
14686    '\u24B8': 'C',
14687    '\uFF23': 'C',
14688    '\u0106': 'C',
14689    '\u0108': 'C',
14690    '\u010A': 'C',
14691    '\u010C': 'C',
14692    '\u00C7': 'C',
14693    '\u1E08': 'C',
14694    '\u0187': 'C',
14695    '\u023B': 'C',
14696    '\uA73E': 'C',
14697    '\u24B9': 'D',
14698    '\uFF24': 'D',
14699    '\u1E0A': 'D',
14700    '\u010E': 'D',
14701    '\u1E0C': 'D',
14702    '\u1E10': 'D',
14703    '\u1E12': 'D',
14704    '\u1E0E': 'D',
14705    '\u0110': 'D',
14706    '\u018B': 'D',
14707    '\u018A': 'D',
14708    '\u0189': 'D',
14709    '\uA779': 'D',
14710    '\u01F1': 'DZ',
14711    '\u01C4': 'DZ',
14712    '\u01F2': 'Dz',
14713    '\u01C5': 'Dz',
14714    '\u24BA': 'E',
14715    '\uFF25': 'E',
14716    '\u00C8': 'E',
14717    '\u00C9': 'E',
14718    '\u00CA': 'E',
14719    '\u1EC0': 'E',
14720    '\u1EBE': 'E',
14721    '\u1EC4': 'E',
14722    '\u1EC2': 'E',
14723    '\u1EBC': 'E',
14724    '\u0112': 'E',
14725    '\u1E14': 'E',
14726    '\u1E16': 'E',
14727    '\u0114': 'E',
14728    '\u0116': 'E',
14729    '\u00CB': 'E',
14730    '\u1EBA': 'E',
14731    '\u011A': 'E',
14732    '\u0204': 'E',
14733    '\u0206': 'E',
14734    '\u1EB8': 'E',
14735    '\u1EC6': 'E',
14736    '\u0228': 'E',
14737    '\u1E1C': 'E',
14738    '\u0118': 'E',
14739    '\u1E18': 'E',
14740    '\u1E1A': 'E',
14741    '\u0190': 'E',
14742    '\u018E': 'E',
14743    '\u24BB': 'F',
14744    '\uFF26': 'F',
14745    '\u1E1E': 'F',
14746    '\u0191': 'F',
14747    '\uA77B': 'F',
14748    '\u24BC': 'G',
14749    '\uFF27': 'G',
14750    '\u01F4': 'G',
14751    '\u011C': 'G',
14752    '\u1E20': 'G',
14753    '\u011E': 'G',
14754    '\u0120': 'G',
14755    '\u01E6': 'G',
14756    '\u0122': 'G',
14757    '\u01E4': 'G',
14758    '\u0193': 'G',
14759    '\uA7A0': 'G',
14760    '\uA77D': 'G',
14761    '\uA77E': 'G',
14762    '\u24BD': 'H',
14763    '\uFF28': 'H',
14764    '\u0124': 'H',
14765    '\u1E22': 'H',
14766    '\u1E26': 'H',
14767    '\u021E': 'H',
14768    '\u1E24': 'H',
14769    '\u1E28': 'H',
14770    '\u1E2A': 'H',
14771    '\u0126': 'H',
14772    '\u2C67': 'H',
14773    '\u2C75': 'H',
14774    '\uA78D': 'H',
14775    '\u24BE': 'I',
14776    '\uFF29': 'I',
14777    '\u00CC': 'I',
14778    '\u00CD': 'I',
14779    '\u00CE': 'I',
14780    '\u0128': 'I',
14781    '\u012A': 'I',
14782    '\u012C': 'I',
14783    '\u0130': 'I',
14784    '\u00CF': 'I',
14785    '\u1E2E': 'I',
14786    '\u1EC8': 'I',
14787    '\u01CF': 'I',
14788    '\u0208': 'I',
14789    '\u020A': 'I',
14790    '\u1ECA': 'I',
14791    '\u012E': 'I',
14792    '\u1E2C': 'I',
14793    '\u0197': 'I',
14794    '\u24BF': 'J',
14795    '\uFF2A': 'J',
14796    '\u0134': 'J',
14797    '\u0248': 'J',
14798    '\u24C0': 'K',
14799    '\uFF2B': 'K',
14800    '\u1E30': 'K',
14801    '\u01E8': 'K',
14802    '\u1E32': 'K',
14803    '\u0136': 'K',
14804    '\u1E34': 'K',
14805    '\u0198': 'K',
14806    '\u2C69': 'K',
14807    '\uA740': 'K',
14808    '\uA742': 'K',
14809    '\uA744': 'K',
14810    '\uA7A2': 'K',
14811    '\u24C1': 'L',
14812    '\uFF2C': 'L',
14813    '\u013F': 'L',
14814    '\u0139': 'L',
14815    '\u013D': 'L',
14816    '\u1E36': 'L',
14817    '\u1E38': 'L',
14818    '\u013B': 'L',
14819    '\u1E3C': 'L',
14820    '\u1E3A': 'L',
14821    '\u0141': 'L',
14822    '\u023D': 'L',
14823    '\u2C62': 'L',
14824    '\u2C60': 'L',
14825    '\uA748': 'L',
14826    '\uA746': 'L',
14827    '\uA780': 'L',
14828    '\u01C7': 'LJ',
14829    '\u01C8': 'Lj',
14830    '\u24C2': 'M',
14831    '\uFF2D': 'M',
14832    '\u1E3E': 'M',
14833    '\u1E40': 'M',
14834    '\u1E42': 'M',
14835    '\u2C6E': 'M',
14836    '\u019C': 'M',
14837    '\u24C3': 'N',
14838    '\uFF2E': 'N',
14839    '\u01F8': 'N',
14840    '\u0143': 'N',
14841    '\u00D1': 'N',
14842    '\u1E44': 'N',
14843    '\u0147': 'N',
14844    '\u1E46': 'N',
14845    '\u0145': 'N',
14846    '\u1E4A': 'N',
14847    '\u1E48': 'N',
14848    '\u0220': 'N',
14849    '\u019D': 'N',
14850    '\uA790': 'N',
14851    '\uA7A4': 'N',
14852    '\u01CA': 'NJ',
14853    '\u01CB': 'Nj',
14854    '\u24C4': 'O',
14855    '\uFF2F': 'O',
14856    '\u00D2': 'O',
14857    '\u00D3': 'O',
14858    '\u00D4': 'O',
14859    '\u1ED2': 'O',
14860    '\u1ED0': 'O',
14861    '\u1ED6': 'O',
14862    '\u1ED4': 'O',
14863    '\u00D5': 'O',
14864    '\u1E4C': 'O',
14865    '\u022C': 'O',
14866    '\u1E4E': 'O',
14867    '\u014C': 'O',
14868    '\u1E50': 'O',
14869    '\u1E52': 'O',
14870    '\u014E': 'O',
14871    '\u022E': 'O',
14872    '\u0230': 'O',
14873    '\u00D6': 'O',
14874    '\u022A': 'O',
14875    '\u1ECE': 'O',
14876    '\u0150': 'O',
14877    '\u01D1': 'O',
14878    '\u020C': 'O',
14879    '\u020E': 'O',
14880    '\u01A0': 'O',
14881    '\u1EDC': 'O',
14882    '\u1EDA': 'O',
14883    '\u1EE0': 'O',
14884    '\u1EDE': 'O',
14885    '\u1EE2': 'O',
14886    '\u1ECC': 'O',
14887    '\u1ED8': 'O',
14888    '\u01EA': 'O',
14889    '\u01EC': 'O',
14890    '\u00D8': 'O',
14891    '\u01FE': 'O',
14892    '\u0186': 'O',
14893    '\u019F': 'O',
14894    '\uA74A': 'O',
14895    '\uA74C': 'O',
14896    '\u01A2': 'OI',
14897    '\uA74E': 'OO',
14898    '\u0222': 'OU',
14899    '\u24C5': 'P',
14900    '\uFF30': 'P',
14901    '\u1E54': 'P',
14902    '\u1E56': 'P',
14903    '\u01A4': 'P',
14904    '\u2C63': 'P',
14905    '\uA750': 'P',
14906    '\uA752': 'P',
14907    '\uA754': 'P',
14908    '\u24C6': 'Q',
14909    '\uFF31': 'Q',
14910    '\uA756': 'Q',
14911    '\uA758': 'Q',
14912    '\u024A': 'Q',
14913    '\u24C7': 'R',
14914    '\uFF32': 'R',
14915    '\u0154': 'R',
14916    '\u1E58': 'R',
14917    '\u0158': 'R',
14918    '\u0210': 'R',
14919    '\u0212': 'R',
14920    '\u1E5A': 'R',
14921    '\u1E5C': 'R',
14922    '\u0156': 'R',
14923    '\u1E5E': 'R',
14924    '\u024C': 'R',
14925    '\u2C64': 'R',
14926    '\uA75A': 'R',
14927    '\uA7A6': 'R',
14928    '\uA782': 'R',
14929    '\u24C8': 'S',
14930    '\uFF33': 'S',
14931    '\u1E9E': 'S',
14932    '\u015A': 'S',
14933    '\u1E64': 'S',
14934    '\u015C': 'S',
14935    '\u1E60': 'S',
14936    '\u0160': 'S',
14937    '\u1E66': 'S',
14938    '\u1E62': 'S',
14939    '\u1E68': 'S',
14940    '\u0218': 'S',
14941    '\u015E': 'S',
14942    '\u2C7E': 'S',
14943    '\uA7A8': 'S',
14944    '\uA784': 'S',
14945    '\u24C9': 'T',
14946    '\uFF34': 'T',
14947    '\u1E6A': 'T',
14948    '\u0164': 'T',
14949    '\u1E6C': 'T',
14950    '\u021A': 'T',
14951    '\u0162': 'T',
14952    '\u1E70': 'T',
14953    '\u1E6E': 'T',
14954    '\u0166': 'T',
14955    '\u01AC': 'T',
14956    '\u01AE': 'T',
14957    '\u023E': 'T',
14958    '\uA786': 'T',
14959    '\uA728': 'TZ',
14960    '\u24CA': 'U',
14961    '\uFF35': 'U',
14962    '\u00D9': 'U',
14963    '\u00DA': 'U',
14964    '\u00DB': 'U',
14965    '\u0168': 'U',
14966    '\u1E78': 'U',
14967    '\u016A': 'U',
14968    '\u1E7A': 'U',
14969    '\u016C': 'U',
14970    '\u00DC': 'U',
14971    '\u01DB': 'U',
14972    '\u01D7': 'U',
14973    '\u01D5': 'U',
14974    '\u01D9': 'U',
14975    '\u1EE6': 'U',
14976    '\u016E': 'U',
14977    '\u0170': 'U',
14978    '\u01D3': 'U',
14979    '\u0214': 'U',
14980    '\u0216': 'U',
14981    '\u01AF': 'U',
14982    '\u1EEA': 'U',
14983    '\u1EE8': 'U',
14984    '\u1EEE': 'U',
14985    '\u1EEC': 'U',
14986    '\u1EF0': 'U',
14987    '\u1EE4': 'U',
14988    '\u1E72': 'U',
14989    '\u0172': 'U',
14990    '\u1E76': 'U',
14991    '\u1E74': 'U',
14992    '\u0244': 'U',
14993    '\u24CB': 'V',
14994    '\uFF36': 'V',
14995    '\u1E7C': 'V',
14996    '\u1E7E': 'V',
14997    '\u01B2': 'V',
14998    '\uA75E': 'V',
14999    '\u0245': 'V',
15000    '\uA760': 'VY',
15001    '\u24CC': 'W',
15002    '\uFF37': 'W',
15003    '\u1E80': 'W',
15004    '\u1E82': 'W',
15005    '\u0174': 'W',
15006    '\u1E86': 'W',
15007    '\u1E84': 'W',
15008    '\u1E88': 'W',
15009    '\u2C72': 'W',
15010    '\u24CD': 'X',
15011    '\uFF38': 'X',
15012    '\u1E8A': 'X',
15013    '\u1E8C': 'X',
15014    '\u24CE': 'Y',
15015    '\uFF39': 'Y',
15016    '\u1EF2': 'Y',
15017    '\u00DD': 'Y',
15018    '\u0176': 'Y',
15019    '\u1EF8': 'Y',
15020    '\u0232': 'Y',
15021    '\u1E8E': 'Y',
15022    '\u0178': 'Y',
15023    '\u1EF6': 'Y',
15024    '\u1EF4': 'Y',
15025    '\u01B3': 'Y',
15026    '\u024E': 'Y',
15027    '\u1EFE': 'Y',
15028    '\u24CF': 'Z',
15029    '\uFF3A': 'Z',
15030    '\u0179': 'Z',
15031    '\u1E90': 'Z',
15032    '\u017B': 'Z',
15033    '\u017D': 'Z',
15034    '\u1E92': 'Z',
15035    '\u1E94': 'Z',
15036    '\u01B5': 'Z',
15037    '\u0224': 'Z',
15038    '\u2C7F': 'Z',
15039    '\u2C6B': 'Z',
15040    '\uA762': 'Z',
15041    '\u24D0': 'a',
15042    '\uFF41': 'a',
15043    '\u1E9A': 'a',
15044    '\u00E0': 'a',
15045    '\u00E1': 'a',
15046    '\u00E2': 'a',
15047    '\u1EA7': 'a',
15048    '\u1EA5': 'a',
15049    '\u1EAB': 'a',
15050    '\u1EA9': 'a',
15051    '\u00E3': 'a',
15052    '\u0101': 'a',
15053    '\u0103': 'a',
15054    '\u1EB1': 'a',
15055    '\u1EAF': 'a',
15056    '\u1EB5': 'a',
15057    '\u1EB3': 'a',
15058    '\u0227': 'a',
15059    '\u01E1': 'a',
15060    '\u00E4': 'a',
15061    '\u01DF': 'a',
15062    '\u1EA3': 'a',
15063    '\u00E5': 'a',
15064    '\u01FB': 'a',
15065    '\u01CE': 'a',
15066    '\u0201': 'a',
15067    '\u0203': 'a',
15068    '\u1EA1': 'a',
15069    '\u1EAD': 'a',
15070    '\u1EB7': 'a',
15071    '\u1E01': 'a',
15072    '\u0105': 'a',
15073    '\u2C65': 'a',
15074    '\u0250': 'a',
15075    '\uA733': 'aa',
15076    '\u00E6': 'ae',
15077    '\u01FD': 'ae',
15078    '\u01E3': 'ae',
15079    '\uA735': 'ao',
15080    '\uA737': 'au',
15081    '\uA739': 'av',
15082    '\uA73B': 'av',
15083    '\uA73D': 'ay',
15084    '\u24D1': 'b',
15085    '\uFF42': 'b',
15086    '\u1E03': 'b',
15087    '\u1E05': 'b',
15088    '\u1E07': 'b',
15089    '\u0180': 'b',
15090    '\u0183': 'b',
15091    '\u0253': 'b',
15092    '\u24D2': 'c',
15093    '\uFF43': 'c',
15094    '\u0107': 'c',
15095    '\u0109': 'c',
15096    '\u010B': 'c',
15097    '\u010D': 'c',
15098    '\u00E7': 'c',
15099    '\u1E09': 'c',
15100    '\u0188': 'c',
15101    '\u023C': 'c',
15102    '\uA73F': 'c',
15103    '\u2184': 'c',
15104    '\u24D3': 'd',
15105    '\uFF44': 'd',
15106    '\u1E0B': 'd',
15107    '\u010F': 'd',
15108    '\u1E0D': 'd',
15109    '\u1E11': 'd',
15110    '\u1E13': 'd',
15111    '\u1E0F': 'd',
15112    '\u0111': 'd',
15113    '\u018C': 'd',
15114    '\u0256': 'd',
15115    '\u0257': 'd',
15116    '\uA77A': 'd',
15117    '\u01F3': 'dz',
15118    '\u01C6': 'dz',
15119    '\u24D4': 'e',
15120    '\uFF45': 'e',
15121    '\u00E8': 'e',
15122    '\u00E9': 'e',
15123    '\u00EA': 'e',
15124    '\u1EC1': 'e',
15125    '\u1EBF': 'e',
15126    '\u1EC5': 'e',
15127    '\u1EC3': 'e',
15128    '\u1EBD': 'e',
15129    '\u0113': 'e',
15130    '\u1E15': 'e',
15131    '\u1E17': 'e',
15132    '\u0115': 'e',
15133    '\u0117': 'e',
15134    '\u00EB': 'e',
15135    '\u1EBB': 'e',
15136    '\u011B': 'e',
15137    '\u0205': 'e',
15138    '\u0207': 'e',
15139    '\u1EB9': 'e',
15140    '\u1EC7': 'e',
15141    '\u0229': 'e',
15142    '\u1E1D': 'e',
15143    '\u0119': 'e',
15144    '\u1E19': 'e',
15145    '\u1E1B': 'e',
15146    '\u0247': 'e',
15147    '\u025B': 'e',
15148    '\u01DD': 'e',
15149    '\u24D5': 'f',
15150    '\uFF46': 'f',
15151    '\u1E1F': 'f',
15152    '\u0192': 'f',
15153    '\uA77C': 'f',
15154    '\u24D6': 'g',
15155    '\uFF47': 'g',
15156    '\u01F5': 'g',
15157    '\u011D': 'g',
15158    '\u1E21': 'g',
15159    '\u011F': 'g',
15160    '\u0121': 'g',
15161    '\u01E7': 'g',
15162    '\u0123': 'g',
15163    '\u01E5': 'g',
15164    '\u0260': 'g',
15165    '\uA7A1': 'g',
15166    '\u1D79': 'g',
15167    '\uA77F': 'g',
15168    '\u24D7': 'h',
15169    '\uFF48': 'h',
15170    '\u0125': 'h',
15171    '\u1E23': 'h',
15172    '\u1E27': 'h',
15173    '\u021F': 'h',
15174    '\u1E25': 'h',
15175    '\u1E29': 'h',
15176    '\u1E2B': 'h',
15177    '\u1E96': 'h',
15178    '\u0127': 'h',
15179    '\u2C68': 'h',
15180    '\u2C76': 'h',
15181    '\u0265': 'h',
15182    '\u0195': 'hv',
15183    '\u24D8': 'i',
15184    '\uFF49': 'i',
15185    '\u00EC': 'i',
15186    '\u00ED': 'i',
15187    '\u00EE': 'i',
15188    '\u0129': 'i',
15189    '\u012B': 'i',
15190    '\u012D': 'i',
15191    '\u00EF': 'i',
15192    '\u1E2F': 'i',
15193    '\u1EC9': 'i',
15194    '\u01D0': 'i',
15195    '\u0209': 'i',
15196    '\u020B': 'i',
15197    '\u1ECB': 'i',
15198    '\u012F': 'i',
15199    '\u1E2D': 'i',
15200    '\u0268': 'i',
15201    '\u0131': 'i',
15202    '\u24D9': 'j',
15203    '\uFF4A': 'j',
15204    '\u0135': 'j',
15205    '\u01F0': 'j',
15206    '\u0249': 'j',
15207    '\u24DA': 'k',
15208    '\uFF4B': 'k',
15209    '\u1E31': 'k',
15210    '\u01E9': 'k',
15211    '\u1E33': 'k',
15212    '\u0137': 'k',
15213    '\u1E35': 'k',
15214    '\u0199': 'k',
15215    '\u2C6A': 'k',
15216    '\uA741': 'k',
15217    '\uA743': 'k',
15218    '\uA745': 'k',
15219    '\uA7A3': 'k',
15220    '\u24DB': 'l',
15221    '\uFF4C': 'l',
15222    '\u0140': 'l',
15223    '\u013A': 'l',
15224    '\u013E': 'l',
15225    '\u1E37': 'l',
15226    '\u1E39': 'l',
15227    '\u013C': 'l',
15228    '\u1E3D': 'l',
15229    '\u1E3B': 'l',
15230    '\u017F': 'l',
15231    '\u0142': 'l',
15232    '\u019A': 'l',
15233    '\u026B': 'l',
15234    '\u2C61': 'l',
15235    '\uA749': 'l',
15236    '\uA781': 'l',
15237    '\uA747': 'l',
15238    '\u01C9': 'lj',
15239    '\u24DC': 'm',
15240    '\uFF4D': 'm',
15241    '\u1E3F': 'm',
15242    '\u1E41': 'm',
15243    '\u1E43': 'm',
15244    '\u0271': 'm',
15245    '\u026F': 'm',
15246    '\u24DD': 'n',
15247    '\uFF4E': 'n',
15248    '\u01F9': 'n',
15249    '\u0144': 'n',
15250    '\u00F1': 'n',
15251    '\u1E45': 'n',
15252    '\u0148': 'n',
15253    '\u1E47': 'n',
15254    '\u0146': 'n',
15255    '\u1E4B': 'n',
15256    '\u1E49': 'n',
15257    '\u019E': 'n',
15258    '\u0272': 'n',
15259    '\u0149': 'n',
15260    '\uA791': 'n',
15261    '\uA7A5': 'n',
15262    '\u01CC': 'nj',
15263    '\u24DE': 'o',
15264    '\uFF4F': 'o',
15265    '\u00F2': 'o',
15266    '\u00F3': 'o',
15267    '\u00F4': 'o',
15268    '\u1ED3': 'o',
15269    '\u1ED1': 'o',
15270    '\u1ED7': 'o',
15271    '\u1ED5': 'o',
15272    '\u00F5': 'o',
15273    '\u1E4D': 'o',
15274    '\u022D': 'o',
15275    '\u1E4F': 'o',
15276    '\u014D': 'o',
15277    '\u1E51': 'o',
15278    '\u1E53': 'o',
15279    '\u014F': 'o',
15280    '\u022F': 'o',
15281    '\u0231': 'o',
15282    '\u00F6': 'o',
15283    '\u022B': 'o',
15284    '\u1ECF': 'o',
15285    '\u0151': 'o',
15286    '\u01D2': 'o',
15287    '\u020D': 'o',
15288    '\u020F': 'o',
15289    '\u01A1': 'o',
15290    '\u1EDD': 'o',
15291    '\u1EDB': 'o',
15292    '\u1EE1': 'o',
15293    '\u1EDF': 'o',
15294    '\u1EE3': 'o',
15295    '\u1ECD': 'o',
15296    '\u1ED9': 'o',
15297    '\u01EB': 'o',
15298    '\u01ED': 'o',
15299    '\u00F8': 'o',
15300    '\u01FF': 'o',
15301    '\u0254': 'o',
15302    '\uA74B': 'o',
15303    '\uA74D': 'o',
15304    '\u0275': 'o',
15305    '\u01A3': 'oi',
15306    '\u0223': 'ou',
15307    '\uA74F': 'oo',
15308    '\u24DF': 'p',
15309    '\uFF50': 'p',
15310    '\u1E55': 'p',
15311    '\u1E57': 'p',
15312    '\u01A5': 'p',
15313    '\u1D7D': 'p',
15314    '\uA751': 'p',
15315    '\uA753': 'p',
15316    '\uA755': 'p',
15317    '\u24E0': 'q',
15318    '\uFF51': 'q',
15319    '\u024B': 'q',
15320    '\uA757': 'q',
15321    '\uA759': 'q',
15322    '\u24E1': 'r',
15323    '\uFF52': 'r',
15324    '\u0155': 'r',
15325    '\u1E59': 'r',
15326    '\u0159': 'r',
15327    '\u0211': 'r',
15328    '\u0213': 'r',
15329    '\u1E5B': 'r',
15330    '\u1E5D': 'r',
15331    '\u0157': 'r',
15332    '\u1E5F': 'r',
15333    '\u024D': 'r',
15334    '\u027D': 'r',
15335    '\uA75B': 'r',
15336    '\uA7A7': 'r',
15337    '\uA783': 'r',
15338    '\u24E2': 's',
15339    '\uFF53': 's',
15340    '\u00DF': 's',
15341    '\u015B': 's',
15342    '\u1E65': 's',
15343    '\u015D': 's',
15344    '\u1E61': 's',
15345    '\u0161': 's',
15346    '\u1E67': 's',
15347    '\u1E63': 's',
15348    '\u1E69': 's',
15349    '\u0219': 's',
15350    '\u015F': 's',
15351    '\u023F': 's',
15352    '\uA7A9': 's',
15353    '\uA785': 's',
15354    '\u1E9B': 's',
15355    '\u24E3': 't',
15356    '\uFF54': 't',
15357    '\u1E6B': 't',
15358    '\u1E97': 't',
15359    '\u0165': 't',
15360    '\u1E6D': 't',
15361    '\u021B': 't',
15362    '\u0163': 't',
15363    '\u1E71': 't',
15364    '\u1E6F': 't',
15365    '\u0167': 't',
15366    '\u01AD': 't',
15367    '\u0288': 't',
15368    '\u2C66': 't',
15369    '\uA787': 't',
15370    '\uA729': 'tz',
15371    '\u24E4': 'u',
15372    '\uFF55': 'u',
15373    '\u00F9': 'u',
15374    '\u00FA': 'u',
15375    '\u00FB': 'u',
15376    '\u0169': 'u',
15377    '\u1E79': 'u',
15378    '\u016B': 'u',
15379    '\u1E7B': 'u',
15380    '\u016D': 'u',
15381    '\u00FC': 'u',
15382    '\u01DC': 'u',
15383    '\u01D8': 'u',
15384    '\u01D6': 'u',
15385    '\u01DA': 'u',
15386    '\u1EE7': 'u',
15387    '\u016F': 'u',
15388    '\u0171': 'u',
15389    '\u01D4': 'u',
15390    '\u0215': 'u',
15391    '\u0217': 'u',
15392    '\u01B0': 'u',
15393    '\u1EEB': 'u',
15394    '\u1EE9': 'u',
15395    '\u1EEF': 'u',
15396    '\u1EED': 'u',
15397    '\u1EF1': 'u',
15398    '\u1EE5': 'u',
15399    '\u1E73': 'u',
15400    '\u0173': 'u',
15401    '\u1E77': 'u',
15402    '\u1E75': 'u',
15403    '\u0289': 'u',
15404    '\u24E5': 'v',
15405    '\uFF56': 'v',
15406    '\u1E7D': 'v',
15407    '\u1E7F': 'v',
15408    '\u028B': 'v',
15409    '\uA75F': 'v',
15410    '\u028C': 'v',
15411    '\uA761': 'vy',
15412    '\u24E6': 'w',
15413    '\uFF57': 'w',
15414    '\u1E81': 'w',
15415    '\u1E83': 'w',
15416    '\u0175': 'w',
15417    '\u1E87': 'w',
15418    '\u1E85': 'w',
15419    '\u1E98': 'w',
15420    '\u1E89': 'w',
15421    '\u2C73': 'w',
15422    '\u24E7': 'x',
15423    '\uFF58': 'x',
15424    '\u1E8B': 'x',
15425    '\u1E8D': 'x',
15426    '\u24E8': 'y',
15427    '\uFF59': 'y',
15428    '\u1EF3': 'y',
15429    '\u00FD': 'y',
15430    '\u0177': 'y',
15431    '\u1EF9': 'y',
15432    '\u0233': 'y',
15433    '\u1E8F': 'y',
15434    '\u00FF': 'y',
15435    '\u1EF7': 'y',
15436    '\u1E99': 'y',
15437    '\u1EF5': 'y',
15438    '\u01B4': 'y',
15439    '\u024F': 'y',
15440    '\u1EFF': 'y',
15441    '\u24E9': 'z',
15442    '\uFF5A': 'z',
15443    '\u017A': 'z',
15444    '\u1E91': 'z',
15445    '\u017C': 'z',
15446    '\u017E': 'z',
15447    '\u1E93': 'z',
15448    '\u1E95': 'z',
15449    '\u01B6': 'z',
15450    '\u0225': 'z',
15451    '\u0240': 'z',
15452    '\u2C6C': 'z',
15453    '\uA763': 'z',
15454    '\u0386': '\u0391',
15455    '\u0388': '\u0395',
15456    '\u0389': '\u0397',
15457    '\u038A': '\u0399',
15458    '\u03AA': '\u0399',
15459    '\u038C': '\u039F',
15460    '\u038E': '\u03A5',
15461    '\u03AB': '\u03A5',
15462    '\u038F': '\u03A9',
15463    '\u03AC': '\u03B1',
15464    '\u03AD': '\u03B5',
15465    '\u03AE': '\u03B7',
15466    '\u03AF': '\u03B9',
15467    '\u03CA': '\u03B9',
15468    '\u0390': '\u03B9',
15469    '\u03CC': '\u03BF',
15470    '\u03CD': '\u03C5',
15471    '\u03CB': '\u03C5',
15472    '\u03B0': '\u03C5',
15473    '\u03C9': '\u03C9',
15474    '\u03C2': '\u03C3'
15475  };
15476
15477  return diacritics;
15478});
15479
15480S2.define('select2/data/base',[
15481  '../utils'
15482], function (Utils) {
15483  function BaseAdapter ($element, options) {
15484    BaseAdapter.__super__.constructor.call(this);
15485  }
15486
15487  Utils.Extend(BaseAdapter, Utils.Observable);
15488
15489  BaseAdapter.prototype.current = function (callback) {
15490    throw new Error('The `current` method must be defined in child classes.');
15491  };
15492
15493  BaseAdapter.prototype.query = function (params, callback) {
15494    throw new Error('The `query` method must be defined in child classes.');
15495  };
15496
15497  BaseAdapter.prototype.bind = function (container, $container) {
15498    // Can be implemented in subclasses
15499  };
15500
15501  BaseAdapter.prototype.destroy = function () {
15502    // Can be implemented in subclasses
15503  };
15504
15505  BaseAdapter.prototype.generateResultId = function (container, data) {
15506    var id = 
vendor: 34,941 bytes, lines 15506-17003
15506container.id + '-result-';
15507
15508    id += Utils.generateChars(4);
15509
15510    if (data.id != null) {
15511      id += '-' + data.id.toString();
15512    } else {
15513      id += '-' + Utils.generateChars(4);
15514    }
15515    return id;
15516  };
15517
15518  return BaseAdapter;
15519});
15520
15521S2.define('select2/data/select',[
15522  './base',
15523  '../utils',
15524  'jquery'
15525], function (BaseAdapter, Utils, $) {
15526  function SelectAdapter ($element, options) {
15527    this.$element = $element;
15528    this.options = options;
15529
15530    SelectAdapter.__super__.constructor.call(this);
15531  }
15532
15533  Utils.Extend(SelectAdapter, BaseAdapter);
15534
15535  SelectAdapter.prototype.current = function (callback) {
15536    var data = [];
15537    var self = this;
15538
15539    this.$element.find(':selected').each(function () {
15540      var $option = $(this);
15541
15542      var option = self.item($option);
15543
15544      data.push(option);
15545    });
15546
15547    callback(data);
15548  };
15549
15550  SelectAdapter.prototype.select = function (data) {
15551    var self = this;
15552
15553    data.selected = true;
15554
15555    // If data.element is a DOM node, use it instead
15556    if ($(data.element).is('option')) {
15557      data.element.selected = true;
15558
15559      this.$element.trigger('change');
15560
15561      return;
15562    }
15563
15564    if (this.$element.prop('multiple')) {
15565      this.current(function (currentData) {
15566        var val = [];
15567
15568        data = [data];
15569        data.push.apply(data, currentData);
15570
15571        for (var d = 0; d < data.length; d++) {
15572          var id = data[d].id;
15573
15574          if ($.inArray(id, val) === -1) {
15575            val.push(id);
15576          }
15577        }
15578
15579        self.$element.val(val);
15580        self.$element.trigger('change');
15581      });
15582    } else {
15583      var val = data.id;
15584
15585      this.$element.val(val);
15586      this.$element.trigger('change');
15587    }
15588  };
15589
15590  SelectAdapter.prototype.unselect = function (data) {
15591    var self = this;
15592
15593    if (!this.$element.prop('multiple')) {
15594      return;
15595    }
15596
15597    data.selected = false;
15598
15599    if ($(data.element).is('option')) {
15600      data.element.selected = false;
15601
15602      this.$element.trigger('change');
15603
15604      return;
15605    }
15606
15607    this.current(function (currentData) {
15608      var val = [];
15609
15610      for (var d = 0; d < currentData.length; d++) {
15611        var id = currentData[d].id;
15612
15613        if (id !== data.id && $.inArray(id, val) === -1) {
15614          val.push(id);
15615        }
15616      }
15617
15618      self.$element.val(val);
15619
15620      self.$element.trigger('change');
15621    });
15622  };
15623
15624  SelectAdapter.prototype.bind = function (container, $container) {
15625    var self = this;
15626
15627    this.container = container;
15628
15629    container.on('select', function (params) {
15630      self.select(params.data);
15631    });
15632
15633    container.on('unselect', function (params) {
15634      self.unselect(params.data);
15635    });
15636  };
15637
15638  SelectAdapter.prototype.destroy = function () {
15639    // Remove anything added to child elements
15640    this.$element.find('*').each(function () {
15641      // Remove any custom data set by Select2
15642      $.removeData(this, 'data');
15643    });
15644  };
15645
15646  SelectAdapter.prototype.query = function (params, callback) {
15647    var data = [];
15648    var self = this;
15649
15650    var $options = this.$element.children();
15651
15652    $options.each(function () {
15653      var $option = $(this);
15654
15655      if (!$option.is('option') && !$option.is('optgroup')) {
15656        return;
15657      }
15658
15659      var option = self.item($option);
15660
15661      var matches = self.matches(params, option);
15662
15663      if (matches !== null) {
15664        data.push(matches);
15665      }
15666    });
15667
15668    callback({
15669      results: data
15670    });
15671  };
15672
15673  SelectAdapter.prototype.addOptions = function ($options) {
15674    Utils.appendMany(this.$element, $options);
15675  };
15676
15677  SelectAdapter.prototype.option = function (data) {
15678    var option;
15679
15680    if (data.children) {
15681      option = document.createElement('optgroup');
15682      option.label = data.text;
15683    } else {
15684      option = document.createElement('option');
15685
15686      if (option.textContent !== undefined) {
15687        option.textContent = data.text;
15688      } else {
15689        option.innerText = data.text;
15690      }
15691    }
15692
15693    if (data.id) {
15694      option.value = data.id;
15695    }
15696
15697    if (data.disabled) {
15698      option.disabled = true;
15699    }
15700
15701    if (data.selected) {
15702      option.selected = true;
15703    }
15704
15705    if (data.title) {
15706      option.title = data.title;
15707    }
15708
15709    var $option = $(option);
15710
15711    var normalizedData = this._normalizeItem(data);
15712    normalizedData.element = option;
15713
15714    // Override the option's data with the combined data
15715    $.data(option, 'data', normalizedData);
15716
15717    return $option;
15718  };
15719
15720  SelectAdapter.prototype.item = function ($option) {
15721    var data = {};
15722
15723    data = $.data($option[0], 'data');
15724
15725    if (data != null) {
15726      return data;
15727    }
15728
15729    if ($option.is('option')) {
15730      data = {
15731        id: $option.val(),
15732        text: $option.text(),
15733        disabled: $option.prop('disabled'),
15734        selected: $option.prop('selected'),
15735        title: $option.prop('title')
15736      };
15737    } else if ($option.is('optgroup')) {
15738      data = {
15739        text: $option.prop('label'),
15740        children: [],
15741        title: $option.prop('title')
15742      };
15743
15744      var $children = $option.children('option');
15745      var children = [];
15746
15747      for (var c = 0; c < $children.length; c++) {
15748        var $child = $($children[c]);
15749
15750        var child = this.item($child);
15751
15752        children.push(child);
15753      }
15754
15755      data.children = children;
15756    }
15757
15758    data = this._normalizeItem(data);
15759    data.element = $option[0];
15760
15761    $.data($option[0], 'data', data);
15762
15763    return data;
15764  };
15765
15766  SelectAdapter.prototype._normalizeItem = function (item) {
15767    if (!$.isPlainObject(item)) {
15768      item = {
15769        id: item,
15770        text: item
15771      };
15772    }
15773
15774    item = $.extend({}, {
15775      text: ''
15776    }, item);
15777
15778    var defaults = {
15779      selected: false,
15780      disabled: false
15781    };
15782
15783    if (item.id != null) {
15784      item.id = item.id.toString();
15785    }
15786
15787    if (item.text != null) {
15788      item.text = item.text.toString();
15789    }
15790
15791    if (item._resultId == null && item.id && this.container != null) {
15792      item._resultId = this.generateResultId(this.container, item);
15793    }
15794
15795    return $.extend({}, defaults, item);
15796  };
15797
15798  SelectAdapter.prototype.matches = function (params, data) {
15799    var matcher = this.options.get('matcher');
15800
15801    return matcher(params, data);
15802  };
15803
15804  return SelectAdapter;
15805});
15806
15807S2.define('select2/data/array',[
15808  './select',
15809  '../utils',
15810  'jquery'
15811], function (SelectAdapter, Utils, $) {
15812  function ArrayAdapter ($element, options) {
15813    var data = options.get('data') || [];
15814
15815    ArrayAdapter.__super__.constructor.call(this, $element, options);
15816
15817    this.addOptions(this.convertToOptions(data));
15818  }
15819
15820  Utils.Extend(ArrayAdapter, SelectAdapter);
15821
15822  ArrayAdapter.prototype.select = function (data) {
15823    var $option = this.$element.find('option').filter(function (i, elm) {
15824      return elm.value == data.id.toString();
15825    });
15826
15827    if ($option.length === 0) {
15828      $option = this.option(data);
15829
15830      this.addOptions($option);
15831    }
15832
15833    ArrayAdapter.__super__.select.call(this, data);
15834  };
15835
15836  ArrayAdapter.prototype.convertToOptions = function (data) {
15837    var self = this;
15838
15839    var $existing = this.$element.find('option');
15840    var existingIds = $existing.map(function () {
15841      return self.item($(this)).id;
15842    }).get();
15843
15844    var $options = [];
15845
15846    // Filter out all items except for the one passed in the argument
15847    function onlyItem (item) {
15848      return function () {
15849        return $(this).val() == item.id;
15850      };
15851    }
15852
15853    for (var d = 0; d < data.length; d++) {
15854      var item = this._normalizeItem(data[d]);
15855
15856      // Skip items which were pre-loaded, only merge the data
15857      if ($.inArray(item.id, existingIds) >= 0) {
15858        var $existingOption = $existing.filter(onlyItem(item));
15859
15860        var existingData = this.item($existingOption);
15861        var newData = $.extend(true, {}, existingData, item);
15862
15863        var $newOption = this.option(newData);
15864
15865        $existingOption.replaceWith($newOption);
15866
15867        continue;
15868      }
15869
15870      var $option = this.option(item);
15871
15872      if (item.children) {
15873        var $children = this.convertToOptions(item.children);
15874
15875        Utils.appendMany($option, $children);
15876      }
15877
15878      $options.push($option);
15879    }
15880
15881    return $options;
15882  };
15883
15884  return ArrayAdapter;
15885});
15886
15887S2.define('select2/data/ajax',[
15888  './array',
15889  '../utils',
15890  'jquery'
15891], function (ArrayAdapter, Utils, $) {
15892  function AjaxAdapter ($element, options) {
15893    this.ajaxOptions = this._applyDefaults(options.get('ajax'));
15894
15895    if (this.ajaxOptions.processResults != null) {
15896      this.processResults = this.ajaxOptions.processResults;
15897    }
15898
15899    AjaxAdapter.__super__.constructor.call(this, $element, options);
15900  }
15901
15902  Utils.Extend(AjaxAdapter, ArrayAdapter);
15903
15904  AjaxAdapter.prototype._applyDefaults = function (options) {
15905    var defaults = {
15906      data: function (params) {
15907        return $.extend({}, params, {
15908          q: params.term
15909        });
15910      },
15911      transport: function (params, success, failure) {
15912        var $request = $.ajax(params);
15913
15914        $request.then(success);
15915        $request.fail(failure);
15916
15917        return $request;
15918      }
15919    };
15920
15921    return $.extend({}, defaults, options, true);
15922  };
15923
15924  AjaxAdapter.prototype.processResults = function (results) {
15925    return results;
15926  };
15927
15928  AjaxAdapter.prototype.query = function (params, callback) {
15929    var matches = [];
15930    var self = this;
15931
15932    if (this._request != null) {
15933      // JSONP requests cannot always be aborted
15934      if ($.isFunction(this._request.abort)) {
15935        this._request.abort();
15936      }
15937
15938      this._request = null;
15939    }
15940
15941    var options = $.extend({
15942      type: 'GET'
15943    }, this.ajaxOptions);
15944
15945    if (typeof options.url === 'function') {
15946      options.url = options.url.call(this.$element, params);
15947    }
15948
15949    if (typeof options.data === 'function') {
15950      options.data = options.data.call(this.$element, params);
15951    }
15952
15953    function request () {
15954      var $request = options.transport(options, function (data) {
15955        var results = self.processResults(data, params);
15956
15957        if (self.options.get('debug') && window.console && console.error) {
15958          // Check to make sure that the response included a `results` key.
15959          if (!results || !results.results || !$.isArray(results.results)) {
15960            console.error(
15961              'Select2: The AJAX results did not return an array in the ' +
15962              '`results` key of the response.'
15963            );
15964          }
15965        }
15966
15967        callback(results);
15968      }, function () {
15969        // TODO: Handle AJAX errors
15970      });
15971
15972      self._request = $request;
15973    }
15974
15975    if (this.ajaxOptions.delay && params.term !== '') {
15976      if (this._queryTimeout) {
15977        window.clearTimeout(this._queryTimeout);
15978      }
15979
15980      this._queryTimeout = window.setTimeout(request, this.ajaxOptions.delay);
15981    } else {
15982      request();
15983    }
15984  };
15985
15986  return AjaxAdapter;
15987});
15988
15989S2.define('select2/data/tags',[
15990  'jquery'
15991], function ($) {
15992  function Tags (decorated, $element, options) {
15993    var tags = options.get('tags');
15994
15995    var createTag = options.get('createTag');
15996
15997    if (createTag !== undefined) {
15998      this.createTag = createTag;
15999    }
16000
16001    decorated.call(this, $element, options);
16002
16003    if ($.isArray(tags)) {
16004      for (var t = 0; t < tags.length; t++) {
16005        var tag = tags[t];
16006        var item = this._normalizeItem(tag);
16007
16008        var $option = this.option(item);
16009
16010        this.$element.append($option);
16011      }
16012    }
16013  }
16014
16015  Tags.prototype.query = function (decorated, params, callback) {
16016    var self = this;
16017
16018    this._removeOldTags();
16019
16020    if (params.term == null || params.page != null) {
16021      decorated.call(this, params, callback);
16022      return;
16023    }
16024
16025    function wrapper (obj, child) {
16026      var data = obj.results;
16027
16028      for (var i = 0; i < data.length; i++) {
16029        var option = data[i];
16030
16031        var checkChildren = (
16032          option.children != null &&
16033          !wrapper({
16034            results: option.children
16035          }, true)
16036        );
16037
16038        var checkText = option.text === params.term;
16039
16040        if (checkText || checkChildren) {
16041          if (child) {
16042            return false;
16043          }
16044
16045          obj.data = data;
16046          callback(obj);
16047
16048          return;
16049        }
16050      }
16051
16052      if (child) {
16053        return true;
16054      }
16055
16056      var tag = self.createTag(params);
16057
16058      if (tag != null) {
16059        var $option = self.option(tag);
16060        $option.attr('data-select2-tag', true);
16061
16062        self.addOptions([$option]);
16063
16064        self.insertTag(data, tag);
16065      }
16066
16067      obj.results = data;
16068
16069      callback(obj);
16070    }
16071
16072    decorated.call(this, params, wrapper);
16073  };
16074
16075  Tags.prototype.createTag = function (decorated, params) {
16076    var term = $.trim(params.term);
16077
16078    if (term === '') {
16079      return null;
16080    }
16081
16082    return {
16083      id: term,
16084      text: term
16085    };
16086  };
16087
16088  Tags.prototype.insertTag = function (_, data, tag) {
16089    data.unshift(tag);
16090  };
16091
16092  Tags.prototype._removeOldTags = function (_) {
16093    var tag = this._lastTag;
16094
16095    var $options = this.$element.find('option[data-select2-tag]');
16096
16097    $options.each(function () {
16098      if (this.selected) {
16099        return;
16100      }
16101
16102      $(this).remove();
16103    });
16104  };
16105
16106  return Tags;
16107});
16108
16109S2.define('select2/data/tokenizer',[
16110  'jquery'
16111], function ($) {
16112  function Tokenizer (decorated, $element, options) {
16113    var tokenizer = options.get('tokenizer');
16114
16115    if (tokenizer !== undefined) {
16116      this.tokenizer = tokenizer;
16117    }
16118
16119    decorated.call(this, $element, options);
16120  }
16121
16122  Tokenizer.prototype.bind = function (decorated, container, $container) {
16123    decorated.call(this, container, $container);
16124
16125    this.$search =  container.dropdown.$search || container.selection.$search ||
16126      $container.find('.select2-search__field');
16127  };
16128
16129  Tokenizer.prototype.query = function (decorated, params, callback) {
16130    var self = this;
16131
16132    function select (data) {
16133      self.trigger('select', {
16134        data: data
16135      });
16136    }
16137
16138    params.term = params.term || '';
16139
16140    var tokenData = this.tokenizer(params, this.options, select);
16141
16142    if (tokenData.term !== params.term) {
16143      // Replace the search term if we have the search box
16144      if (this.$search.length) {
16145        this.$search.val(tokenData.term);
16146        this.$search.focus();
16147      }
16148
16149      params.term = tokenData.term;
16150    }
16151
16152    decorated.call(this, params, callback);
16153  };
16154
16155  Tokenizer.prototype.tokenizer = function (_, params, options, callback) {
16156    var separators = options.get('tokenSeparators') || [];
16157    var term = params.term;
16158    var i = 0;
16159
16160    var createTag = this.createTag || function (params) {
16161      return {
16162        id: params.term,
16163        text: params.term
16164      };
16165    };
16166
16167    while (i < term.length) {
16168      var termChar = term[i];
16169
16170      if ($.inArray(termChar, separators) === -1) {
16171        i++;
16172
16173        continue;
16174      }
16175
16176      var part = term.substr(0, i);
16177      var partParams = $.extend({}, params, {
16178        term: part
16179      });
16180
16181      var data = createTag(partParams);
16182
16183      if (data == null) {
16184        i++;
16185        continue;
16186      }
16187
16188      callback(data);
16189
16190      // Reset the term to not include the tokenized portion
16191      term = term.substr(i + 1) || '';
16192      i = 0;
16193    }
16194
16195    return {
16196      term: term
16197    };
16198  };
16199
16200  return Tokenizer;
16201});
16202
16203S2.define('select2/data/minimumInputLength',[
16204
16205], function () {
16206  function MinimumInputLength (decorated, $e, options) {
16207    this.minimumInputLength = options.get('minimumInputLength');
16208
16209    decorated.call(this, $e, options);
16210  }
16211
16212  MinimumInputLength.prototype.query = function (decorated, params, callback) {
16213    params.term = params.term || '';
16214
16215    if (params.term.length < this.minimumInputLength) {
16216      this.trigger('results:message', {
16217        message: 'inputTooShort',
16218        args: {
16219          minimum: this.minimumInputLength,
16220          input: params.term,
16221          params: params
16222        }
16223      });
16224
16225      return;
16226    }
16227
16228    decorated.call(this, params, callback);
16229  };
16230
16231  return MinimumInputLength;
16232});
16233
16234S2.define('select2/data/maximumInputLength',[
16235
16236], function () {
16237  function MaximumInputLength (decorated, $e, options) {
16238    this.maximumInputLength = options.get('maximumInputLength');
16239
16240    decorated.call(this, $e, options);
16241  }
16242
16243  MaximumInputLength.prototype.query = function (decorated, params, callback) {
16244    params.term = params.term || '';
16245
16246    if (this.maximumInputLength > 0 &&
16247        params.term.length > this.maximumInputLength) {
16248      this.trigger('results:message', {
16249        message: 'inputTooLong',
16250        args: {
16251          maximum: this.maximumInputLength,
16252          input: params.term,
16253          params: params
16254        }
16255      });
16256
16257      return;
16258    }
16259
16260    decorated.call(this, params, callback);
16261  };
16262
16263  return MaximumInputLength;
16264});
16265
16266S2.define('select2/data/maximumSelectionLength',[
16267
16268], function (){
16269  function MaximumSelectionLength (decorated, $e, options) {
16270    this.maximumSelectionLength = options.get('maximumSelectionLength');
16271
16272    decorated.call(this, $e, options);
16273  }
16274
16275  MaximumSelectionLength.prototype.query =
16276    function (decorated, params, callback) {
16277      var self = this;
16278
16279      this.current(function (currentData) {
16280        var count = currentData != null ? currentData.length : 0;
16281        if (self.maximumSelectionLength > 0 &&
16282          count >= self.maximumSelectionLength) {
16283          self.trigger('results:message', {
16284            message: 'maximumSelected',
16285            args: {
16286              maximum: self.maximumSelectionLength
16287            }
16288          });
16289          return;
16290        }
16291        decorated.call(self, params, callback);
16292      });
16293  };
16294
16295  return MaximumSelectionLength;
16296});
16297
16298S2.define('select2/dropdown',[
16299  'jquery',
16300  './utils'
16301], function ($, Utils) {
16302  function Dropdown ($element, options) {
16303    this.$element = $element;
16304    this.options = options;
16305
16306    Dropdown.__super__.constructor.call(this);
16307  }
16308
16309  Utils.Extend(Dropdown, Utils.Observable);
16310
16311  Dropdown.prototype.render = function () {
16312    var $dropdown = $(
16313      '<span class="select2-dropdown">' +
16314        '<span class="select2-results"></span>' +
16315      '</span>'
16316    );
16317
16318    $dropdown.attr('dir', this.options.get('dir'));
16319
16320    this.$dropdown = $dropdown;
16321
16322    return $dropdown;
16323  };
16324
16325  Dropdown.prototype.bind = function () {
16326    // Should be implemented in subclasses
16327  };
16328
16329  Dropdown.prototype.position = function ($dropdown, $container) {
16330    // Should be implmented in subclasses
16331  };
16332
16333  Dropdown.prototype.destroy = function () {
16334    // Remove the dropdown from the DOM
16335    this.$dropdown.remove();
16336  };
16337
16338  return Dropdown;
16339});
16340
16341S2.define('select2/dropdown/search',[
16342  'jquery',
16343  '../utils'
16344], function ($, Utils) {
16345  function Search () { }
16346
16347  Search.prototype.render = function (decorated) {
16348    var $rendered = decorated.call(this);
16349
16350    var $search = $(
16351      '<span class="select2-search select2-search--dropdown">' +
16352        '<input class="select2-search__field" type="search" tabindex="-1"' +
16353        ' autocomplete="off" autocorrect="off" autocapitalize="off"' +
16354        ' spellcheck="false" role="textbox" />' +
16355      '</span>'
16356    );
16357
16358    this.$searchContainer = $search;
16359    this.$search = $search.find('input');
16360
16361    $rendered.prepend($search);
16362
16363    return $rendered;
16364  };
16365
16366  Search.prototype.bind = function (decorated, container, $container) {
16367    var self = this;
16368
16369    decorated.call(this, container, $container);
16370
16371    this.$search.on('keydown', function (evt) {
16372      self.trigger('keypress', evt);
16373
16374      self._keyUpPrevented = evt.isDefaultPrevented();
16375    });
16376
16377    // Workaround for browsers which do not support the `input` event
16378    // This will prevent double-triggering of events for browsers which support
16379    // both the `keyup` and `input` events.
16380    this.$search.on('input', function (evt) {
16381      // Unbind the duplicated `keyup` event
16382      $(this).off('keyup');
16383    });
16384
16385    this.$search.on('keyup input', function (evt) {
16386      self.handleSearch(evt);
16387    });
16388
16389    container.on('open', function () {
16390      self.$search.attr('tabindex', 0);
16391
16392      self.$search.focus();
16393
16394      window.setTimeout(function () {
16395        self.$search.focus();
16396      }, 0);
16397    });
16398
16399    container.on('close', function () {
16400      self.$search.attr('tabindex', -1);
16401
16402      self.$search.val('');
16403    });
16404
16405    container.on('results:all', function (params) {
16406      if (params.query.term == null || params.query.term === '') {
16407        var showSearch = self.showSearch(params);
16408
16409        if (showSearch) {
16410          self.$searchContainer.removeClass('select2-search--hide');
16411        } else {
16412          self.$searchContainer.addClass('select2-search--hide');
16413        }
16414      }
16415    });
16416  };
16417
16418  Search.prototype.handleSearch = function (evt) {
16419    if (!this._keyUpPrevented) {
16420      var input = this.$search.val();
16421
16422      this.trigger('query', {
16423        term: input
16424      });
16425    }
16426
16427    this._keyUpPrevented = false;
16428  };
16429
16430  Search.prototype.showSearch = function (_, params) {
16431    return true;
16432  };
16433
16434  return Search;
16435});
16436
16437S2.define('select2/dropdown/hidePlaceholder',[
16438
16439], function () {
16440  function HidePlaceholder (decorated, $element, options, dataAdapter) {
16441    this.placeholder = this.normalizePlaceholder(options.get('placeholder'));
16442
16443    decorated.call(this, $element, options, dataAdapter);
16444  }
16445
16446  HidePlaceholder.prototype.append = function (decorated, data) {
16447    data.results = this.removePlaceholder(data.results);
16448
16449    decorated.call(this, data);
16450  };
16451
16452  HidePlaceholder.prototype.normalizePlaceholder = function (_, placeholder) {
16453    if (typeof placeholder === 'string') {
16454      placeholder = {
16455        id: '',
16456        text: placeholder
16457      };
16458    }
16459
16460    return placeholder;
16461  };
16462
16463  HidePlaceholder.prototype.removePlaceholder = function (_, data) {
16464    var modifiedData = data.slice(0);
16465
16466    for (var d = data.length - 1; d >= 0; d--) {
16467      var item = data[d];
16468
16469      if (this.placeholder.id === item.id) {
16470        modifiedData.splice(d, 1);
16471      }
16472    }
16473
16474    return modifiedData;
16475  };
16476
16477  return HidePlaceholder;
16478});
16479
16480S2.define('select2/dropdown/infiniteScroll',[
16481  'jquery'
16482], function ($) {
16483  function InfiniteScroll (decorated, $element, options, dataAdapter) {
16484    this.lastParams = {};
16485
16486    decorated.call(this, $element, options, dataAdapter);
16487
16488    this.$loadingMore = this.createLoadingMore();
16489    this.loading = false;
16490  }
16491
16492  InfiniteScroll.prototype.append = function (decorated, data) {
16493    this.$loadingMore.remove();
16494    this.loading = false;
16495
16496    decorated.call(this, data);
16497
16498    if (this.showLoadingMore(data)) {
16499      this.$results.append(this.$loadingMore);
16500    }
16501  };
16502
16503  InfiniteScroll.prototype.bind = function (decorated, container, $container) {
16504    var self = this;
16505
16506    decorated.call(this, container, $container);
16507
16508    container.on('query', function (params) {
16509      self.lastParams = params;
16510      self.loading = true;
16511    });
16512
16513    container.on('query:append', function (params) {
16514      self.lastParams = params;
16515      self.loading = true;
16516    });
16517
16518    this.$results.on('scroll', function () {
16519      var isLoadMoreVisible = $.contains(
16520        document.documentElement,
16521        self.$loadingMore[0]
16522      );
16523
16524      if (self.loading || !isLoadMoreVisible) {
16525        return;
16526      }
16527
16528      var currentOffset = self.$results.offset().top +
16529        self.$results.outerHeight(false);
16530      var loadingMoreOffset = self.$loadingMore.offset().top +
16531        self.$loadingMore.outerHeight(false);
16532
16533      if (currentOffset + 50 >= loadingMoreOffset) {
16534        self.loadMore();
16535      }
16536    });
16537  };
16538
16539  InfiniteScroll.prototype.loadMore = function () {
16540    this.loading = true;
16541
16542    var params = $.extend({}, {page: 1}, this.lastParams);
16543
16544    params.page++;
16545
16546    this.trigger('query:append', params);
16547  };
16548
16549  InfiniteScroll.prototype.showLoadingMore = function (_, data) {
16550    return data.pagination && data.pagination.more;
16551  };
16552
16553  InfiniteScroll.prototype.createLoadingMore = function () {
16554    var $option = $(
16555      '<li ' +
16556      'class="select2-results__option select2-results__option--load-more"' +
16557      'role="treeitem" aria-disabled="true"></li>'
16558    );
16559
16560    var message = this.options.get('translations').get('loadingMore');
16561
16562    $option.html(message(this.lastParams));
16563
16564    return $option;
16565  };
16566
16567  return InfiniteScroll;
16568});
16569
16570S2.define('select2/dropdown/attachBody',[
16571  'jquery',
16572  '../utils'
16573], function ($, Utils) {
16574  function AttachBody (decorated, $element, options) {
16575    this.$dropdownParent = options.get('dropdownParent') || $(document.body);
16576
16577    decorated.call(this, $element, options);
16578  }
16579
16580  AttachBody.prototype.bind = function (decorated, container, $container) {
16581    var self = this;
16582
16583    var setupResultsEvents = false;
16584
16585    decorated.call(this, container, $container);
16586
16587    container.on('open', function () {
16588      self._showDropdown();
16589      self._attachPositioningHandler(container);
16590
16591      if (!setupResultsEvents) {
16592        setupResultsEvents = true;
16593
16594        container.on('results:all', function () {
16595          self._positionDropdown();
16596          self._resizeDropdown();
16597        });
16598
16599        container.on('results:append', function () {
16600          self._positionDropdown();
16601          self._resizeDropdown();
16602        });
16603      }
16604    });
16605
16606    container.on('close', function () {
16607      self._hideDropdown();
16608      self._detachPositioningHandler(container);
16609    });
16610
16611    this.$dropdownContainer.on('mousedown', function (evt) {
16612      evt.stopPropagation();
16613    });
16614  };
16615
16616  AttachBody.prototype.destroy = function (decorated) {
16617    decorated.call(this);
16618
16619    this.$dropdownContainer.remove();
16620  };
16621
16622  AttachBody.prototype.position = function (decorated, $dropdown, $container) {
16623    // Clone all of the container classes
16624    $dropdown.attr('class', $container.attr('class'));
16625
16626    $dropdown.removeClass('select2');
16627    $dropdown.addClass('select2-container--open');
16628
16629    $dropdown.css({
16630      position: 'absolute',
16631      top: -999999
16632    });
16633
16634    this.$container = $container;
16635  };
16636
16637  AttachBody.prototype.render = function (decorated) {
16638    var $container = $('<span></span>');
16639
16640    var $dropdown = decorated.call(this);
16641    $container.append($dropdown);
16642
16643    this.$dropdownContainer = $container;
16644
16645    return $container;
16646  };
16647
16648  AttachBody.prototype._hideDropdown = function (decorated) {
16649    this.$dropdownContainer.detach();
16650  };
16651
16652  AttachBody.prototype._attachPositioningHandler =
16653      function (decorated, container) {
16654    var self = this;
16655
16656    var scrollEvent = 'scroll.select2.' + container.id;
16657    var resizeEvent = 'resize.select2.' + container.id;
16658    var orientationEvent = 'orientationchange.select2.' + container.id;
16659
16660    var $watchers = this.$container.parents().filter(Utils.hasScroll);
16661    $watchers.each(function () {
16662      $(this).data('select2-scroll-position', {
16663        x: $(this).scrollLeft(),
16664        y: $(this).scrollTop()
16665      });
16666    });
16667
16668    $watchers.on(scrollEvent, function (ev) {
16669      var position = $(this).data('select2-scroll-position');
16670      $(this).scrollTop(position.y);
16671    });
16672
16673    $(window).on(scrollEvent + ' ' + resizeEvent + ' ' + orientationEvent,
16674      function (e) {
16675      self._positionDropdown();
16676      self._resizeDropdown();
16677    });
16678  };
16679
16680  AttachBody.prototype._detachPositioningHandler =
16681      function (decorated, container) {
16682    var scrollEvent = 'scroll.select2.' + container.id;
16683    var resizeEvent = 'resize.select2.' + container.id;
16684    var orientationEvent = 'orientationchange.select2.' + container.id;
16685
16686    var $watchers = this.$container.parents().filter(Utils.hasScroll);
16687    $watchers.off(scrollEvent);
16688
16689    $(window).off(scrollEvent + ' ' + resizeEvent + ' ' + orientationEvent);
16690  };
16691
16692  AttachBody.prototype._positionDropdown = function () {
16693    var $window = $(window);
16694
16695    var isCurrentlyAbove = this.$dropdown.hasClass('select2-dropdown--above');
16696    var isCurrentlyBelow = this.$dropdown.hasClass('select2-dropdown--below');
16697
16698    var newDirection = null;
16699
16700    var position = this.$container.position();
16701    var offset = this.$container.offset();
16702
16703    offset.bottom = offset.top + this.$container.outerHeight(false);
16704
16705    var container = {
16706      height: this.$container.outerHeight(false)
16707    };
16708
16709    container.top = offset.top;
16710    container.bottom = offset.top + container.height;
16711
16712    var dropdown = {
16713      height: this.$dropdown.outerHeight(false)
16714    };
16715
16716    var viewport = {
16717      top: $window.scrollTop(),
16718      bottom: $window.scrollTop() + $window.height()
16719    };
16720
16721    var enoughRoomAbove = viewport.top < (offset.top - dropdown.height);
16722    var enoughRoomBelow = viewport.bottom > (offset.bottom + dropdown.height);
16723
16724    var css = {
16725      left: offset.left,
16726      top: container.bottom
16727    };
16728
16729    // Fix positioning with static parents
16730    if (this.$dropdownParent[0].style.position !== 'static') {
16731      var parentOffset = this.$dropdownParent.offset();
16732
16733      css.top -= parentOffset.top;
16734      css.left -= parentOffset.left;
16735    }
16736
16737    if (!isCurrentlyAbove && !isCurrentlyBelow) {
16738      newDirection = 'below';
16739    }
16740
16741    if (!enoughRoomBelow && enoughRoomAbove && !isCurrentlyAbove) {
16742      newDirection = 'above';
16743    } else if (!enoughRoomAbove && enoughRoomBelow && isCurrentlyAbove) {
16744      newDirection = 'below';
16745    }
16746
16747    if (newDirection == 'above' ||
16748      (isCurrentlyAbove && newDirection !== 'below')) {
16749      css.top = container.top - dropdown.height;
16750    }
16751
16752    if (newDirection != null) {
16753      this.$dropdown
16754        .removeClass('select2-dropdown--below select2-dropdown--above')
16755        .addClass('select2-dropdown--' + newDirection);
16756      this.$container
16757        .removeClass('select2-container--below select2-container--above')
16758        .addClass('select2-container--' + newDirection);
16759    }
16760
16761    this.$dropdownContainer.css(css);
16762  };
16763
16764  AttachBody.prototype._resizeDropdown = function () {
16765    var css = {
16766      width: this.$container.outerWidth(false) + 'px'
16767    };
16768
16769    if (this.options.get('dropdownAutoWidth')) {
16770      css.minWidth = css.width;
16771      css.width = 'auto';
16772    }
16773
16774    this.$dropdown.css(css);
16775  };
16776
16777  AttachBody.prototype._showDropdown = function (decorated) {
16778    this.$dropdownContainer.appendTo(this.$dropdownParent);
16779
16780    this._positionDropdown();
16781    this._resizeDropdown();
16782  };
16783
16784  return AttachBody;
16785});
16786
16787S2.define('select2/dropdown/minimumResultsForSearch',[
16788
16789], function () {
16790  function countResults (data) {
16791    var count = 0;
16792
16793    for (var d = 0; d < data.length; d++) {
16794      var item = data[d];
16795
16796      if (item.children) {
16797        count += countResults(item.children);
16798      } else {
16799        count++;
16800      }
16801    }
16802
16803    return count;
16804  }
16805
16806  function MinimumResultsForSearch (decorated, $element, options, dataAdapter) {
16807    this.minimumResultsForSearch = options.get('minimumResultsForSearch');
16808
16809    if (this.minimumResultsForSearch < 0) {
16810      this.minimumResultsForSearch = Infinity;
16811    }
16812
16813    decorated.call(this, $element, options, dataAdapter);
16814  }
16815
16816  MinimumResultsForSearch.prototype.showSearch = function (decorated, params) {
16817    if (countResults(params.data.results) < this.minimumResultsForSearch) {
16818      return false;
16819    }
16820
16821    return decorated.call(this, params);
16822  };
16823
16824  return MinimumResultsForSearch;
16825});
16826
16827S2.define('select2/dropdown/selectOnClose',[
16828
16829], function () {
16830  function SelectOnClose () { }
16831
16832  SelectOnClose.prototype.bind = function (decorated, container, $container) {
16833    var self = this;
16834
16835    decorated.call(this, container, $container);
16836
16837    container.on('close', function () {
16838      self._handleSelectOnClose();
16839    });
16840  };
16841
16842  SelectOnClose.prototype._handleSelectOnClose = function () {
16843    var $highlightedResults = this.getHighlightedResults();
16844
16845    // Only select highlighted results
16846    if ($highlightedResults.length < 1) {
16847      return;
16848    }
16849
16850    var data = $highlightedResults.data('data');
16851
16852    // Don't re-select already selected resulte
16853    if (
16854      (data.element != null && data.element.selected) ||
16855      (data.element == null && data.selected)
16856    ) {
16857      return;
16858    }
16859
16860    this.trigger('select', {
16861        data: data
16862    });
16863  };
16864
16865  return SelectOnClose;
16866});
16867
16868S2.define('select2/dropdown/closeOnSelect',[
16869
16870], function () {
16871  function CloseOnSelect () { }
16872
16873  CloseOnSelect.prototype.bind = function (decorated, container, $container) {
16874    var self = this;
16875
16876    decorated.call(this, container, $container);
16877
16878    container.on('select', function (evt) {
16879      self._selectTriggered(evt);
16880    });
16881
16882    container.on('unselect', function (evt) {
16883      self._selectTriggered(evt);
16884    });
16885  };
16886
16887  CloseOnSelect.prototype._selectTriggered = function (_, evt) {
16888    var originalEvent = evt.originalEvent;
16889
16890    // Don't close if the control key is being held
16891    if (originalEvent && originalEvent.ctrlKey) {
16892      return;
16893    }
16894
16895    this.trigger('close', {});
16896  };
16897
16898  return CloseOnSelect;
16899});
16900
16901S2.define('select2/i18n/en',[],function () {
16902  // English
16903  return {
16904    errorLoading: function () {
16905      return 'The results could not be loaded.';
16906    },
16907    inputTooLong: function (args) {
16908      var overChars = args.input.length - args.maximum;
16909
16910      var message = 'Please delete ' + overChars + ' character';
16911
16912      if (overChars != 1) {
16913        message += 's';
16914      }
16915
16916      return message;
16917    },
16918    inputTooShort: function (args) {
16919      var remainingChars = args.minimum - args.input.length;
16920
16921      var message = 'Please enter ' + remainingChars + ' or more characters';
16922
16923      return message;
16924    },
16925    loadingMore: function () {
16926      return 'Loading more results…';
16927    },
16928    maximumSelected: function (args) {
16929      var message = 'You can only select ' + args.maximum + ' item';
16930
16931      if (args.maximum != 1) {
16932        message += 's';
16933      }
16934
16935      return message;
16936    },
16937    noResults: function () {
16938      return 'No results found';
16939    },
16940    searching: function () {
16941      return 'Searching…';
16942    }
16943  };
16944});
16945
16946S2.define('select2/defaults',[
16947  'jquery',
16948  'require',
16949
16950  './results',
16951
16952  './selection/single',
16953  './selection/multiple',
16954  './selection/placeholder',
16955  './selection/allowClear',
16956  './selection/search',
16957  './selection/eventRelay',
16958
16959  './utils',
16960  './translation',
16961  './diacritics',
16962
16963  './data/select',
16964  './data/array',
16965  './data/ajax',
16966  './data/tags',
16967  './data/tokenizer',
16968  './data/minimumInputLength',
16969  './data/maximumInputLength',
16970  './data/maximumSelectionLength',
16971
16972  './dropdown',
16973  './dropdown/search',
16974  './dropdown/hidePlaceholder',
16975  './dropdown/infiniteScroll',
16976  './dropdown/attachBody',
16977  './dropdown/minimumResultsForSearch',
16978  './dropdown/selectOnClose',
16979  './dropdown/closeOnSelect',
16980
16981  './i18n/en'
16982], function ($, require,
16983
16984             ResultsList,
16985
16986             SingleSelection, MultipleSelection, Placeholder, AllowClear,
16987             SelectionSearch, EventRelay,
16988
16989             Utils, Translation, DIACRITICS,
16990
16991             SelectData, ArrayData, AjaxData, Tags, Tokenizer,
16992             MinimumInputLength, MaximumInputLength, MaximumSelectionLength,
16993
16994             Dropdown, DropdownSearch, HidePlaceholder, InfiniteScroll,
16995             AttachBody, MinimumResultsForSearch, SelectOnClose, CloseOnSelect,
16996
16997             EnglishTranslation) {
16998  function Defaults () {
16999    this.reset();
17000  }
17001
17002  Defaults.prototype.apply = function (options) {
17003    options = $.extend(
vendor: 15,268 bytes, lines 17003-17567
17003{}, this.defaults, options);
17004
17005    if (options.dataAdapter == null) {
17006      if (options.ajax != null) {
17007        options.dataAdapter = AjaxData;
17008      } else if (options.data != null) {
17009        options.dataAdapter = ArrayData;
17010      } else {
17011        options.dataAdapter = SelectData;
17012      }
17013
17014      if (options.minimumInputLength > 0) {
17015        options.dataAdapter = Utils.Decorate(
17016          options.dataAdapter,
17017          MinimumInputLength
17018        );
17019      }
17020
17021      if (options.maximumInputLength > 0) {
17022        options.dataAdapter = Utils.Decorate(
17023          options.dataAdapter,
17024          MaximumInputLength
17025        );
17026      }
17027
17028      if (options.maximumSelectionLength > 0) {
17029        options.dataAdapter = Utils.Decorate(
17030          options.dataAdapter,
17031          MaximumSelectionLength
17032        );
17033      }
17034
17035      if (options.tags) {
17036        options.dataAdapter = Utils.Decorate(options.dataAdapter, Tags);
17037      }
17038
17039      if (options.tokenSeparators != null || options.tokenizer != null) {
17040        options.dataAdapter = Utils.Decorate(
17041          options.dataAdapter,
17042          Tokenizer
17043        );
17044      }
17045
17046      if (options.query != null) {
17047        var Query = require(options.amdBase + 'compat/query');
17048
17049        options.dataAdapter = Utils.Decorate(
17050          options.dataAdapter,
17051          Query
17052        );
17053      }
17054
17055      if (options.initSelection != null) {
17056        var InitSelection = require(options.amdBase + 'compat/initSelection');
17057
17058        options.dataAdapter = Utils.Decorate(
17059          options.dataAdapter,
17060          InitSelection
17061        );
17062      }
17063    }
17064
17065    if (options.resultsAdapter == null) {
17066      options.resultsAdapter = ResultsList;
17067
17068      if (options.ajax != null) {
17069        options.resultsAdapter = Utils.Decorate(
17070          options.resultsAdapter,
17071          InfiniteScroll
17072        );
17073      }
17074
17075      if (options.placeholder != null) {
17076        options.resultsAdapter = Utils.Decorate(
17077          options.resultsAdapter,
17078          HidePlaceholder
17079        );
17080      }
17081
17082      if (options.selectOnClose) {
17083        options.resultsAdapter = Utils.Decorate(
17084          options.resultsAdapter,
17085          SelectOnClose
17086        );
17087      }
17088    }
17089
17090    if (options.dropdownAdapter == null) {
17091      if (options.multiple) {
17092        options.dropdownAdapter = Dropdown;
17093      } else {
17094        var SearchableDropdown = Utils.Decorate(Dropdown, DropdownSearch);
17095
17096        options.dropdownAdapter = SearchableDropdown;
17097      }
17098
17099      if (options.minimumResultsForSearch !== 0) {
17100        options.dropdownAdapter = Utils.Decorate(
17101          options.dropdownAdapter,
17102          MinimumResultsForSearch
17103        );
17104      }
17105
17106      if (options.closeOnSelect) {
17107        options.dropdownAdapter = Utils.Decorate(
17108          options.dropdownAdapter,
17109          CloseOnSelect
17110        );
17111      }
17112
17113      if (
17114        options.dropdownCssClass != null ||
17115        options.dropdownCss != null ||
17116        options.adaptDropdownCssClass != null
17117      ) {
17118        var DropdownCSS = require(options.amdBase + 'compat/dropdownCss');
17119
17120        options.dropdownAdapter = Utils.Decorate(
17121          options.dropdownAdapter,
17122          DropdownCSS
17123        );
17124      }
17125
17126      options.dropdownAdapter = Utils.Decorate(
17127        options.dropdownAdapter,
17128        AttachBody
17129      );
17130    }
17131
17132    if (options.selectionAdapter == null) {
17133      if (options.multiple) {
17134        options.selectionAdapter = MultipleSelection;
17135      } else {
17136        options.selectionAdapter = SingleSelection;
17137      }
17138
17139      // Add the placeholder mixin if a placeholder was specified
17140      if (options.placeholder != null) {
17141        options.selectionAdapter = Utils.Decorate(
17142          options.selectionAdapter,
17143          Placeholder
17144        );
17145      }
17146
17147      if (options.allowClear) {
17148        options.selectionAdapter = Utils.Decorate(
17149          options.selectionAdapter,
17150          AllowClear
17151        );
17152      }
17153
17154      if (options.multiple) {
17155        options.selectionAdapter = Utils.Decorate(
17156          options.selectionAdapter,
17157          SelectionSearch
17158        );
17159      }
17160
17161      if (
17162        options.containerCssClass != null ||
17163        options.containerCss != null ||
17164        options.adaptContainerCssClass != null
17165      ) {
17166        var ContainerCSS = require(options.amdBase + 'compat/containerCss');
17167
17168        options.selectionAdapter = Utils.Decorate(
17169          options.selectionAdapter,
17170          ContainerCSS
17171        );
17172      }
17173
17174      options.selectionAdapter = Utils.Decorate(
17175        options.selectionAdapter,
17176        EventRelay
17177      );
17178    }
17179
17180    if (typeof options.language === 'string') {
17181      // Check if the language is specified with a region
17182      if (options.language.indexOf('-') > 0) {
17183        // Extract the region information if it is included
17184        var languageParts = options.language.split('-');
17185        var baseLanguage = languageParts[0];
17186
17187        options.language = [options.language, baseLanguage];
17188      } else {
17189        options.language = [options.language];
17190      }
17191    }
17192
17193    if ($.isArray(options.language)) {
17194      var languages = new Translation();
17195      options.language.push('en');
17196
17197      var languageNames = options.language;
17198
17199      for (var l = 0; l < languageNames.length; l++) {
17200        var name = languageNames[l];
17201        var language = {};
17202
17203        try {
17204          // Try to load it with the original name
17205          language = Translation.loadPath(name);
17206        } catch (e) {
17207          try {
17208            // If we couldn't load it, check if it wasn't the full path
17209            name = this.defaults.amdLanguageBase + name;
17210            language = Translation.loadPath(name);
17211          } catch (ex) {
17212            // The translation could not be loaded at all. Sometimes this is
17213            // because of a configuration problem, other times this can be
17214            // because of how Select2 helps load all possible translation files.
17215            if (options.debug && window.console && console.warn) {
17216              console.warn(
17217                'Select2: The language file for "' + name + '" could not be ' +
17218                'automatically loaded. A fallback will be used instead.'
17219              );
17220            }
17221
17222            continue;
17223          }
17224        }
17225
17226        languages.extend(language);
17227      }
17228
17229      options.translations = languages;
17230    } else {
17231      var baseTranslation = Translation.loadPath(
17232        this.defaults.amdLanguageBase + 'en'
17233      );
17234      var customTranslation = new Translation(options.language);
17235
17236      customTranslation.extend(baseTranslation);
17237
17238      options.translations = customTranslation;
17239    }
17240
17241    return options;
17242  };
17243
17244  Defaults.prototype.reset = function () {
17245    function stripDiacritics (text) {
17246      // Used 'uni range + named function' from http://jsperf.com/diacritics/18
17247      function match(a) {
17248        return DIACRITICS[a] || a;
17249      }
17250
17251      return text.replace(/[^\u0000-\u007E]/g, match);
17252    }
17253
17254    function matcher (params, data) {
17255      // Always return the object if there is nothing to compare
17256      if ($.trim(params.term) === '') {
17257        return data;
17258      }
17259
17260      // Do a recursive check for options with children
17261      if (data.children && data.children.length > 0) {
17262        // Clone the data object if there are children
17263        // This is required as we modify the object to remove any non-matches
17264        var match = $.extend(true, {}, data);
17265
17266        // Check each child of the option
17267        for (var c = data.children.length - 1; c >= 0; c--) {
17268          var child = data.children[c];
17269
17270          var matches = matcher(params, child);
17271
17272          // If there wasn't a match, remove the object in the array
17273          if (matches == null) {
17274            match.children.splice(c, 1);
17275          }
17276        }
17277
17278        // If any children matched, return the new object
17279        if (match.children.length > 0) {
17280          return match;
17281        }
17282
17283        // If there were no matching children, check just the plain object
17284        return matcher(params, match);
17285      }
17286
17287      var original = stripDiacritics(data.text).toUpperCase();
17288      var term = stripDiacritics(params.term).toUpperCase();
17289
17290      // Check if the text contains the term
17291      if (original.indexOf(term) > -1) {
17292        return data;
17293      }
17294
17295      // If it doesn't contain the term, don't return anything
17296      return null;
17297    }
17298
17299    this.defaults = {
17300      amdBase: './',
17301      amdLanguageBase: './i18n/',
17302      closeOnSelect: true,
17303      debug: false,
17304      dropdownAutoWidth: false,
17305      escapeMarkup: Utils.escapeMarkup,
17306      language: EnglishTranslation,
17307      matcher: matcher,
17308      minimumInputLength: 0,
17309      maximumInputLength: 0,
17310      maximumSelectionLength: 0,
17311      minimumResultsForSearch: 0,
17312      selectOnClose: false,
17313      sorter: function (data) {
17314        return data;
17315      },
17316      templateResult: function (result) {
17317        return result.text;
17318      },
17319      templateSelection: function (selection) {
17320        return selection.text;
17321      },
17322      theme: 'default',
17323      width: 'resolve'
17324    };
17325  };
17326
17327  Defaults.prototype.set = function (key, value) {
17328    var camelKey = $.camelCase(key);
17329
17330    var data = {};
17331    data[camelKey] = value;
17332
17333    var convertedData = Utils._convertData(data);
17334
17335    $.extend(this.defaults, convertedData);
17336  };
17337
17338  var defaults = new Defaults();
17339
17340  return defaults;
17341});
17342
17343S2.define('select2/options',[
17344  'require',
17345  'jquery',
17346  './defaults',
17347  './utils'
17348], function (require, $, Defaults, Utils) {
17349  function Options (options, $element) {
17350    this.options = options;
17351
17352    if ($element != null) {
17353      this.fromElement($element);
17354    }
17355
17356    this.options = Defaults.apply(this.options);
17357
17358    if ($element && $element.is('input')) {
17359      var InputCompat = require(this.get('amdBase') + 'compat/inputData');
17360
17361      this.options.dataAdapter = Utils.Decorate(
17362        this.options.dataAdapter,
17363        InputCompat
17364      );
17365    }
17366  }
17367
17368  Options.prototype.fromElement = function ($e) {
17369    var excludedData = ['select2'];
17370
17371    if (this.options.multiple == null) {
17372      this.options.multiple = $e.prop('multiple');
17373    }
17374
17375    if (this.options.disabled == null) {
17376      this.options.disabled = $e.prop('disabled');
17377    }
17378
17379    if (this.options.language == null) {
17380      if ($e.prop('lang')) {
17381        this.options.language = $e.prop('lang').toLowerCase();
17382      } else if ($e.closest('[lang]').prop('lang')) {
17383        this.options.language = $e.closest('[lang]').prop('lang');
17384      }
17385    }
17386
17387    if (this.options.dir == null) {
17388      if ($e.prop('dir')) {
17389        this.options.dir = $e.prop('dir');
17390      } else if ($e.closest('[dir]').prop('dir')) {
17391        this.options.dir = $e.closest('[dir]').prop('dir');
17392      } else {
17393        this.options.dir = 'ltr';
17394      }
17395    }
17396
17397    $e.prop('disabled', this.options.disabled);
17398    $e.prop('multiple', this.options.multiple);
17399
17400    if ($e.data('select2Tags')) {
17401      if (this.options.debug && window.console && console.warn) {
17402        console.warn(
17403          'Select2: The `data-select2-tags` attribute has been changed to ' +
17404          'use the `data-data` and `data-tags="true"` attributes and will be ' +
17405          'removed in future versions of Select2.'
17406        );
17407      }
17408
17409      $e.data('data', $e.data('select2Tags'));
17410      $e.data('tags', true);
17411    }
17412
17413    if ($e.data('ajaxUrl')) {
17414      if (this.options.debug && window.console && console.warn) {
17415        console.warn(
17416          'Select2: The `data-ajax-url` attribute has been changed to ' +
17417          '`data-ajax--url` and support for the old attribute will be removed' +
17418          ' in future versions of Select2.'
17419        );
17420      }
17421
17422      $e.attr('ajax--url', $e.data('ajaxUrl'));
17423      $e.data('ajax--url', $e.data('ajaxUrl'));
17424    }
17425
17426    var dataset = {};
17427
17428    // Prefer the element's `dataset` attribute if it exists
17429    // jQuery 1.x does not correctly handle data attributes with multiple dashes
17430    if ($.fn.jquery && $.fn.jquery.substr(0, 2) == '1.' && $e[0].dataset) {
17431      dataset = $.extend(true, {}, $e[0].dataset, $e.data());
17432    } else {
17433      dataset = $e.data();
17434    }
17435
17436    var data = $.extend(true, {}, dataset);
17437
17438    data = Utils._convertData(data);
17439
17440    for (var key in data) {
17441      if ($.inArray(key, excludedData) > -1) {
17442        continue;
17443      }
17444
17445      if ($.isPlainObject(this.options[key])) {
17446        $.extend(this.options[key], data[key]);
17447      } else {
17448        this.options[key] = data[key];
17449      }
17450    }
17451
17452    return this;
17453  };
17454
17455  Options.prototype.get = function (key) {
17456    return this.options[key];
17457  };
17458
17459  Options.prototype.set = function (key, val) {
17460    this.options[key] = val;
17461  };
17462
17463  return Options;
17464});
17465
17466S2.define('select2/core',[
17467  'jquery',
17468  './options',
17469  './utils',
17470  './keys'
17471], function ($, Options, Utils, KEYS) {
17472  var Select2 = function ($element, options) {
17473    if ($element.data('select2') != null) {
17474      $element.data('select2').destroy();
17475    }
17476
17477    this.$element = $element;
17478
17479    this.id = this._generateId($element);
17480
17481    options = options || {};
17482
17483    this.options = new Options(options, $element);
17484
17485    Select2.__super__.constructor.call(this);
17486
17487    // Set up the tabindex
17488
17489    var tabindex = $element.attr('tabindex') || 0;
17490    $element.data('old-tabindex', tabindex);
17491    $element.attr('tabindex', '-1');
17492
17493    // Set up containers and adapters
17494
17495    var DataAdapter = this.options.get('dataAdapter');
17496    this.dataAdapter = new DataAdapter($element, this.options);
17497
17498    var $container = this.render();
17499
17500    this._placeContainer($container);
17501
17502    var SelectionAdapter = this.options.get('selectionAdapter');
17503    this.selection = new SelectionAdapter($element, this.options);
17504    this.$selection = this.selection.render();
17505
17506    this.selection.position(this.$selection, $container);
17507
17508    var DropdownAdapter = this.options.get('dropdownAdapter');
17509    this.dropdown = new DropdownAdapter($element, this.options);
17510    this.$dropdown = this.dropdown.render();
17511
17512    this.dropdown.position(this.$dropdown, $container);
17513
17514    var ResultsAdapter = this.options.get('resultsAdapter');
17515    this.results = new ResultsAdapter($element, this.options, this.dataAdapter);
17516    this.$results = this.results.render();
17517
17518    this.results.position(this.$results, this.$dropdown);
17519
17520    // Bind events
17521
17522    var self = this;
17523
17524    // Bind the container to all of the adapters
17525    this._bindAdapters();
17526
17527    // Register any DOM event handlers
17528    this._registerDomEvents();
17529
17530    // Register any internal event handlers
17531    this._registerDataEvents();
17532    this._registerSelectionEvents();
17533    this._registerDropdownEvents();
17534    this._registerResultsEvents();
17535    this._registerEvents();
17536
17537    // Set the initial state
17538    this.dataAdapter.current(function (initialData) {
17539      self.trigger('selection:update', {
17540        data: initialData
17541      });
17542    });
17543
17544    // Hide the original select
17545    $element.addClass('select2-hidden-accessible');
17546    $element.attr('aria-hidden', 'true');
17547
17548    // Synchronize any monitored attributes
17549    this._syncAttributes();
17550
17551    $element.data('select2', this);
17552  };
17553
17554  Utils.Extend(Select2, Utils.Observable);
17555
17556  Select2.prototype._generateId = function ($element) {
17557    var id = '';
17558
17559    if ($element.attr('id') != null) {
17560      id = $element.attr('id');
17561    } else if ($element.attr('name') != null) {
17562      id = $element.attr('name') + '-' + Utils.generateChars(2);
17563    } else {
17564      id = Utils.generateChars(4);
17565    }
17566
17567    id = 
vendor: 40,193 bytes, lines 17567-19007
17567'select2-' + id;
17568
17569    return id;
17570  };
17571
17572  Select2.prototype._placeContainer = function ($container) {
17573    $container.insertAfter(this.$element);
17574
17575    var width = this._resolveWidth(this.$element, this.options.get('width'));
17576
17577    if (width != null) {
17578      $container.css('width', width);
17579    }
17580  };
17581
17582  Select2.prototype._resolveWidth = function ($element, method) {
17583    var WIDTH = /^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i;
17584
17585    if (method == 'resolve') {
17586      var styleWidth = this._resolveWidth($element, 'style');
17587
17588      if (styleWidth != null) {
17589        return styleWidth;
17590      }
17591
17592      return this._resolveWidth($element, 'element');
17593    }
17594
17595    if (method == 'element') {
17596      var elementWidth = $element.outerWidth(false);
17597
17598      if (elementWidth <= 0) {
17599        return 'auto';
17600      }
17601
17602      return elementWidth + 'px';
17603    }
17604
17605    if (method == 'style') {
17606      var style = $element.attr('style');
17607
17608      if (typeof(style) !== 'string') {
17609        return null;
17610      }
17611
17612      var attrs = style.split(';');
17613
17614      for (var i = 0, l = attrs.length; i < l; i = i + 1) {
17615        var attr = attrs[i].replace(/\s/g, '');
17616        var matches = attr.match(WIDTH);
17617
17618        if (matches !== null && matches.length >= 1) {
17619          return matches[1];
17620        }
17621      }
17622
17623      return null;
17624    }
17625
17626    return method;
17627  };
17628
17629  Select2.prototype._bindAdapters = function () {
17630    this.dataAdapter.bind(this, this.$container);
17631    this.selection.bind(this, this.$container);
17632
17633    this.dropdown.bind(this, this.$container);
17634    this.results.bind(this, this.$container);
17635  };
17636
17637  Select2.prototype._registerDomEvents = function () {
17638    var self = this;
17639
17640    this.$element.on('change.select2', function () {
17641      self.dataAdapter.current(function (data) {
17642        self.trigger('selection:update', {
17643          data: data
17644        });
17645      });
17646    });
17647
17648    this._sync = Utils.bind(this._syncAttributes, this);
17649
17650    if (this.$element[0].attachEvent) {
17651      this.$element[0].attachEvent('onpropertychange', this._sync);
17652    }
17653
17654    var observer = window.MutationObserver ||
17655      window.WebKitMutationObserver ||
17656      window.MozMutationObserver
17657    ;
17658
17659    if (observer != null) {
17660      this._observer = new observer(function (mutations) {
17661        $.each(mutations, self._sync);
17662      });
17663      this._observer.observe(this.$element[0], {
17664        attributes: true,
17665        subtree: false
17666      });
17667    } else if (this.$element[0].addEventListener) {
17668      this.$element[0].addEventListener('DOMAttrModified', self._sync, false);
17669    }
17670  };
17671
17672  Select2.prototype._registerDataEvents = function () {
17673    var self = this;
17674
17675    this.dataAdapter.on('*', function (name, params) {
17676      self.trigger(name, params);
17677    });
17678  };
17679
17680  Select2.prototype._registerSelectionEvents = function () {
17681    var self = this;
17682    var nonRelayEvents = ['toggle', 'focus'];
17683
17684    this.selection.on('toggle', function () {
17685      self.toggleDropdown();
17686    });
17687
17688    this.selection.on('focus', function (params) {
17689      self.focus(params);
17690    });
17691
17692    this.selection.on('*', function (name, params) {
17693      if ($.inArray(name, nonRelayEvents) !== -1) {
17694        return;
17695      }
17696
17697      self.trigger(name, params);
17698    });
17699  };
17700
17701  Select2.prototype._registerDropdownEvents = function () {
17702    var self = this;
17703
17704    this.dropdown.on('*', function (name, params) {
17705      self.trigger(name, params);
17706    });
17707  };
17708
17709  Select2.prototype._registerResultsEvents = function () {
17710    var self = this;
17711
17712    this.results.on('*', function (name, params) {
17713      self.trigger(name, params);
17714    });
17715  };
17716
17717  Select2.prototype._registerEvents = function () {
17718    var self = this;
17719
17720    this.on('open', function () {
17721      self.$container.addClass('select2-container--open');
17722    });
17723
17724    this.on('close', function () {
17725      self.$container.removeClass('select2-container--open');
17726    });
17727
17728    this.on('enable', function () {
17729      self.$container.removeClass('select2-container--disabled');
17730    });
17731
17732    this.on('disable', function () {
17733      self.$container.addClass('select2-container--disabled');
17734    });
17735
17736    this.on('blur', function () {
17737      self.$container.removeClass('select2-container--focus');
17738    });
17739
17740    this.on('query', function (params) {
17741      if (!self.isOpen()) {
17742        self.trigger('open', {});
17743      }
17744
17745      this.dataAdapter.query(params, function (data) {
17746        self.trigger('results:all', {
17747          data: data,
17748          query: params
17749        });
17750      });
17751    });
17752
17753    this.on('query:append', function (params) {
17754      this.dataAdapter.query(params, function (data) {
17755        self.trigger('results:append', {
17756          data: data,
17757          query: params
17758        });
17759      });
17760    });
17761
17762    this.on('keypress', function (evt) {
17763      var key = evt.which;
17764
17765      if (self.isOpen()) {
17766        if (key === KEYS.ESC || key === KEYS.TAB ||
17767            (key === KEYS.UP && evt.altKey)) {
17768          self.close();
17769
17770          evt.preventDefault();
17771        } else if (key === KEYS.ENTER) {
17772          self.trigger('results:select', {});
17773
17774          evt.preventDefault();
17775        } else if ((key === KEYS.SPACE && evt.ctrlKey)) {
17776          self.trigger('results:toggle', {});
17777
17778          evt.preventDefault();
17779        } else if (key === KEYS.UP) {
17780          self.trigger('results:previous', {});
17781
17782          evt.preventDefault();
17783        } else if (key === KEYS.DOWN) {
17784          self.trigger('results:next', {});
17785
17786          evt.preventDefault();
17787        }
17788      } else {
17789        if (key === KEYS.ENTER || key === KEYS.SPACE ||
17790            (key === KEYS.DOWN && evt.altKey)) {
17791          self.open();
17792
17793          evt.preventDefault();
17794        }
17795      }
17796    });
17797  };
17798
17799  Select2.prototype._syncAttributes = function () {
17800    this.options.set('disabled', this.$element.prop('disabled'));
17801
17802    if (this.options.get('disabled')) {
17803      if (this.isOpen()) {
17804        this.close();
17805      }
17806
17807      this.trigger('disable', {});
17808    } else {
17809      this.trigger('enable', {});
17810    }
17811  };
17812
17813  /**
17814   * Override the trigger method to automatically trigger pre-events when
17815   * there are events that can be prevented.
17816   */
17817  Select2.prototype.trigger = function (name, args) {
17818    var actualTrigger = Select2.__super__.trigger;
17819    var preTriggerMap = {
17820      'open': 'opening',
17821      'close': 'closing',
17822      'select': 'selecting',
17823      'unselect': 'unselecting'
17824    };
17825
17826    if (args === undefined) {
17827      args = {};
17828    }
17829
17830    if (name in preTriggerMap) {
17831      var preTriggerName = preTriggerMap[name];
17832      var preTriggerArgs = {
17833        prevented: false,
17834        name: name,
17835        args: args
17836      };
17837
17838      actualTrigger.call(this, preTriggerName, preTriggerArgs);
17839
17840      if (preTriggerArgs.prevented) {
17841        args.prevented = true;
17842
17843        return;
17844      }
17845    }
17846
17847    actualTrigger.call(this, name, args);
17848  };
17849
17850  Select2.prototype.toggleDropdown = function () {
17851    if (this.options.get('disabled')) {
17852      return;
17853    }
17854
17855    if (this.isOpen()) {
17856      this.close();
17857    } else {
17858      this.open();
17859    }
17860  };
17861
17862  Select2.prototype.open = function () {
17863    if (this.isOpen()) {
17864      return;
17865    }
17866
17867    this.trigger('query', {});
17868  };
17869
17870  Select2.prototype.close = function () {
17871    if (!this.isOpen()) {
17872      return;
17873    }
17874
17875    this.trigger('close', {});
17876  };
17877
17878  Select2.prototype.isOpen = function () {
17879    return this.$container.hasClass('select2-container--open');
17880  };
17881
17882  Select2.prototype.hasFocus = function () {
17883    return this.$container.hasClass('select2-container--focus');
17884  };
17885
17886  Select2.prototype.focus = function (data) {
17887    // No need to re-trigger focus events if we are already focused
17888    if (this.hasFocus()) {
17889      return;
17890    }
17891
17892    this.$container.addClass('select2-container--focus');
17893    this.trigger('focus', {});
17894  };
17895
17896  Select2.prototype.enable = function (args) {
17897    if (this.options.get('debug') && window.console && console.warn) {
17898      console.warn(
17899        'Select2: The `select2("enable")` method has been deprecated and will' +
17900        ' be removed in later Select2 versions. Use $element.prop("disabled")' +
17901        ' instead.'
17902      );
17903    }
17904
17905    if (args == null || args.length === 0) {
17906      args = [true];
17907    }
17908
17909    var disabled = !args[0];
17910
17911    this.$element.prop('disabled', disabled);
17912  };
17913
17914  Select2.prototype.data = function () {
17915    if (this.options.get('debug') &&
17916        arguments.length > 0 && window.console && console.warn) {
17917      console.warn(
17918        'Select2: Data can no longer be set using `select2("data")`. You ' +
17919        'should consider setting the value instead using `$element.val()`.'
17920      );
17921    }
17922
17923    var data = [];
17924
17925    this.dataAdapter.current(function (currentData) {
17926      data = currentData;
17927    });
17928
17929    return data;
17930  };
17931
17932  Select2.prototype.val = function (args) {
17933    if (this.options.get('debug') && window.console && console.warn) {
17934      console.warn(
17935        'Select2: The `select2("val")` method has been deprecated and will be' +
17936        ' removed in later Select2 versions. Use $element.val() instead.'
17937      );
17938    }
17939
17940    if (args == null || args.length === 0) {
17941      return this.$element.val();
17942    }
17943
17944    var newVal = args[0];
17945
17946    if ($.isArray(newVal)) {
17947      newVal = $.map(newVal, function (obj) {
17948        return obj.toString();
17949      });
17950    }
17951
17952    this.$element.val(newVal).trigger('change');
17953  };
17954
17955  Select2.prototype.destroy = function () {
17956    this.$container.remove();
17957
17958    if (this.$element[0].detachEvent) {
17959      this.$element[0].detachEvent('onpropertychange', this._sync);
17960    }
17961
17962    if (this._observer != null) {
17963      this._observer.disconnect();
17964      this._observer = null;
17965    } else if (this.$element[0].removeEventListener) {
17966      this.$element[0]
17967        .removeEventListener('DOMAttrModified', this._sync, false);
17968    }
17969
17970    this._sync = null;
17971
17972    this.$element.off('.select2');
17973    this.$element.attr('tabindex', this.$element.data('old-tabindex'));
17974
17975    this.$element.removeClass('select2-hidden-accessible');
17976    this.$element.attr('aria-hidden', 'false');
17977    this.$element.removeData('select2');
17978
17979    this.dataAdapter.destroy();
17980    this.selection.destroy();
17981    this.dropdown.destroy();
17982    this.results.destroy();
17983
17984    this.dataAdapter = null;
17985    this.selection = null;
17986    this.dropdown = null;
17987    this.results = null;
17988  };
17989
17990  Select2.prototype.render = function () {
17991    var $container = $(
17992      '<span class="select2 select2-container">' +
17993        '<span class="selection"></span>' +
17994        '<span class="dropdown-wrapper" aria-hidden="true"></span>' +
17995      '</span>'
17996    );
17997
17998    $container.attr('dir', this.options.get('dir'));
17999
18000    this.$container = $container;
18001
18002    this.$container.addClass('select2-container--' + this.options.get('theme'));
18003
18004    $container.data('element', this.$element);
18005
18006    return $container;
18007  };
18008
18009  return Select2;
18010});
18011
18012S2.define('select2/compat/utils',[
18013  'jquery'
18014], function ($) {
18015  function syncCssClasses ($dest, $src, adapter) {
18016    var classes, replacements = [], adapted;
18017
18018    classes = $.trim($dest.attr('class'));
18019
18020    if (classes) {
18021      classes = '' + classes; // for IE which returns object
18022
18023      $(classes.split(/\s+/)).each(function () {
18024        // Save all Select2 classes
18025        if (this.indexOf('select2-') === 0) {
18026          replacements.push(this);
18027        }
18028      });
18029    }
18030
18031    classes = $.trim($src.attr('class'));
18032
18033    if (classes) {
18034      classes = '' + classes; // for IE which returns object
18035
18036      $(classes.split(/\s+/)).each(function () {
18037        // Only adapt non-Select2 classes
18038        if (this.indexOf('select2-') !== 0) {
18039          adapted = adapter(this);
18040
18041          if (adapted != null) {
18042            replacements.push(adapted);
18043          }
18044        }
18045      });
18046    }
18047
18048    $dest.attr('class', replacements.join(' '));
18049  }
18050
18051  return {
18052    syncCssClasses: syncCssClasses
18053  };
18054});
18055
18056S2.define('select2/compat/containerCss',[
18057  'jquery',
18058  './utils'
18059], function ($, CompatUtils) {
18060  // No-op CSS adapter that discards all classes by default
18061  function _containerAdapter (clazz) {
18062    return null;
18063  }
18064
18065  function ContainerCSS () { }
18066
18067  ContainerCSS.prototype.render = function (decorated) {
18068    var $container = decorated.call(this);
18069
18070    var containerCssClass = this.options.get('containerCssClass') || '';
18071
18072    if ($.isFunction(containerCssClass)) {
18073      containerCssClass = containerCssClass(this.$element);
18074    }
18075
18076    var containerCssAdapter = this.options.get('adaptContainerCssClass');
18077    containerCssAdapter = containerCssAdapter || _containerAdapter;
18078
18079    if (containerCssClass.indexOf(':all:') !== -1) {
18080      containerCssClass = containerCssClass.replace(':all:', '');
18081
18082      var _cssAdapter = containerCssAdapter;
18083
18084      containerCssAdapter = function (clazz) {
18085        var adapted = _cssAdapter(clazz);
18086
18087        if (adapted != null) {
18088          // Append the old one along with the adapted one
18089          return adapted + ' ' + clazz;
18090        }
18091
18092        return clazz;
18093      };
18094    }
18095
18096    var containerCss = this.options.get('containerCss') || {};
18097
18098    if ($.isFunction(containerCss)) {
18099      containerCss = containerCss(this.$element);
18100    }
18101
18102    CompatUtils.syncCssClasses($container, this.$element, containerCssAdapter);
18103
18104    $container.css(containerCss);
18105    $container.addClass(containerCssClass);
18106
18107    return $container;
18108  };
18109
18110  return ContainerCSS;
18111});
18112
18113S2.define('select2/compat/dropdownCss',[
18114  'jquery',
18115  './utils'
18116], function ($, CompatUtils) {
18117  // No-op CSS adapter that discards all classes by default
18118  function _dropdownAdapter (clazz) {
18119    return null;
18120  }
18121
18122  function DropdownCSS () { }
18123
18124  DropdownCSS.prototype.render = function (decorated) {
18125    var $dropdown = decorated.call(this);
18126
18127    var dropdownCssClass = this.options.get('dropdownCssClass') || '';
18128
18129    if ($.isFunction(dropdownCssClass)) {
18130      dropdownCssClass = dropdownCssClass(this.$element);
18131    }
18132
18133    var dropdownCssAdapter = this.options.get('adaptDropdownCssClass');
18134    dropdownCssAdapter = dropdownCssAdapter || _dropdownAdapter;
18135
18136    if (dropdownCssClass.indexOf(':all:') !== -1) {
18137      dropdownCssClass = dropdownCssClass.replace(':all:', '');
18138
18139      var _cssAdapter = dropdownCssAdapter;
18140
18141      dropdownCssAdapter = function (clazz) {
18142        var adapted = _cssAdapter(clazz);
18143
18144        if (adapted != null) {
18145          // Append the old one along with the adapted one
18146          return adapted + ' ' + clazz;
18147        }
18148
18149        return clazz;
18150      };
18151    }
18152
18153    var dropdownCss = this.options.get('dropdownCss') || {};
18154
18155    if ($.isFunction(dropdownCss)) {
18156      dropdownCss = dropdownCss(this.$element);
18157    }
18158
18159    CompatUtils.syncCssClasses($dropdown, this.$element, dropdownCssAdapter);
18160
18161    $dropdown.css(dropdownCss);
18162    $dropdown.addClass(dropdownCssClass);
18163
18164    return $dropdown;
18165  };
18166
18167  return DropdownCSS;
18168});
18169
18170S2.define('select2/compat/initSelection',[
18171  'jquery'
18172], function ($) {
18173  function InitSelection (decorated, $element, options) {
18174    if (options.get('debug') && window.console && console.warn) {
18175      console.warn(
18176        'Select2: The `initSelection` option has been deprecated in favor' +
18177        ' of a custom data adapter that overrides the `current` method. ' +
18178        'This method is now called multiple times instead of a single ' +
18179        'time when the instance is initialized. Support will be removed ' +
18180        'for the `initSelection` option in future versions of Select2'
18181      );
18182    }
18183
18184    this.initSelection = options.get('initSelection');
18185    this._isInitialized = false;
18186
18187    decorated.call(this, $element, options);
18188  }
18189
18190  InitSelection.prototype.current = function (decorated, callback) {
18191    var self = this;
18192
18193    if (this._isInitialized) {
18194      decorated.call(this, callback);
18195
18196      return;
18197    }
18198
18199    this.initSelection.call(null, this.$element, function (data) {
18200      self._isInitialized = true;
18201
18202      if (!$.isArray(data)) {
18203        data = [data];
18204      }
18205
18206      callback(data);
18207    });
18208  };
18209
18210  return InitSelection;
18211});
18212
18213S2.define('select2/compat/inputData',[
18214  'jquery'
18215], function ($) {
18216  function InputData (decorated, $element, options) {
18217    this._currentData = [];
18218    this._valueSeparator = options.get('valueSeparator') || ',';
18219
18220    if ($element.prop('type') === 'hidden') {
18221      if (options.get('debug') && console && console.warn) {
18222        console.warn(
18223          'Select2: Using a hidden input with Select2 is no longer ' +
18224          'supported and may stop working in the future. It is recommended ' +
18225          'to use a `<select>` element instead.'
18226        );
18227      }
18228    }
18229
18230    decorated.call(this, $element, options);
18231  }
18232
18233  InputData.prototype.current = function (_, callback) {
18234    function getSelected (data, selectedIds) {
18235      var selected = [];
18236
18237      if (data.selected || $.inArray(data.id, selectedIds) !== -1) {
18238        data.selected = true;
18239        selected.push(data);
18240      } else {
18241        data.selected = false;
18242      }
18243
18244      if (data.children) {
18245        selected.push.apply(selected, getSelected(data.children, selectedIds));
18246      }
18247
18248      return selected;
18249    }
18250
18251    var selected = [];
18252
18253    for (var d = 0; d < this._currentData.length; d++) {
18254      var data = this._currentData[d];
18255
18256      selected.push.apply(
18257        selected,
18258        getSelected(
18259          data,
18260          this.$element.val().split(
18261            this._valueSeparator
18262          )
18263        )
18264      );
18265    }
18266
18267    callback(selected);
18268  };
18269
18270  InputData.prototype.select = function (_, data) {
18271    if (!this.options.get('multiple')) {
18272      this.current(function (allData) {
18273        $.map(allData, function (data) {
18274          data.selected = false;
18275        });
18276      });
18277
18278      this.$element.val(data.id);
18279      this.$element.trigger('change');
18280    } else {
18281      var value = this.$element.val();
18282      value += this._valueSeparator + data.id;
18283
18284      this.$element.val(value);
18285      this.$element.trigger('change');
18286    }
18287  };
18288
18289  InputData.prototype.unselect = function (_, data) {
18290    var self = this;
18291
18292    data.selected = false;
18293
18294    this.current(function (allData) {
18295      var values = [];
18296
18297      for (var d = 0; d < allData.length; d++) {
18298        var item = allData[d];
18299
18300        if (data.id == item.id) {
18301          continue;
18302        }
18303
18304        values.push(item.id);
18305      }
18306
18307      self.$element.val(values.join(self._valueSeparator));
18308      self.$element.trigger('change');
18309    });
18310  };
18311
18312  InputData.prototype.query = function (_, params, callback) {
18313    var results = [];
18314
18315    for (var d = 0; d < this._currentData.length; d++) {
18316      var data = this._currentData[d];
18317
18318      var matches = this.matches(params, data);
18319
18320      if (matches !== null) {
18321        results.push(matches);
18322      }
18323    }
18324
18325    callback({
18326      results: results
18327    });
18328  };
18329
18330  InputData.prototype.addOptions = function (_, $options) {
18331    var options = $.map($options, function ($option) {
18332      return $.data($option[0], 'data');
18333    });
18334
18335    this._currentData.push.apply(this._currentData, options);
18336  };
18337
18338  return InputData;
18339});
18340
18341S2.define('select2/compat/matcher',[
18342  'jquery'
18343], function ($) {
18344  function oldMatcher (matcher) {
18345    function wrappedMatcher (params, data) {
18346      var match = $.extend(true, {}, data);
18347
18348      if (params.term == null || $.trim(params.term) === '') {
18349        return match;
18350      }
18351
18352      if (data.children) {
18353        for (var c = data.children.length - 1; c >= 0; c--) {
18354          var child = data.children[c];
18355
18356          // Check if the child object matches
18357          // The old matcher returned a boolean true or false
18358          var doesMatch = matcher(params.term, child.text, child);
18359
18360          // If the child didn't match, pop it off
18361          if (!doesMatch) {
18362            match.children.splice(c, 1);
18363          }
18364        }
18365
18366        if (match.children.length > 0) {
18367          return match;
18368        }
18369      }
18370
18371      if (matcher(params.term, data.text, data)) {
18372        return match;
18373      }
18374
18375      return null;
18376    }
18377
18378    return wrappedMatcher;
18379  }
18380
18381  return oldMatcher;
18382});
18383
18384S2.define('select2/compat/query',[
18385
18386], function () {
18387  function Query (decorated, $element, options) {
18388    if (options.get('debug') && window.console && console.warn) {
18389      console.warn(
18390        'Select2: The `query` option has been deprecated in favor of a ' +
18391        'custom data adapter that overrides the `query` method. Support ' +
18392        'will be removed for the `query` option in future versions of ' +
18393        'Select2.'
18394      );
18395    }
18396
18397    decorated.call(this, $element, options);
18398  }
18399
18400  Query.prototype.query = function (_, params, callback) {
18401    params.callback = callback;
18402
18403    var query = this.options.get('query');
18404
18405    query.call(null, params);
18406  };
18407
18408  return Query;
18409});
18410
18411S2.define('select2/dropdown/attachContainer',[
18412
18413], function () {
18414  function AttachContainer (decorated, $element, options) {
18415    decorated.call(this, $element, options);
18416  }
18417
18418  AttachContainer.prototype.position =
18419    function (decorated, $dropdown, $container) {
18420    var $dropdownContainer = $container.find('.dropdown-wrapper');
18421    $dropdownContainer.append($dropdown);
18422
18423    $dropdown.addClass('select2-dropdown--below');
18424    $container.addClass('select2-container--below');
18425  };
18426
18427  return AttachContainer;
18428});
18429
18430S2.define('select2/dropdown/stopPropagation',[
18431
18432], function () {
18433  function StopPropagation () { }
18434
18435  StopPropagation.prototype.bind = function (decorated, container, $container) {
18436    decorated.call(this, container, $container);
18437
18438    var stoppedEvents = [
18439    'blur',
18440    'change',
18441    'click',
18442    'dblclick',
18443    'focus',
18444    'focusin',
18445    'focusout',
18446    'input',
18447    'keydown',
18448    'keyup',
18449    'keypress',
18450    'mousedown',
18451    'mouseenter',
18452    'mouseleave',
18453    'mousemove',
18454    'mouseover',
18455    'mouseup',
18456    'search',
18457    'touchend',
18458    'touchstart'
18459    ];
18460
18461    this.$dropdown.on(stoppedEvents.join(' '), function (evt) {
18462      evt.stopPropagation();
18463    });
18464  };
18465
18466  return StopPropagation;
18467});
18468
18469S2.define('select2/selection/stopPropagation',[
18470
18471], function () {
18472  function StopPropagation () { }
18473
18474  StopPropagation.prototype.bind = function (decorated, container, $container) {
18475    decorated.call(this, container, $container);
18476
18477    var stoppedEvents = [
18478      'blur',
18479      'change',
18480      'click',
18481      'dblclick',
18482      'focus',
18483      'focusin',
18484      'focusout',
18485      'input',
18486      'keydown',
18487      'keyup',
18488      'keypress',
18489      'mousedown',
18490      'mouseenter',
18491      'mouseleave',
18492      'mousemove',
18493      'mouseover',
18494      'mouseup',
18495      'search',
18496      'touchend',
18497      'touchstart'
18498    ];
18499
18500    this.$selection.on(stoppedEvents.join(' '), function (evt) {
18501      evt.stopPropagation();
18502    });
18503  };
18504
18505  return StopPropagation;
18506});
18507
18508/*!
18509 * jQuery Mousewheel 3.1.13
18510 *
18511 * Copyright jQuery Foundation and other contributors
18512 * Released under the MIT license
18513 * http://jquery.org/license
18514 */
18515
18516(function (factory) {
18517    if ( typeof S2.define === 'function' && S2.define.amd ) {
18518        // AMD. Register as an anonymous module.
18519        S2.define('jquery-mousewheel',['jquery'], factory);
18520    } else if (typeof exports === 'object') {
18521        // Node/CommonJS style for Browserify
18522        module.exports = factory;
18523    } else {
18524        // Browser globals
18525        factory(jQuery);
18526    }
18527}(function ($) {
18528
18529    var toFix  = ['wheel', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll'],
18530        toBind = ( 'onwheel' in document || document.documentMode >= 9 ) ?
18531                    ['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'],
18532        slice  = Array.prototype.slice,
18533        nullLowestDeltaTimeout, lowestDelta;
18534
18535    if ( $.event.fixHooks ) {
18536        for ( var i = toFix.length; i; ) {
18537            $.event.fixHooks[ toFix[--i] ] = $.event.mouseHooks;
18538        }
18539    }
18540
18541    var special = $.event.special.mousewheel = {
18542        version: '3.1.12',
18543
18544        setup: function() {
18545            if ( this.addEventListener ) {
18546                for ( var i = toBind.length; i; ) {
18547                    this.addEventListener( toBind[--i], handler, false );
18548                }
18549            } else {
18550                this.onmousewheel = handler;
18551            }
18552            // Store the line height and page height for this particular element
18553            $.data(this, 'mousewheel-line-height', special.getLineHeight(this));
18554            $.data(this, 'mousewheel-page-height', special.getPageHeight(this));
18555        },
18556
18557        teardown: function() {
18558            if ( this.removeEventListener ) {
18559                for ( var i = toBind.length; i; ) {
18560                    this.removeEventListener( toBind[--i], handler, false );
18561                }
18562            } else {
18563                this.onmousewheel = null;
18564            }
18565            // Clean up the data we added to the element
18566            $.removeData(this, 'mousewheel-line-height');
18567            $.removeData(this, 'mousewheel-page-height');
18568        },
18569
18570        getLineHeight: function(elem) {
18571            var $elem = $(elem),
18572                $parent = $elem['offsetParent' in $.fn ? 'offsetParent' : 'parent']();
18573            if (!$parent.length) {
18574                $parent = $('body');
18575            }
18576            return parseInt($parent.css('fontSize'), 10) || parseInt($elem.css('fontSize'), 10) || 16;
18577        },
18578
18579        getPageHeight: function(elem) {
18580            return $(elem).height();
18581        },
18582
18583        settings: {
18584            adjustOldDeltas: true, // see shouldAdjustOldDeltas() below
18585            normalizeOffset: true  // calls getBoundingClientRect for each event
18586        }
18587    };
18588
18589    $.fn.extend({
18590        // mousewheel: function(fn) {
18591        //     return fn ? this.bind('mousewheel', fn) : this.trigger('mousewheel');
18592        // },
18593        //
18594        // unmousewheel: function(fn) {
18595        //     return this.unbind('mousewheel', fn);
18596        // }
18597    });
18598
18599
18600    function handler(event) {
18601        var orgEvent   = event || window.event,
18602            args       = slice.call(arguments, 1),
18603            delta      = 0,
18604            deltaX     = 0,
18605            deltaY     = 0,
18606            absDelta   = 0,
18607            offsetX    = 0,
18608            offsetY    = 0;
18609        event = $.event.fix(orgEvent);
18610        event.type = 'mousewheel';
18611
18612        // Old school scrollwheel delta
18613        if ( 'detail'      in orgEvent ) { deltaY = orgEvent.detail * -1;      }
18614        if ( 'wheelDelta'  in orgEvent ) { deltaY = orgEvent.wheelDelta;       }
18615        if ( 'wheelDeltaY' in orgEvent ) { deltaY = orgEvent.wheelDeltaY;      }
18616        if ( 'wheelDeltaX' in orgEvent ) { deltaX = orgEvent.wheelDeltaX * -1; }
18617
18618        // Firefox < 17 horizontal scrolling related to DOMMouseScroll event
18619        if ( 'axis' in orgEvent && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) {
18620            deltaX = deltaY * -1;
18621            deltaY = 0;
18622        }
18623
18624        // Set delta to be deltaY or deltaX if deltaY is 0 for backwards compatabilitiy
18625        delta = deltaY === 0 ? deltaX : deltaY;
18626
18627        // New school wheel delta (wheel event)
18628        if ( 'deltaY' in orgEvent ) {
18629            deltaY = orgEvent.deltaY * -1;
18630            delta  = deltaY;
18631        }
18632        if ( 'deltaX' in orgEvent ) {
18633            deltaX = orgEvent.deltaX;
18634            if ( deltaY === 0 ) { delta  = deltaX * -1; }
18635        }
18636
18637        // No change actually happened, no reason to go any further
18638        if ( deltaY === 0 && deltaX === 0 ) { return; }
18639
18640        // Need to convert lines and pages to pixels if we aren't already in pixels
18641        // There are three delta modes:
18642        //   * deltaMode 0 is by pixels, nothing to do
18643        //   * deltaMode 1 is by lines
18644        //   * deltaMode 2 is by pages
18645        if ( orgEvent.deltaMode === 1 ) {
18646            var lineHeight = $.data(this, 'mousewheel-line-height');
18647            delta  *= lineHeight;
18648            deltaY *= lineHeight;
18649            deltaX *= lineHeight;
18650        } else if ( orgEvent.deltaMode === 2 ) {
18651            var pageHeight = $.data(this, 'mousewheel-page-height');
18652            delta  *= pageHeight;
18653            deltaY *= pageHeight;
18654            deltaX *= pageHeight;
18655        }
18656
18657        // Store lowest absolute delta to normalize the delta values
18658        absDelta = Math.max( Math.abs(deltaY), Math.abs(deltaX) );
18659
18660        if ( !lowestDelta || absDelta < lowestDelta ) {
18661            lowestDelta = absDelta;
18662
18663            // Adjust older deltas if necessary
18664            if ( shouldAdjustOldDeltas(orgEvent, absDelta) ) {
18665                lowestDelta /= 40;
18666            }
18667        }
18668
18669        // Adjust older deltas if necessary
18670        if ( shouldAdjustOldDeltas(orgEvent, absDelta) ) {
18671            // Divide all the things by 40!
18672            delta  /= 40;
18673            deltaX /= 40;
18674            deltaY /= 40;
18675        }
18676
18677        // Get a whole, normalized value for the deltas
18678        delta  = Math[ delta  >= 1 ? 'floor' : 'ceil' ](delta  / lowestDelta);
18679        deltaX = Math[ deltaX >= 1 ? 'floor' : 'ceil' ](deltaX / lowestDelta);
18680        deltaY = Math[ deltaY >= 1 ? 'floor' : 'ceil' ](deltaY / lowestDelta);
18681
18682        // Normalise offsetX and offsetY properties
18683        if ( special.settings.normalizeOffset && this.getBoundingClientRect ) {
18684            var boundingRect = this.getBoundingClientRect();
18685            offsetX = event.clientX - boundingRect.left;
18686            offsetY = event.clientY - boundingRect.top;
18687        }
18688
18689        // Add information to the event object
18690        event.deltaX = deltaX;
18691        event.deltaY = deltaY;
18692        event.deltaFactor = lowestDelta;
18693        event.offsetX = offsetX;
18694        event.offsetY = offsetY;
18695        // Go ahead and set deltaMode to 0 since we converted to pixels
18696        // Although this is a little odd since we overwrite the deltaX/Y
18697        // properties with normalized deltas.
18698        event.deltaMode = 0;
18699
18700        // Add event and delta to the front of the arguments
18701        args.unshift(event, delta, deltaX, deltaY);
18702
18703        // Clearout lowestDelta after sometime to better
18704        // handle multiple device types that give different
18705        // a different lowestDelta
18706        // Ex: trackpad = 3 and mouse wheel = 120
18707        if (nullLowestDeltaTimeout) { clearTimeout(nullLowestDeltaTimeout); }
18708        nullLowestDeltaTimeout = setTimeout(nullLowestDelta, 200);
18709
18710        return ($.event.dispatch || $.event.handle).apply(this, args);
18711    }
18712
18713    function nullLowestDelta() {
18714        lowestDelta = null;
18715    }
18716
18717    function shouldAdjustOldDeltas(orgEvent, absDelta) {
18718        // If this is an older event and the delta is divisable by 120,
18719        // then we are assuming that the browser is treating this as an
18720        // older mouse wheel event and that we should divide the deltas
18721        // by 40 to try and get a more usable deltaFactor.
18722        // Side note, this actually impacts the reported scroll distance
18723        // in older browsers and can cause scrolling to be slower than native.
18724        // Turn this off by setting $.event.special.mousewheel.settings.adjustOldDeltas to false.
18725        return special.settings.adjustOldDeltas && orgEvent.type === 'mousewheel' && absDelta % 120 === 0;
18726    }
18727
18728}));
18729
18730S2.define('jquery.select2',[
18731  'jquery',
18732  'jquery-mousewheel',
18733
18734  './select2/core',
18735  './select2/defaults'
18736], function ($, _, Select2, Defaults) {
18737  if ($.fn.select2 == null) {
18738    // All methods that should return the element
18739    var thisMethods = ['open', 'close', 'destroy'];
18740
18741    $.fn.select2 = function (options) {
18742      options = options || {};
18743
18744      if (typeof options === 'object') {
18745        this.each(function () {
18746          var instanceOptions = $.extend(true, {}, options);
18747
18748          var instance = new Select2($(this), instanceOptions);
18749        });
18750
18751        return this;
18752      } else if (typeof options === 'string') {
18753        var ret;
18754
18755        this.each(function () {
18756          var instance = $(this).data('select2');
18757
18758          if (instance == null && window.console && console.error) {
18759            console.error(
18760              'The select2(\'' + options + '\') method was called on an ' +
18761              'element that is not using Select2.'
18762            );
18763          }
18764
18765          var args = Array.prototype.slice.call(arguments, 1);
18766
18767          ret = instance[options].apply(instance, args);
18768        });
18769
18770        // Check if we should be returning `this`
18771        if ($.inArray(options, thisMethods) > -1) {
18772          return this;
18773        }
18774
18775        return ret;
18776      } else {
18777        throw new Error('Invalid arguments for Select2: ' + options);
18778      }
18779    };
18780  }
18781
18782  if ($.fn.select2.defaults == null) {
18783    $.fn.select2.defaults = Defaults;
18784  }
18785
18786  return Select2;
18787});
18788
18789  // Return the AMD loader configuration so it can be used outside of this file
18790  return {
18791    define: S2.define,
18792    require: S2.require
18793  };
18794}());
18795
18796  // Autoload the jQuery bindings
18797  // We know that all of the modules exist above this, so we're safe
18798  var select2 = S2.require('jquery.select2');
18799
18800  // Hold the AMD module references on the jQuery function that was just loaded
18801  // This allows Select2 to use the internal loader outside of this file, such
18802  // as in the language files.
18803  jQuery.fn.select2.amd = S2;
18804
18805  // Return the Select2 instance for anyone who is importing it.
18806  return select2;
18807}));
18808
18809/*!
18810 * jQuery Mousewheel 3.1.13
18811 *
18812 * Copyright jQuery Foundation and other contributors
18813 * Released under the MIT license
18814 * http://jquery.org/license
18815 */
18816
18817(function (factory) {
18818    if ( typeof define === 'function' && define.amd ) {
18819        // AMD. Register as an anonymous module.
18820        define(['jquery'], factory);
18821    } else if (typeof exports === 'object') {
18822        // Node/CommonJS style for Browserify
18823        module.exports = factory;
18824    } else {
18825        // Browser globals
18826        factory(jQuery);
18827    }
18828}(function ($) {
18829
18830    var toFix  = ['wheel', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll'],
18831        toBind = ( 'onwheel' in document || document.documentMode >= 9 ) ?
18832                    ['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'],
18833        slice  = Array.prototype.slice,
18834        nullLowestDeltaTimeout, lowestDelta;
18835
18836    if ( $.event.fixHooks ) {
18837        for ( var i = toFix.length; i; ) {
18838            $.event.fixHooks[ toFix[--i] ] = $.event.mouseHooks;
18839        }
18840    }
18841
18842    var special = $.event.special.mousewheel = {
18843        version: '3.1.12',
18844
18845        setup: function() {
18846            if ( this.addEventListener ) {
18847                for ( var i = toBind.length; i; ) {
18848                    this.addEventListener( toBind[--i], handler, false );
18849                }
18850            } else {
18851                this.onmousewheel = handler;
18852            }
18853            // Store the line height and page height for this particular element
18854            $.data(this, 'mousewheel-line-height', special.getLineHeight(this));
18855            $.data(this, 'mousewheel-page-height', special.getPageHeight(this));
18856        },
18857
18858        teardown: function() {
18859            if ( this.removeEventListener ) {
18860                for ( var i = toBind.length; i; ) {
18861                    this.removeEventListener( toBind[--i], handler, false );
18862                }
18863            } else {
18864                this.onmousewheel = null;
18865            }
18866            // Clean up the data we added to the element
18867            $.removeData(this, 'mousewheel-line-height');
18868            $.removeData(this, 'mousewheel-page-height');
18869        },
18870
18871        getLineHeight: function(elem) {
18872            var $elem = $(elem),
18873                $parent = $elem['offsetParent' in $.fn ? 'offsetParent' : 'parent']();
18874            if (!$parent.length) {
18875                $parent = $('body');
18876            }
18877            return parseInt($parent.css('fontSize'), 10) || parseInt($elem.css('fontSize'), 10) || 16;
18878        },
18879
18880        getPageHeight: function(elem) {
18881            return $(elem).height();
18882        },
18883
18884        settings: {
18885            adjustOldDeltas: true, // see shouldAdjustOldDeltas() below
18886            normalizeOffset: true  // calls getBoundingClientRect for each event
18887        }
18888    };
18889
18890    $.fn.extend({
18891        mousewheel: function(fn) {
18892            return fn ? this.bind('mousewheel', fn) : this.trigger('mousewheel');
18893        },
18894
18895        unmousewheel: function(fn) {
18896            return this.unbind('mousewheel', fn);
18897        }
18898    });
18899
18900
18901    function handler(event) {
18902        var orgEvent   = event || window.event,
18903            args       = slice.call(arguments, 1),
18904            delta      = 0,
18905            deltaX     = 0,
18906            deltaY     = 0,
18907            absDelta   = 0,
18908            offsetX    = 0,
18909            offsetY    = 0;
18910        event = $.event.fix(orgEvent);
18911        event.type = 'mousewheel';
18912
18913        // Old school scrollwheel delta
18914        if ( 'detail'      in orgEvent ) { deltaY = orgEvent.detail * -1;      }
18915        if ( 'wheelDelta'  in orgEvent ) { deltaY = orgEvent.wheelDelta;       }
18916        if ( 'wheelDeltaY' in orgEvent ) { deltaY = orgEvent.wheelDeltaY;      }
18917        if ( 'wheelDeltaX' in orgEvent ) { deltaX = orgEvent.wheelDeltaX * -1; }
18918
18919        // Firefox < 17 horizontal scrolling related to DOMMouseScroll event
18920        if ( 'axis' in orgEvent && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) {
18921            deltaX = deltaY * -1;
18922            deltaY = 0;
18923        }
18924
18925        // Set delta to be deltaY or deltaX if deltaY is 0 for backwards compatabilitiy
18926        delta = deltaY === 0 ? deltaX : deltaY;
18927
18928        // New school wheel delta (wheel event)
18929        if ( 'deltaY' in orgEvent ) {
18930            deltaY = orgEvent.deltaY * -1;
18931            delta  = deltaY;
18932        }
18933        if ( 'deltaX' in orgEvent ) {
18934            deltaX = orgEvent.deltaX;
18935            if ( deltaY === 0 ) { delta  = deltaX * -1; }
18936        }
18937
18938        // No change actually happened, no reason to go any further
18939        if ( deltaY === 0 && deltaX === 0 ) { return; }
18940
18941        // Need to convert lines and pages to pixels if we aren't already in pixels
18942        // There are three delta modes:
18943        //   * deltaMode 0 is by pixels, nothing to do
18944        //   * deltaMode 1 is by lines
18945        //   * deltaMode 2 is by pages
18946        if ( orgEvent.deltaMode === 1 ) {
18947            var lineHeight = $.data(this, 'mousewheel-line-height');
18948            delta  *= lineHeight;
18949            deltaY *= lineHeight;
18950            deltaX *= lineHeight;
18951        } else if ( orgEvent.deltaMode === 2 ) {
18952            var pageHeight = $.data(this, 'mousewheel-page-height');
18953            delta  *= pageHeight;
18954            deltaY *= pageHeight;
18955            deltaX *= pageHeight;
18956        }
18957
18958        // Store lowest absolute delta to normalize the delta values
18959        absDelta = Math.max( Math.abs(deltaY), Math.abs(deltaX) );
18960
18961        if ( !lowestDelta || absDelta < lowestDelta ) {
18962            lowestDelta = absDelta;
18963
18964            // Adjust older deltas if necessary
18965            if ( shouldAdjustOldDeltas(orgEvent, absDelta) ) {
18966                lowestDelta /= 40;
18967            }
18968        }
18969
18970        // Adjust older deltas if necessary
18971        if ( shouldAdjustOldDeltas(orgEvent, absDelta) ) {
18972            // Divide all the things by 40!
18973            delta  /= 40;
18974            deltaX /= 40;
18975            deltaY /= 40;
18976        }
18977
18978        // Get a whole, normalized value for the deltas
18979        delta  = Math[ delta  >= 1 ? 'floor' : 'ceil' ](delta  / lowestDelta);
18980        deltaX = Math[ deltaX >= 1 ? 'floor' : 'ceil' ](deltaX / lowestDelta);
18981        deltaY = Math[ deltaY >= 1 ? 'floor' : 'ceil' ](deltaY / lowestDelta);
18982
18983        // Normalise offsetX and offsetY properties
18984        if ( special.settings.normalizeOffset && this.getBoundingClientRect ) {
18985            var boundingRect = this.getBoundingClientRect();
18986            offsetX = event.clientX - boundingRect.left;
18987            offsetY = event.clientY - boundingRect.top;
18988        }
18989
18990        // Add information to the event object
18991        event.deltaX = deltaX;
18992        event.deltaY = deltaY;
18993        event.deltaFactor = lowestDelta;
18994        event.offsetX = offsetX;
18995        event.offsetY = offsetY;
18996        // Go ahead and set deltaMode to 0 since we converted to pixels
18997        // Although this is a little odd since we overwrite the deltaX/Y
18998        // properties with normalized deltas.
18999        event.deltaMode = 0;
19000
19001        // Add event and delta to the front of the arguments
19002        args.unshift(event, delta, deltaX, deltaY);
19003
19004        // Clearout lowestDelta after sometime to better
19005        // handle multiple device types that give different
19006        // a different lowestDelta
19007        // Ex: trackpad = 3 and mouse wheel = 120
19008        if (nullLowestDeltaTimeout) { clearTimeout(nullLowestDeltaTimeout); }
19009        nullLowestDeltaTimeout = setTimeout(nullLowestDelta, 200);
19010
19011        return ($.event.dispatch || $.event.handle).apply(this, args);
19012    }
19013
19014    function nullLowestDelta() {
19015        lowestDelta = null;
19016    }
19017
19018    function shouldAdjustOldDeltas(orgEvent, absDelta) {
19019        // If this is an older event and the delta is divisable by 120,
19020        // then we are assuming that the browser is treating this as an
19021        // older mouse wheel event and that we should divide the deltas
19022        // by 40 to try and get a more usable deltaFactor.
19023        // Side note, this actually impacts the reported scroll distance
19024        // in older browsers and can cause scrolling to be slower than native.
19025        // Turn this off by setting $.event.special.mousewheel.settings.adjustOldDeltas to false.
19026        return special.settings.adjustOldDeltas && orgEvent.type === 'mousewheel' && absDelta % 120 === 0;
19027    }
19028
19029}));
19030
19031/* jquery.nicescroll
19032-- version 3.6.6
19033-- copyright 2015-11-17 InuYaksa*2015
19034-- licensed under the MIT
19035--
19036-- http://nicescroll.areaaperta.com/
19037-- https://github.com/inuyaksa/jquery.nicescroll
19038--
19039*/
19040
19041(function(factory) {
19042  if (typeof define === 'function' && define.amd) {
19043    // AMD. Register as anonymous module.
19044    define(['jquery'], factory);
19045  } else if (typeof exports === 'object') {
19046    // Node/CommonJS.
19047    module.exports = factory(require('jquery'));
19048  } else {
19049    // Browser globals.
19050    factory(jQuery);
19051  }
19052}(function(jQuery) {
19053  "use strict";
19054
19055  // globals
19056  var domfocus = false;
19057  var mousefocus = false;
19058  var tabindexcounter = 0;
19059  var ascrailcounter = 2000;
19060  var globalmaxzindex = 0;
19061
19062  var $ = jQuery; // sandbox
19063
19064  // http://stackoverflow.com/questions/2161159/get-script-path
19065  function getScriptPath() {
19066    var scripts = document.getElementsByTagName('script');
19067    var path = scripts.length ? scripts[scripts.length - 1].src.split('?')[0] : '';
19068    return (path.split('/').length > 0) ? path.split('/').slice(0, -1).join('/') + '/' : '';
19069  }
19070
19071  var vendors = ['webkit','ms','moz','o'];
19072
19073  var setAnimationFrame = window.requestAnimationFrame || false;
19074  var clearAnimationFrame = window.cancelAnimationFrame || false;
19075
19076  if (!setAnimationFrame) {  // legacy detection
19077    for (var vx in vendors) {
19078      var v = vendors[vx];
19079      if (!setAnimationFrame) setAnimationFrame = window[v + 'RequestAnimationFrame'];
19080      if (!clearAnimationFrame) clearAnimationFrame = window[v + 'CancelAnimationFrame'] || window[v + 'CancelRequestAnimationFrame'];
19081    }
19082  }
19083
19084  var ClsMutationObserver = window.MutationObserver || window.WebKitMutationObserver || false;
19085
19086  var _globaloptions = {
19087    zindex: "auto",
19088    cursoropacitymin: 0,
19089    cursoropacitymax: 1,
19090    cursorcolor: "#424242",
19091    cursorwidth: "5px",
19092    cursorborder: "1px solid #fff",
19093    cursorborderradius: "5px",
19094    scrollspeed: 60,
19095    mousescrollstep: 8 * 3,
19096    touchbehavior: false,
19097    hwacceleration: true,
19098    usetransition: true,
19099    boxzoom: false,
19100    dblclickzoom: true,
19101    gesturezoom: true,
19102    grabcursorenabled: true,
19103    autohidemode: true,
19104    background: "",
19105    iframeautoresize: true,
19106    cursorminheight: 32,
19107    preservenativescrolling: true,
19108    railoffset: false,
19109    railhoffset: false,
19110    bouncescroll: true,
19111    spacebarenabled: true,
19112    railpadding: {
19113      top: 0,
19114      right: 0,
19115      left: 0,
19116      bottom: 0
19117    },
19118    disableoutline: true,
19119    horizrailenabled: true,
19120    railalign: "right",
19121    railvalign: "bottom",
19122    enabletranslate3d: true,
19123    enablemousewheel: true,
19124    enablekeyboard: true,
19125    smoothscroll: true,
19126    sensitiverail: true,
19127    enablemouselockapi: true,
19128    //      cursormaxheight:false,
19129    cursorfixedheight: false,
19130    directionlockdeadzone: 6,
19131    hidecursordelay: 400,
19132    nativeparentscrolling: true,
19133    enablescrollonselection: true,
19134    overflowx: true,
19135    overflowy: true,
19136    cursordragspeed: 0.3,
19137    rtlmode: "auto",
19138    cursordragontouch: false,
19139    oneaxismousemode: "auto",
19140    scriptpath: getScriptPath(),
19141    preventmultitouchscrolling: true
19142  };
19143
19144  var browserdetected = false;
19145
19146  var getBrowserDetection = function() {
19147
19148    if (browserdetected) return browserdetected;
19149
19150    var _el = document.createElement('DIV'),
19151        _style = _el.style,
19152        _agent = navigator.userAgent,
19153        _platform = navigator.platform,
19154        d = {};
19155
19156    d.haspointerlock = "pointerLockElement" in document || "webkitPointerLockElement" in document || "mozPointerLockElement" in document;
19157
19158    d.isopera = ("opera" in window); // 12-
19159    d.isopera12 = (d.isopera && ("getUserMedia" in navigator));
19160    d.isoperamini = (Object.prototype.toString.call(window.operamini) === "[object OperaMini]");
19161
19162    d.isie = (("all" in document) && ("attachEvent" in _el) && !d.isopera); //IE10-
19163    d.isieold = (d.isie && !("msInterpolationMode" in _style)); // IE6 and older
19164    d.isie7 = d.isie && !d.isieold && (!("documentMode" in document) || (document.documentMode == 7));
19165    d.isie8 = d.isie && ("documentMode" in document) && (document.documentMode == 8);
19166    d.isie9 = d.isie && ("performance" in window) && (document.documentMode >= 9);
19167    d.isie10 = d.isie && ("performance" in window) && (document.documentMode == 10);
19168    d.isie11 = ("msRequestFullscreen" in _el) && (document.documentMode >= 11); // IE11+
19169		d.isieedge = (navigator.userAgent.match(/Edge\/12\./));
19170
19171    d.isie9mobile = /iemobile.9/i.test(_agent); //wp 7.1 mango
19172    if (d.isie9mobile) d.isie9 = false;
19173    d.isie7mobile = (!d.isie9mobile && d.isie7) && /iemobile/i.test(_agent); //wp 7.0
19174
19175    d.ismozilla = ("MozAppearance" in _style);
19176
19177    d.iswebkit = ("WebkitAppearance" in _style);
19178
19179    d.ischrome = ("chrome" in window);
19180    d.ischrome22 = (d.ischrome && d.haspointerlock);
19181    d.ischrome26 = (d.ischrome && ("transition" in _style)); // issue with transform detection (maintain prefix)
19182
19183    d.cantouch = ("ontouchstart" in document.documentElement) || ("ontouchstart" in window); // detection for Chrome Touch Emulation
19184    d.hasmstouch = (window.MSPointerEvent || false); // IE10 pointer events
19185    d.hasw3ctouch = (window.PointerEvent || false) && ((navigator.MaxTouchPoints > 0)||(navigator.msMaxTouchPoints > 0)); //IE11 pointer events, following W3C Pointer Events spec
19186
19187    d.ismac = /^mac$/i.test(_platform);
19188
19189    d.isios = (d.cantouch && /iphone|ipad|ipod/i.test(_platform));
19190    d.isios4 = ((d.isios) && !("seal" in Object));
19191    d.isios7 = ((d.isios)&&("webkitHidden" in document));  //iOS 7+
19192
19193    d.isandroid = (/android/i.test(_agent));
19194
19195    d.haseventlistener = ("addEventListener" in _el);
19196    
19197    d.trstyle = false;
19198    d.hastransform = false;
19199    d.hastranslate3d = false;
19200    d.transitionstyle = false;
19201    d.hastransition = false;
19202    d.transitionend = false;
19203
19204    var a;
19205    var check = ['transform', 'msTransform', 'webkitTransform', 'MozTransform', 'OTransform'];    
19206    for (a = 0; a < check.length; a++) {
19207      if (typeof _style[check[a]] != "undefined") {
19208        d.trstyle = check[a];
19209        break;
19210      }
19211    }
19212    d.hastransform = (!!d.trstyle);
19213    if (d.hastransform) {
19214      _style[d.trstyle] = "translate3d(1px,2px,3px)";
19215      d.hastranslate3d = /translate3d/.test(_style[d.trstyle]);
19216    }
19217
19218    d.transitionstyle = false;
19219    d.prefixstyle = '';
19220    d.transitionend = false;
19221    check = ['transition', 'webkitTransition', 'msTransition', 'MozTransition', 'OTransition', 'OTransition', 'KhtmlTransition'];
19222    var prefix = ['', '-webkit-', '-ms-', '-moz-', '-o-', '-o', '-khtml-'];
19223    var evs = ['transitionend', 'webkitTransitionEnd', 'msTransitionEnd',  'transitionend', 'otransitionend', 'oTransitionEnd', 'KhtmlTransitionEnd'];
19224    for (a = 0; a < check.length; a++) {
19225      if (check[a] in _style) {
19226        d.transitionstyle = check[a];
19227        d.prefixstyle = prefix[a];
19228        d.transitionend = evs[a];
19229        break;
19230      }
19231    }
19232    if (d.ischrome26) {  // always use prefix
19233      d.prefixstyle = prefix[1];
19234    }
19235
19236    d.hastransition = (d.transitionstyle);
19237
19238    function detectCursorGrab() {
19239      var lst = ['-webkit-grab', '-moz-grab', 'grab'];
19240      if ((d.ischrome && !d.ischrome22) || d.isie) lst = []; // force setting for IE returns false positive and chrome cursor bug
19241      for (var a = 0; a < lst.length; a++) {
19242        var p = lst[a];
19243        _style.cursor = p;
19244        if (_style.cursor == p) return p;
19245      }
19246      return 'url(//mail.google.com/mail/images/2/openhand.cur),n-resize'; // thank you google for custom cursor!
19247    }
19248    d.cursorgrabvalue = detectCursorGrab();
19249
19250    d.hasmousecapture = ("setCapture" in _el);
19251
19252    d.hasMutationObserver = (ClsMutationObserver !== false);
19253
19254    _el = null; //memory released
19255
19256    browserdetected = d;
19257
19258    return d;
19259  };
19260
19261  var NiceScrollClass = function(myopt, me) {
19262
19263    var self = this;
19264
19265    this.version = '3.6.6';
19266    this.name = 'nicescroll';
19267
19268    this.me = me;
19269
19270    this.opt = {
19271      doc: $("body"),
19272      win: false
19273    };
19274
19275    $.extend(this.opt, _globaloptions);  // clone opts
19276
19277    // Options for internal use
19278    this.opt.snapbackspeed = 80;
19279
19280    if (myopt || false) {
19281      for (var a in self.opt) {
19282        if (typeof myopt[a] != "undefined") self.opt[a] = myopt[a];
19283      }
19284    }
19285
19286    this.doc = self.opt.doc;
19287    this.iddoc = (this.doc && this.doc[0]) ? this.doc[0].id || '' : '';
19288    this.ispage = /^BODY|HTML/.test((self.opt.win) ? self.opt.win[0].nodeName : this.doc[0].nodeName);
19289    this.haswrapper = (self.opt.win !== false);
19290    this.win = self.opt.win || (this.ispage ? $(window) : this.doc);
19291    this.docscroll = (this.ispage && !this.haswrapper) ? $(window) : this.win;
19292    this.body = $("body");
19293    this.viewport = false;
19294
19295    this.isfixed = false;
19296
19297    this.iframe = false;
19298    this.isiframe = ((this.doc[0].nodeName == 'IFRAME') && (this.win[0].nodeName == 'IFRAME'));
19299
19300    this.istextarea = (this.win[0].nodeName == 'TEXTAREA');
19301
19302    this.forcescreen = false; //force to use screen position on events
19303
19304    this.canshowonmouseevent = (self.opt.autohidemode != "scroll");
19305
19306    // Events jump table    
19307    this.onmousedown = false;
19308    this.onmouseup = false;
19309    this.onmousemove = false;
19310    this.onmousewheel = false;
19311    this.onkeypress = false;
19312    this.ongesturezoom = false;
19313    this.onclick = false;
19314
19315    // Nicescroll custom events
19316    this.onscrollstart = false;
19317    this.onscrollend = false;
19318    this.onscrollcancel = false;
19319
19320    this.onzoomin = false;
19321    this.onzoomout = false;
19322
19323    // Let's start!  
19324    this.view = false;
19325    this.page = false;
19326
19327    this.scroll = {
19328      x: 0,
19329      y: 0
19330    };
19331    this.scrollratio = {
19332      x: 0,
19333      y: 0
19334    };
19335    this.cursorheight = 20;
19336    this.scrollvaluemax = 0;
19337
19338    this.isrtlmode = (this.opt.rtlmode == "auto") ? ((this.win[0] == window ? this.body : this.win).css("direction") == "rtl") : (this.opt.rtlmode === true);
19339    //    this.checkrtlmode = false;
19340    
19341    this.scrollrunning = false;
19342
19343    this.scrollmom = false;
19344
19345    this.observer        = false;  // observer div changes
19346    this.observerremover = false;  // observer on parent for remove detection
19347    this.observerbody    = false;  // observer on body for position change
19348
19349    do {
19350      this.id = "ascrail" + (ascrailcounter++);
19351    } while (document.getElementById(this.id));
19352
19353    this.rail = false;
19354    this.cursor = false;
19355    this.cursorfreezed = false;
19356    this.selectiondrag = false;
19357
19358    this.zoom = false;
19359    this.zoomactive = false;
19360
19361    this.hasfocus = false;
19362    this.hasmousefocus = false;
19363
19364    this.visibility = true;
19365    this.railslocked = false;  // locked by resize
19366    this.locked = false;  // prevent lost of locked status sets by user
19367    this.hidden = false; // rails always hidden
19368    this.cursoractive = true; // user can interact with cursors
19369
19370    this.wheelprevented = false; //prevent mousewheel event
19371
19372    this.overflowx = self.opt.overflowx;
19373    this.overflowy = self.opt.overflowy;
19374
19375    this.nativescrollingarea = false;
19376    this.checkarea = 0;
19377
19378    this.events = []; // event list for unbind
19379
19380    this.saved = {};  // style saved
19381
19382    this.delaylist = {};
19383    this.synclist = {};
19384
19385    this.lastdeltax = 0;
19386    this.lastdeltay = 0;
19387
19388    this.detected = getBrowserDetection();
19389
19390    var cap = $.extend({}, this.detected);
19391
19392    this.canhwscroll = (cap.hastransform && self.opt.hwacceleration);
19393    this.ishwscroll = (this.canhwscroll && self.haswrapper);
19394
19395    this.hasreversehr = (this.isrtlmode&&!cap.iswebkit);  //RTL mode with reverse horizontal axis
19396    
19397    this.istouchcapable = false; // desktop devices with touch screen support
19398
19399    //## Check WebKit-based desktop with touch support
19400    //## + Firefox 18 nightly build (desktop) false positive (or desktop with touch support)
19401    if (cap.cantouch && !cap.isios && !cap.isandroid && (cap.iswebkit || cap.ismozilla)) {
19402      this.istouchcapable = true;
19403      cap.cantouch = false; // parse normal desktop events
19404    }
19405
19406    //## disable MouseLock API on user request
19407    if (!self.opt.enablemouselockapi) {
19408      cap.hasmousecapture = false;
19409      cap.haspointerlock = false;
19410    }
19411
19412/* deprecated
19413    this.delayed = function(name, fn, tm, lazy) {
19414    };
19415*/    
19416
19417    this.debounced = function(name, fn, tm) {
19418      var dd = self.delaylist[name];
19419      self.delaylist[name] = fn;
19420      if (!dd) {
19421        self.debouncedelayed =  setTimeout(function() {
19422					if (!self) return;
19423          var fn = self.delaylist[name];
19424          self.delaylist[name] = false;
19425          fn.call(self);
19426        }, tm);
19427      }
19428    };
19429
19430    var _onsync = false;
19431
19432    this.synched = function(name, fn) {
19433
19434      function requestSync() {
19435        if (_onsync) return;
19436        setAnimationFrame(function() {
19437          _onsync = false;
19438          for (var nn in self.synclist) {
19439            var fn = self.synclist[nn];
19440            if (fn) fn.call(self);
19441            self.synclist[nn] = false;
19442          }
19443        });
19444        _onsync = true;
19445      }
19446
19447      self.synclist[name] = fn;
19448      requestSync();
19449      return name;
19450    };
19451
19452    this.unsynched = function(name) {
19453      if (self.synclist[name]) self.synclist[name] = false;
19454    };
19455
19456    this.css = function(el, pars) { // save & set
19457      for (var n in pars) {
19458        self.saved.css.push([el, n, el.css(n)]);
19459        el.css(n, pars[n]);
19460      }
19461    };
19462
19463    this.scrollTop = function(val) {
19464      return (typeof val == "undefined") ? self.getScrollTop() : self.setScrollTop(val);
19465    };
19466
19467    this.scrollLeft = function(val) {
19468      return (typeof val == "undefined") ? self.getScrollLeft() : self.setScrollLeft(val);
19469    };
19470
19471    // derived by by Dan Pupius www.pupius.net
19472    var BezierClass = function(st, ed, spd, p1, p2, p3, p4) {
19473    
19474      this.st = st;
19475      this.ed = ed;
19476      this.spd = spd;
19477
19478      this.p1 = p1 || 0;
19479      this.p2 = p2 || 1;
19480      this.p3 = p3 || 0;
19481      this.p4 = p4 || 1;
19482
19483      this.ts = (new Date()).getTime();
19484      this.df = this.ed - this.st;
19485    };
19486    BezierClass.prototype = {
19487      B2: function(t) {
19488        return 3 * t * t * (1 - t);
19489      },
19490      B3: function(t) {
19491        return 3 * t * (1 - t) * (1 - t);
19492      },
19493      B4: function(t) {
19494        return (1 - t) * (1 - t) * (1 - t);
19495      },
19496      getNow: function() {
19497        var nw = (new Date()).getTime();
19498        var pc = 1 - ((nw - this.ts) / this.spd);
19499        var bz = this.B2(pc) + this.B3(pc) + this.B4(pc);
19500        return (pc < 0) ? this.ed : this.st + Math.round(this.df * bz);
19501      },
19502      update: function(ed, spd) {
19503        this.st = this.getNow();
19504        this.ed = ed;
19505        this.spd = spd;
vendor: 3,300 bytes, lines 19506-19588
19506        this.ts = (new Date()).getTime();
19507        this.df = this.ed - this.st;
19508        return this;
19509      }
19510    };
19511
19512    //derived from http://stackoverflow.com/questions/11236090/
19513    function getMatrixValues() {
19514      var tr = self.doc.css(cap.trstyle);
19515      if (tr && (tr.substr(0, 6) == "matrix")) {
19516        return tr.replace(/^.*\((.*)\)$/g, "$1").replace(/px/g, '').split(/, +/);
19517      }
19518      return false;
19519    }
19520
19521    if (this.ishwscroll) {
19522      // hw accelerated scroll
19523      this.doc.translate = {
19524        x: 0,
19525        y: 0,
19526        tx: "0px",
19527        ty: "0px"
19528      };
19529
19530      //this one can help to enable hw accel on ios6 http://indiegamr.com/ios6-html-hardware-acceleration-changes-and-how-to-fix-them/
19531      if (cap.hastranslate3d && cap.isios) this.doc.css("-webkit-backface-visibility", "hidden"); // prevent flickering http://stackoverflow.com/questions/3461441/      
19532
19533      this.getScrollTop = function(last) {
19534        if (!last) {
19535          var mtx = getMatrixValues();
19536          if (mtx) return (mtx.length == 16) ? -mtx[13] : -mtx[5]; //matrix3d 16 on IE10
19537          if (self.timerscroll && self.timerscroll.bz) return self.timerscroll.bz.getNow();
19538        }
19539        return self.doc.translate.y;
19540      };
19541
19542      this.getScrollLeft = function(last) {
19543        if (!last) {
19544          var mtx = getMatrixValues();
19545          if (mtx) return (mtx.length == 16) ? -mtx[12] : -mtx[4]; //matrix3d 16 on IE10
19546          if (self.timerscroll && self.timerscroll.bh) return self.timerscroll.bh.getNow();
19547        }
19548        return self.doc.translate.x;
19549      };
19550
19551      this.notifyScrollEvent = function(el) {
19552        var e = document.createEvent("UIEvents");
19553        e.initUIEvent("scroll", false, true, window, 1);
19554        e.niceevent = true;
19555        el.dispatchEvent(e);
19556      };
19557
19558      var cxscrollleft = (this.isrtlmode) ? 1 : -1;
19559
19560      if (cap.hastranslate3d && self.opt.enabletranslate3d) {
19561        this.setScrollTop = function(val, silent) {
19562          self.doc.translate.y = val;
19563          self.doc.translate.ty = (val * -1) + "px";
19564          self.doc.css(cap.trstyle, "translate3d(" + self.doc.translate.tx + "," + self.doc.translate.ty + ",0px)");
19565          if (!silent) self.notifyScrollEvent(self.win[0]);
19566        };
19567        this.setScrollLeft = function(val, silent) {
19568          self.doc.translate.x = val;
19569          self.doc.translate.tx = (val * cxscrollleft) + "px";
19570          self.doc.css(cap.trstyle, "translate3d(" + self.doc.translate.tx + "," + self.doc.translate.ty + ",0px)");
19571          if (!silent) self.notifyScrollEvent(self.win[0]);
19572        };
19573      } else {
19574        this.setScrollTop = function(val, silent) {
19575          self.doc.translate.y = val;
19576          self.doc.translate.ty = (val * -1) + "px";
19577          self.doc.css(cap.trstyle, "translate(" + self.doc.translate.tx + "," + self.doc.translate.ty + ")");
19578          if (!silent) self.notifyScrollEvent(self.win[0]);
19579        };
19580        this.setScrollLeft = function(val, silent) {
19581          self.doc.translate.x = val;
19582          self.doc.translate.tx = (val * cxscrollleft) + "px";
19583          self.doc.css(cap.trstyle, "translate(" + self.doc.translate.tx + "," + self.doc.translate.ty + ")");
19584          if (!silent) self.notifyScrollEvent(self.win[0]);
19585        };
19586      }
19587    } else {
19588      // native scroll
19589      this.getScrollTop = function() {
19590        return self.docscroll.scrollTop();
19591      };
19592      this.setScrollTop = function(val) {
19593        return setTimeout(function() {self.docscroll.scrollTop(val)}, 1);
19594      };
19595      this.getScrollLeft = function() {
19596        if (self.detected.ismozilla && self.isrtlmode)
19597          return Math.abs(self.docscroll.scrollLeft());
19598        return self.docscroll.scrollLeft();
19599      };
19600      this.setScrollLeft = function(val) {
19601        return setTimeout(function() {self.docscroll.scrollLeft((self.detected.ismozilla && self.isrtlmode) ? -val : val)}, 1);
19602      };
19603    }
19604
19605    this.getTarget = function(e) {
19606      if (!e) return false;
19607      if (e.target) return e.target;
19608      if (e.srcElement) return e.srcElement;
19609      return false;
19610    };
19611
19612    this.hasParent = function(e, id) {
19613      if (!e) return false;
19614      var el = e.target || e.srcElement || e || false;
19615      while (el && el.id != id) {
19616        el = el.parentNode || false;
19617      }
19618      return (el !== false);
19619    };
19620
19621    function getZIndex() {
19622      var dom = self.win;
19623      if ("zIndex" in dom) return dom.zIndex(); // use jQuery UI method when available
19624      while (dom.length > 0) {
19625        if (dom[0].nodeType == 9) return false;
19626        var zi = dom.css('zIndex');
19627        if (!isNaN(zi) && zi != 0) return parseInt(zi);
19628        dom = dom.parent();
19629      }
19630      return false;
19631    }
19632
19633    //inspired by http://forum.jquery.com/topic/width-includes-border-width-when-set-to-thin-medium-thick-in-ie
19634    var _convertBorderWidth = {
19635      "thin": 1,
19636      "medium": 3,
19637      "thick": 5
19638    };
19639
19640    function getWidthToPixel(dom, prop, chkheight) {
19641      var wd = dom.css(prop);
19642      var px = parseFloat(wd);
19643      if (isNaN(px)) {
19644        px = _convertBorderWidth[wd] || 0;
19645        var brd = (px == 3) ? ((chkheight) ? (self.win.outerHeight() - self.win.innerHeight()) : (self.win.outerWidth() - self.win.innerWidth())) : 1; //DON'T TRUST CSS
19646        if (self.isie8 && px) px += 1;
19647        return (brd) ? px : 0;
19648      }
19649      return px;
19650    }
19651
19652    this.getDocumentScrollOffset = function() {
19653      return {top:window.pageYOffset||document.documentElement.scrollTop,
19654              left:window.pageXOffset||document.documentElement.scrollLeft};
19655    }
19656    
19657    this.getOffset = function() {
19658      if (self.isfixed) {
19659        var ofs = self.win.offset();  // fix Chrome auto issue (when right/bottom props only)
19660        var scrl = self.getDocumentScrollOffset();
19661        ofs.top-=scrl.top;
19662        ofs.left-=scrl.left;
19663        return ofs;  
19664      }
19665      var ww = self.win.offset();
19666      if (!self.viewport) return ww;      
19667      var vp = self.viewport.offset();
19668      return {
19669        top: ww.top - vp.top,// + self.viewport.scrollTop(),
19670        left: ww.left - vp.left // + self.viewport.scrollLeft()
19671      };
19672    };
19673
19674    this.updateScrollBar = function(len) {
19675      if (self.ishwscroll) {
19676        self.rail.css({  //**
19677          height: self.win.innerHeight() - (self.opt.railpadding.top + self.opt.railpadding.bottom)
19678        });
19679        if (self.railh) self.railh.css({  //**
19680          width: self.win.innerWidth() - (self.opt.railpadding.left + self.opt.railpadding.right)
19681        });
19682        
19683      } else {
19684        var wpos = self.getOffset();
19685        var pos = {
19686          top: wpos.top,
19687          left: wpos.left  - (self.opt.railpadding.left + self.opt.railpadding.right)
19688        };
19689        pos.top += getWidthToPixel(self.win, 'border-top-width', true);
19690        pos.left += (self.rail.align) ? self.win.outerWidth() - getWidthToPixel(self.win, 'border-right-width') - self.rail.width : getWidthToPixel(self.win, 'border-left-width');
19691
19692        var off = self.opt.railoffset;
19693        if (off) {
19694          if (off.top) pos.top += off.top;
19695          if (off.left) pos.left += off.left;
19696        }
19697        
19698        if (!self.railslocked) self.rail.css({
19699          top: pos.top,
19700          left: pos.left,
19701          height: ((len) ? len.h : self.win.innerHeight()) - (self.opt.railpadding.top + self.opt.railpadding.bottom)
19702        });
19703
19704        if (self.zoom) {
19705          self.zoom.css({
19706            top: pos.top + 1,
19707            left: (self.rail.align == 1) ? pos.left - 20 : pos.left + self.rail.width + 4
19708          });
19709        }
19710
19711        if (self.railh && !self.railslocked) {
19712          var pos = {
19713            top: wpos.top,
19714            left: wpos.left
19715          };
19716          var off = self.opt.railhoffset;
19717          if (!!off) {
19718            if (!!off.top) pos.top += off.top;
19719            if (!!off.left) pos.left += off.left;
19720          }
19721          var y = (self.railh.align) ? pos.top + getWidthToPixel(self.win, 'border-top-width', true) + self.win.innerHeight() - self.railh.height : pos.top + getWidthToPixel(self.win, 'border-top-width', true);
19722          var x = pos.left + getWidthToPixel(self.win, 'border-left-width');
19723          self.railh.css({
19724            top: y  - (self.opt.railpadding.top + self.opt.railpadding.bottom),
19725            left: x,
19726            width: self.railh.width
19727          });
19728        }
19729
19730
19731      }
19732    };
19733
19734    this.doRailClick = function(e, dbl, hr) {
19735      var fn, pg, cur, pos;
19736
19737      if (self.railslocked) return;
19738      self.cancelEvent(e);
19739
19740      if (dbl) {
19741        fn = (hr) ? self.doScrollLeft : self.doScrollTop;
19742        cur = (hr) ? ((e.pageX - self.railh.offset().left - (self.cursorwidth / 2)) * self.scrollratio.x) : ((e.pageY - self.rail.offset().top - (self.cursorheight / 2)) * self.scrollratio.y);
19743        fn(cur);
19744      } else {
19745        fn = (hr) ? self.doScrollLeftBy : self.doScrollBy;
19746        cur = (hr) ? self.scroll.x : self.scroll.y;
19747        pos = (hr) ? e.pageX - self.railh.offset().left : e.pageY - self.rail.offset().top;
19748        pg = (hr) ? self.view.w : self.view.h;
19749        fn((cur >= pos) ? pg: -pg);//   (cur >= pos) ? fn(pg): fn(-pg);
19750      }
19751
19752    };
19753
19754    self.hasanimationframe = (setAnimationFrame);
19755    self.hascancelanimationframe = (clearAnimationFrame);
19756
19757    if (!self.hasanimationframe) {
19758      setAnimationFrame = function(fn) {
19759        return setTimeout(fn, 15 - Math.floor((+new Date()) / 1000) % 16);
19760      }; // 1000/60)};
19761      clearAnimationFrame = clearInterval;
19762    } else if (!self.hascancelanimationframe) clearAnimationFrame = function() {
19763      self.cancelAnimationFrame = true;
19764    };
19765
19766    this.init = function() {
19767
19768      self.saved.css = [];
19769
19770      if (cap.isie7mobile) return true; // SORRY, DO NOT WORK!
19771      if (cap.isoperamini) return true; // SORRY, DO NOT WORK!
19772
19773      if (cap.hasmstouch) self.css((self.ispage) ? $("html") : self.win, {
19774        '-ms-touch-action': 'none'
19775      });
19776
19777      self.zindex = "auto";
19778      if (!self.ispage && self.opt.zindex == "auto") {
19779        self.zindex = getZIndex() || "auto";
19780      } else {
19781        self.zindex = self.opt.zindex;
19782      }
19783
19784      if (!self.ispage && self.zindex != "auto") {
19785        if (self.zindex > globalmaxzindex) globalmaxzindex = self.zindex;
19786      }
19787
19788      if (self.isie && self.zindex == 0 && self.opt.zindex == "auto") { // fix IE auto == 0
19789        self.zindex = "auto";
19790      }
19791
19792      if (!self.ispage || (!cap.cantouch && !cap.isieold && !cap.isie9mobile)) {
19793
19794        var cont = self.docscroll;
19795        if (self.ispage) cont = (self.haswrapper) ? self.win : self.doc;
19796
19797        if (!cap.isie9mobile) self.css(cont, {
19798          'overflow-y': 'hidden'
19799        });
19800
19801        if (self.ispage && cap.isie7) {
19802          if (self.doc[0].nodeName == 'BODY') self.css($("html"), {
19803            'overflow-y': 'hidden'
19804          }); //IE7 double scrollbar issue
19805          else if (self.doc[0].nodeName == 'HTML') self.css($("body"), {
19806            'overflow-y': 'hidden'
19807          }); //IE7 double scrollbar issue
19808        }
19809
19810        if (cap.isios && !self.ispage && !self.haswrapper) self.css($("body"), {
19811          "-webkit-overflow-scrolling": "touch"
19812        }); //force hw acceleration
19813
19814        var cursor = $(document.createElement('div'));
19815        cursor.css({
19816          position: "relative",
19817          top: 0,
19818          "float": "right",
19819          width: self.opt.cursorwidth,
19820          height: "0px",
19821          'background-color': self.opt.cursorcolor,
19822          border: self.opt.cursorborder,
19823          'background-clip': 'padding-box',
19824          '-webkit-border-radius': self.opt.cursorborderradius,
19825          '-moz-border-radius': self.opt.cursorborderradius,
19826          'border-radius': self.opt.cursorborderradius
19827        });
19828
19829        cursor.hborder = parseFloat(cursor.outerHeight() - cursor.innerHe
19829ight());
19830        
19831        cursor.addClass('nicescroll-cursors');
19832        
19833        self.cursor = cursor;
19834
19835        var rail = $(document.createElement('div'));
19836        rail.attr('id', self.id);
19837        rail.addClass('nicescroll-rails nicescroll-rails-vr');
19838
19839        var v, a, kp = ["left","right","top","bottom"];  //**
19840        for (var n in kp) {
19841          a = kp[n];
19842          v = self.opt.railpadding[a];
19843          (v) ? rail.css("padding-"+a,v+"px") : self.opt.railpadding[a] = 0;
19844        }
19845
19846        rail.append(cursor);
19847
19848        rail.width = Math.max(parseFloat(self.opt.cursorwidth), cursor.outerWidth());
19849        rail.css({
19850          width: rail.width + "px",
19851          'zIndex': self.zindex,
19852          "background": self.opt.background,
19853          cursor: "default"
19854        });
19855
19856        rail.visibility = true;
19857        rail.scrollable = true;
19858
19859        rail.align = (self.opt.railalign == "left") ? 0 : 1;
19860
19861        self.rail = rail;
19862
19863        self.rail.drag = false;
19864
19865        var zoom = false;
19866        if (self.opt.boxzoom && !self.ispage && !cap.isieold) {
19867          zoom = document.createElement('div');
19868
19869          self.bind(zoom, "click", self.doZoom);
19870          self.bind(zoom, "mouseenter", function() {
19871            self.zoom.css('opacity', self.opt.cursoropacitymax);
19872          });
19873          self.bind(zoom, "mouseleave", function() {
19874            self.zoom.css('opacity', self.opt.cursoropacitymin);
19875          });
19876
19877          self.zoom = $(zoom);
19878          self.zoom.css({
19879            "cursor": "pointer",
19880            'z-index': self.zindex,
19881            'backgroundImage': 'url(' + self.opt.scriptpath + 'zoomico.png)',
19882            'height': 18,
19883            'width': 18,
19884            'backgroundPosition': '0px 0px'
19885          });
19886          if (self.opt.dblclickzoom) self.bind(self.win, "dblclick", self.doZoom);
19887          if (cap.cantouch && self.opt.gesturezoom) {
19888            self.ongesturezoom = function(e) {
19889              if (e.scale > 1.5) self.doZoomIn(e);
19890              if (e.scale < 0.8) self.doZoomOut(e);
19891              return self.cancelEvent(e);
19892            };
19893            self.bind(self.win, "gestureend", self.ongesturezoom);
19894          }
19895        }
19896
19897        // init HORIZ
19898
19899        self.railh = false;
19900        var railh;
19901
19902        if (self.opt.horizrailenabled) {
19903
19904          self.css(cont, {
19905            'overflow-x': 'hidden'
19906          });
19907
19908          var cursor = $(document.createElement('div'));
19909          cursor.css({
19910            position: "absolute",
19911            top: 0,
19912            height: self.opt.cursorwidth,
19913            width: "0px",
19914            'background-color': self.opt.cursorcolor,
19915            border: self.opt.cursorborder,
19916            'background-clip': 'padding-box',
19917            '-webkit-border-radius': self.opt.cursorborderradius,
19918            '-moz-border-radius': self.opt.cursorborderradius,
19919            'border-radius': self.opt.cursorborderradius
19920          });
19921
19922          if (cap.isieold) cursor.css({'overflow':'hidden'});  //IE6 horiz scrollbar issue
19923          
19924          cursor.wborder = parseFloat(cursor.outerWidth() - cursor.innerWidth());
19925          
19926          cursor.addClass('nicescroll-cursors');
19927          
19928          self.cursorh = cursor;
19929
19930          railh = $(document.createElement('div'));
19931          railh.attr('id', self.id + '-hr');
19932          railh.addClass('nicescroll-rails nicescroll-rails-hr');
19933          railh.height = Math.max(parseFloat(self.opt.cursorwidth), cursor.outerHeight());
19934          railh.css({
19935            height: railh.height + "px",
19936            'zIndex': self.zindex,
19937            "background": self.opt.background
19938          });
19939
19940          railh.append(cursor);
19941
19942          railh.visibility = true;
19943          railh.scrollable = true;
19944
19945          railh.align = (self.opt.railvalign == "top") ? 0 : 1;
19946
19947          self.railh = railh;
19948
19949          self.railh.drag = false;
19950
19951        }
19952
19953        //        
19954
19955        if (self.ispage) {
19956          rail.css({
19957            position: "fixed",
19958            top: "0px",
19959            height: "100%"
19960          });
19961          (rail.align) ? rail.css({
19962            right: "0px"
19963          }): rail.css({
19964            left: "0px"
19965          });
19966          self.body.append(rail);
19967          if (self.railh) {
19968            railh.css({
19969              position: "fixed",
19970              left: "0px",
19971              width: "100%"
19972            });
19973            (railh.align) ? railh.css({
19974              bottom: "0px"
19975            }): railh.css({
19976              top: "0px"
19977            });
19978            self.body.append(railh);
19979          }
19980        } else {
19981          if (self.ishwscroll) {
19982            if (self.win.css('position') == 'static') self.css(self.win, {
19983              'position': 'relative'
19984            });
19985            var bd = (self.win[0].nodeName == 'HTML') ? self.body : self.win;
19986            $(bd).scrollTop(0).scrollLeft(0);  // fix rail position if content already scrolled
19987            if (self.zoom) {
19988              self.zoom.css({
19989                position: "absolute",
19990                top: 1,
19991                right: 0,
19992                "margin-right": rail.width + 4
19993              });
19994              bd.append(self.zoom);
19995            }
19996            rail.css({
19997              position: "absolute",
19998              top: 0
19999            });
20000            (rail.align) ? rail.css({
20001              right: 0
20002            }): rail.css({
20003              left: 0
20004            });
20005            bd.append(rail);
20006            if (railh) {
20007              railh.css({
20008                position: "absolute",
20009                left: 0,
20010                bottom: 0
20011              });
20012              (railh.align) ? railh.css({
20013                bottom: 0
20014              }): railh.css({
20015                top: 0
20016              });
20017              bd.append(railh);
20018            }
20019          } else {
20020            self.isfixed = (self.win.css("position") == "fixed");
20021            var rlpos = (self.isfixed) ? "fixed" : "absolute";
20022
20023            if (!self.isfixed) self.viewport = self.getViewport(self.win[0]);
20024            if (self.viewport) {
20025              self.body = self.viewport;
20026              if ((/fixed|absolute/.test(self.viewport.css("position"))) == false) self.css(self.viewport, {
20027                "position": "relative"
20028              });
20029            }
20030
20031            rail.css({
20032              position: rlpos
20033            });
20034            if (self.zoom) self.zoom.css({
20035              position: rlpos
20036            });
20037            self.updateScrollBar();
20038            self.body.append(rail);
20039            if (self.zoom) self.body.append(self.zoom);
20040            if (self.railh) {
20041              railh.css({
20042                position: rlpos
20043              });
20044              self.body.append(railh);
20045            }
20046          }
20047
20048          if (cap.isios) self.css(self.win, {
20049            '-webkit-tap-highlight-color': 'rgba(0,0,0,0)',
20050            '-webkit-touch-callout': 'none'
20051          }); // prevent grey layer on click
20052
20053          if (cap.isie && self.opt.disableoutline) self.win.attr("hideFocus", "true"); // IE, prevent dotted rectangle on focused div
20054          if (cap.iswebkit && self.opt.disableoutline) self.win.css({"outline": "none"});  // Webkit outline
20055          //if (cap.isopera&&self.opt.disableoutline) self.win.css({"outline":"0"});  // Opera 12- to test [TODO]
20056
20057        }
20058
20059        if (self.opt.autohidemode === false) {
20060          self.autohidedom = false;
20061          self.rail.css({
20062            opacity: self.opt.cursoropacitymax
20063          });
20064          if (self.railh) self.railh.css({
20065            opacity: self.opt.cursoropacitymax
20066          });
20067        } else if ((self.opt.autohidemode === true) || (self.opt.autohidemode === "leave")) {
20068          self.autohidedom = $().add(self.rail);
20069          if (cap.isie8) self.autohidedom = self.autohidedom.add(self.cursor);
20070          if (self.railh) self.autohidedom = self.autohidedom.add(self.railh);
20071          if (self.railh && cap.isie8) self.autohidedom = self.autohidedom.add(self.cursorh);
20072        } else if (self.opt.autohidemode == "scroll") {
20073          self.autohidedom = $().add(self.rail);
20074          if (self.railh) self.autohidedom = self.autohidedom.add(self.railh);
20075        } else if (self.opt.autohidemode == "cursor") {
20076          self.autohidedom = $().add(self.cursor);
20077          if (self.railh) self.autohidedom = self.autohidedom.add(self.cursorh);
20078        } else if (self.opt.autohidemode == "hidden") {
20079          self.autohidedom = false;
20080          self.hide();
20081          self.railslocked = false;
20082        }
20083
20084        if (cap.isie9mobile) {
20085
20086          self.scrollmom = new ScrollMomentumClass2D(self);
20087
20088          self.onmangotouch = function() {
20089            var py = self.getScrollTop();
20090            var px = self.getScrollLeft();
20091
20092            if ((py == self.scrollmom.lastscrolly) && (px == self.scrollmom.lastscrollx)) return true;
20093
20094            var dfy = py - self.mangotouch.sy;
20095            var dfx = px - self.mangotouch.sx;
20096            var df = Math.round(Math.sqrt(Math.pow(dfx, 2) + Math.pow(dfy, 2)));
20097            if (df == 0) return;
20098
20099            var dry = (dfy < 0) ? -1 : 1;
20100            var drx = (dfx < 0) ? -1 : 1;
20101
20102            var tm = +new Date();
20103            if (self.mangotouch.lazy) clearTimeout(self.mangotouch.lazy);
20104
20105            if (((tm - self.mangotouch.tm) > 80) || (self.mangotouch.dry != dry) || (self.mangotouch.drx != drx)) {
20106              self.scrollmom.stop();
20107              self.scrollmom.reset(px, py);
20108              self.mangotouch.sy = py;
20109              self.mangotouch.ly = py;
20110              self.mangotouch.sx = px;
20111              self.mangotouch.lx = px;
20112              self.mangotouch.dry = dry;
20113              self.mangotouch.drx = drx;
20114              self.mangotouch.tm = tm;
20115            } else {
20116
20117              self.scrollmom.stop();
20118              self.scrollmom.update(self.mangotouch.sx - dfx, self.mangotouch.sy - dfy);
20119              self.mangotouch.tm = tm;
20120
20121              var ds = Math.max(Math.abs(self.mangotouch.ly - py), Math.abs(self.mangotouch.lx - px));
20122              self.mangotouch.ly = py;
20123              self.mangotouch.lx = px;
20124
20125              if (ds > 2) {
20126                self.mangotouch.lazy = setTimeout(function() {
20127                  self.mangotouch.lazy = false;
20128                  self.mangotouch.dry = 0;
20129                  self.mangotouch.drx = 0;
20130                  self.mangotouch.tm = 0;
20131                  self.scrollmom.doMomentum(30);
20132                }, 100);
20133              }
20134            }
20135          };
20136
20137          var top = self.getScrollTop();
20138          var lef = self.getScrollLeft();
20139          self.mangotouch = {
20140            sy: top,
20141            ly: top,
20142            dry: 0,
20143            sx: lef,
20144            lx: lef,
20145            drx: 0,
20146            lazy: false,
20147            tm: 0
20148          };
20149
20150          self.bind(self.docscroll, "scroll", self.onmangotouch);
20151
20152        } else {
20153
20154          if (cap.cantouch || self.istouchcapable || self.opt.touchbehavior || cap.hasmstouch) {
20155
20156            self.scrollmom = new ScrollMomentumClass2D(self);
20157
20158            self.ontouchstart = function(e) {
20159              if (e.pointerType && e.pointerType != 2 && e.pointerType != "touch") return false;
20160              
20161              self.hasmoving = false;
20162
20163              if (!self.railslocked) {
20164
20165                var tg;
20166                if (cap.hasmstouch) {
20167                  tg = (e.target) ? e.target : false;
20168                  while (tg) {
20169                    var nc = $(tg).getNiceScroll();
20170                    if ((nc.length > 0) && (nc[0].me == self.me)) break;
20171                    if (nc.length > 0) return false;
20172                    if ((tg.nodeName == 'DIV') && (tg.id == self.id)) break;
20173                    tg = (tg.parentNode) ? tg.parentNode : false;
20174                  }
20175                }
20176
20177                self.cancelScroll();
20178
20179                tg = self.getTarget(e);
20180
20181                if (tg) {
20182                  var skp = (/INPUT/i.test(tg.nodeName)) && (/range/i.test(tg.type));
20183                  if (skp) return self.stopPropagation(e);
20184                }
20185
20186                if (!("clientX" in e) && ("changedTouches" in e)) {
20187                  e.clientX = e.changedTouches[0].clientX;
20188                  e.clientY = e.changedTouches[0].clientY;
20189                }
20190
20191                if (self.forcescreen) {
20192                  var le = e;
20193                  e = {
20194                    "original": (e.original) ? e.original : e
20195                  };
20196                  e.clientX = le.screenX;
20197                  e.clientY = le.screenY;
20198                }
20199
20200                self.rail.drag = {
20201                  x: e.clientX,
20202                  y: e.clientY,
20203                  sx: self.scroll.x,
20204                  sy: self.scroll.y,
20205                  st: self.getScrollTop(),
20206                  sl: self.getScrollLeft(),
20207                  pt: 2,
20208                  dl: false
20209                };
20210
20211                if (self.ispage || !self.opt.directionlockdeadzone) {
20212                  self.rail.drag.dl = "f";
20213                } else {
20214
20215                  var view = {
20216                    w: $(window).width(),
20217                    h: $(window).height()
20218                  };
20219
20220                  var page = {
20221                    w: Math.max(document.body.scrollWidth, document.documentElement.scrollWidth),
20222                    h: Math.max(document.body.scrollHeight, document.documentElement.scrollHeight)
20223                  };
20224
20225                  var maxh = Math.max(0, page.h - view.h);
20226                  var maxw = Math.max(0, page.w - view.w);
20227
20228                  if (!self.rail.scrollable && self.railh.scrollable) self.rail.drag.ck = (maxh > 0) ? "v" : false;
20229                  else if (self.rail.scrollable && !self.railh.scrollable) self.rail.drag.ck = (maxw > 0) ? "h" : false;
20230                  else self.rail.drag.ck = false;
20231                  if (!self.rail.drag.ck) self.rail.drag.dl = "f";
20232                }
20233
20234                if (self.opt.touchbehavior && self.isiframe && cap.isie) {
20235                  var wp = self.win.position();
20236                  self.rail.drag.x += wp.left;
20237                  self.rail.drag.y += wp.top;
20238                }
20239
20240                self.hasmoving = false;
20241                self.lastmouseup = false;
20242                self.scrollmom.reset(e.clientX, e.clientY);
20243                
20244                if (!cap.cantouch && !this.istouchcapable && !e.pointerType) {       
20245                
20246                  var ip = (tg) ? /INPUT|SELECT|TEXTAREA/i.test(tg.nodeName) : false;
20247                  if (!ip) {
20248                    if (!self.ispage && cap.hasmousecapture) tg.setCapture();
20249                    if (self.opt.touchbehavior) {
20250                      if (tg.onclick && !(tg._onclick || false)) { // intercept DOM0 onclick event
20251                        tg._onclick = tg.onclick;
20252                        tg.onclick = function(e) {
20253                          if (self.hasmoving) return false;
20254                          tg._onclick.call(this, e);
20255                        };
20256                      }
20257                      return self.cancelEvent(e);
20258                    }
20259                    return self.stopPropagation(e);
20260                  }
20261
20262                  if (/SUBMIT|CANCEL|BUTTON/i.test($(tg).attr('type'))) {
20263                    pc = {
20264                      "tg": tg,
20265                      "click": false
20266                    };
20267                    self.preventclick = pc;
20268                  }
20269
20270                }
20271              }
20272
20273            };
20274
20275            self.ontouchend = function(e) {              
20276              if (!self.rail.drag) return true;              
20277              if (self.rail.drag.pt == 2) {
20278                if (e.pointerType && e.pointerType != 2 && e.pointerType != "touch") return false;
20279                self.scrollmom.doMomentum();
20280                self.rail.drag = false;
20281                if (self.hasmoving) {
20282                  self.lastmouseup = true;
20283                  self.hideCursor();
20284                  if (cap.hasmousecapture) document.releaseCapture();
20285                  if (!cap.cantouch) return self.cancelEvent(e);
20286                }
20287              }
20288              else if (self.rail.drag.pt == 1) {
20289                return self.onmouseup(e);
20290              }
20291
20292            };
20293
20294            var moveneedoffset = (self.opt.touchbehavior && self.isiframe && !cap.hasmousecapture);
20295
20296            self.ontouchmove = function(e, byiframe) {
20297
20298              if (!self.rail.drag) return false;
20299            
20300              if (e.targetTouches && self.opt.preventmultitouchscrolling) {
20301                if (e.targetTouches.length > 1) return false; // multitouch
20302              }
20303            
20304              if (e.pointerType && e.pointerType != 2 && e.pointerType != "touch") return false;
20305          
20306              if (self.rail.drag.pt == 2) {
20307                if (cap.cantouch && (cap.isios) && (typeof e.original == "undefined")) return true; // prevent ios "ghost" events by clickable elements
20308
20309                self.hasmoving = true;
20310
20311                if (self.preventclick && !self.preventclick.click) {
20312                  self.preventclick.click = self.preventclick.tg.onclick || false;
20313                  self.preventclick.tg.onclick = self.onpreventclick;
20314                }
20315
20316                var ev = $.extend({
20317                  "original": e
20318                }, e);
20319                e = ev;
20320
20321                if (("changedTouches" in e)) {
20322                  e.clientX = e.changedTouches[0].clientX;
20323                  e.clientY = e.changedTouches[0].clientY;
20324                }
20325
20326                if (self.forcescreen) {
20327                  var le = e;
20328                  e = {
20329                    "original": (e.original) ? e.original : e
20330                  };
20331                  e.clientX = le.screenX;
20332                  e.clientY = le.screenY;
20333                }
20334
20335                var ofy,ofx;
20336                ofx = ofy = 0;
20337
20338                if (moveneedoffset && !byiframe) {
20339                  var wp = self.win.position();
20340                  ofx = -wp.left;
20341                  ofy = -wp.top;
20342                }
20343
20344                var fy = e.clientY + ofy;
20345                var my = (fy - self.rail.drag.y);
20346                var fx = e.clientX + ofx;
20347                var mx = (fx - self.rail.drag.x);
20348
20349                var ny = self.rail.drag.st - my;
20350
20351                if (self.ishwscroll && self.opt.bouncescroll) {
20352                  if (ny < 0) {
20353                    ny = Math.round(ny / 2);
20354                    //                    fy = 0;
20355                  } else if (ny > self.page.maxh) {
20356                    ny = self.page.maxh + Math.round((ny - self.page.maxh) / 2);
20357                    //                    fy = 0;
20358                  }
20359                } else {
20360                  if (ny < 0) {
20361                    ny = 0;
20362                    fy = 0;
20363                  }
20364                  if (ny > self.page.maxh) {
20365                    ny = self.page.maxh;
20366                    fy = 0;
20367                  }
20368                }
20369
20370                var nx;
20371                if (self.railh && self.railh.scrollable) {
20372                  nx = (self.isrtlmode) ? mx - self.rail.drag.sl : self.rail.drag.sl - mx;
20373
20374                  if (self.ishwscroll && self.opt.bouncescroll) {
20375                    if (nx < 0) {
20376                      nx = Math.round(nx / 2);
20377                      //                      fx = 0;
20378                    } else if (nx > self.page.maxw) {
20379                      nx = self.page.maxw + Math.round((nx - self.page.maxw) / 2);
20380                      //                      fx = 0;
20381                    }
20382                  } else {
20383                    if (nx < 0) {
20384                      nx = 0;
20385                      fx = 0;
20386                    }
20387                    if (nx > self.page.maxw) {
20388                      nx = self.page.maxw;
20389                      fx = 0;
20390                    }
20391                  }
20392
20393                }
20394
20395                var grabbed = false;
20396                if (self.rail.drag.dl) {
20397                  grabbed = true;
20398                  if (self.rail.drag.dl == "v") nx = self.rail.drag.sl;
20399                  else if (self.rail.drag.dl == "h") ny = self.rail.drag.st;
20400                } else {
20401                  var ay = Math.abs(my);
20402                  var ax = Math.abs(mx);
20403                  var dz = self.opt.directionlockdeadzone;
20404                  if (self.rail.drag.ck == "v") {
20405                    if (ay > dz && (ax <= (ay * 0.3))) {
20406                      self.rail.drag = false;
20407                      return true;
20408                    } else if (ax > dz) {
20409                      self.rail.drag.dl = "f";
20410                      $("body").scrollTop($("body").scrollTop()); // stop iOS native scrolling (when active javascript has blocked)
20411                    }
20412                  } else if (self.rail.drag.ck == "h") {
20413                    if (ax > dz && (ay <= (ax * 0.3))) {
20414                      self.rail.drag = false;
20415                      return true;
20416                    } else if (ay > dz) {
20417                      self.rail.drag.dl = "f";
20418                      $("body").scrollLeft($("body").scrollLeft()); // stop iOS native scrolling (when active javascript has blocked)
20419                    }
20420                  }
20421                }
20422
20423                self.synched("touchmove", function() {
20424                  if (self.rail.drag && (self.rail.drag.pt == 2)) {
20425                    if (self.prepareTransition) self.prepareTransition(0);
20426                    if (self.rail.scrollable) self.setScrollTop(ny);
20427                    self.scrollmom.update(fx, fy);
20428                    if (self.railh && self.railh.scrollable) {
20429                      self.setScrollLeft(nx);
20430                      self.showCursor(ny, nx);
20431                    } else {
20432                      self.showCursor(ny);
20433                    }
20434                    if (cap.isie10) document.selection.clear();
20435                  }
20436                });
20437
20438                if (cap.ischrome && self.istouchcapable) grabbed = false; //chrome touch emulation doesn't like!
20439                if (grabbed) return self.cancelEvent(e);
20440              }
20441              else if (self.rail.drag.pt == 1) { // drag on cursor
20442                return self.onmousemove(e);
20443              }
20444
20445            };
20446
20447          }
20448
20449          self.onmousedown = function(e, hronly) {
20450            if (self.rail.drag && self.rail.drag.pt != 1) return;
20451            if (self.railslocked) return self.cancelEvent(e);
20452            self.cancelScroll();
20453            self.rail.drag = {
20454              x: e.clientX,
20455              y: e.clientY,
20456              sx: self.scroll.x,
20457              sy: self.scroll.y,
20458              pt: 1,
20459              hr: (!!hronly)
20460            };
20461            var tg = self.getTarget(e);
20462            if (!self.ispage && cap.hasmousecapture) tg.setCapture();
20463            if (self.isiframe && !cap.hasmousecapture) {
20464              self.saved.csspointerevents = self.doc.css("pointer-events");
20465              self.css(self.doc, {
20466                "pointer-events": "none"
20467              });
20468            }
20469            self.hasmoving = false;
20470            return self.cancelEvent(e);
20471          };
20472
20473          self.onmouseup = function(e) {
20474            if (self.rail.drag) {
20475              if (self.rail.drag.pt != 1) return true;
20476              if (cap.hasmousecapture) document.releaseCapture();
20477              if (self.isiframe && !cap.hasmousecapture) self.doc.css("pointer-events", self.saved.csspointerevents);              
20478              self.rail.drag = false;
20479              //if (!self.rail.active) self.hideCursor();
20480              if (self.hasmoving) self.triggerScrollEnd(); // TODO - check &&!self.scrollrunning
20481              return self.cancelEvent(e);
20482            }
20483          };
20484
20485          self.onmousemove = function(e) {
20486            if (self.rail.drag) {
20487              if (self.rail.drag.pt != 1) return;
20488
20489              if (cap.ischrome && e.which == 0) return self.onmouseup(e);
20490
20491              self.cursorfreezed = true;
20492              self.hasmoving = true;
20493
20494              if (self.rail.drag.hr) {
20495                self.scroll.x = self.rail.drag.sx + (e.clientX - self.rail.drag.x);
20496                if (self.scroll.x < 0) self.scroll.x = 0;
20497                var mw = self.scrollvaluemaxw;
20498                if (self.scroll.x > mw) self.scroll.x = mw;
20499              } else {
20500                self.scroll.y = self.rail.drag.sy + (e.clientY - self.rail.drag.y);
20501                if (self.scroll.y < 0) self.scroll.y = 0;
20502                var my = self.scrollvaluemax;
20503                if (self.scroll.y > my) self.scroll.y = my;
20504              }
20505
20506              self.synched('mousemove', function() {
20507                if (self.rail.drag && (self.rail.drag.pt == 1)) {
20508                  self.showCursor();
20509                  if (self.rail.drag.hr) {
20510                    if (self.hasreversehr) {
20511                      self.doScrollLeft(self.scrollvaluemaxw-Math.round(self.scroll.x * self.scrollratio.x), self.opt.cursordragspeed);
20512                    } else {
20513                      self.doScrollLeft(Math.round(self.scroll.x * self.scrollratio.x), self.opt.cursordragspeed);
20514                    }
20515                  }
20516                  else self.doScrollTop(Math.round(self.scroll.y * self.scrollratio.y), self.opt.cursordragspeed);
20517                }
20518              });
20519
20520              return self.cancelEvent(e);
20521            }
20522            else {
20523              self.checkarea = 0;
20524            }
20525          };
20526
20527          if (cap.cantouch || self.opt.touchbehavior) {
20528
20529            self.onpreventclick = function(e) {
20530              if (self.preventclick) {
20531                self.preventclick.tg.onclick = self.preventclick.click;
20532                self.preventclick = false;
20533                return self.cancelEvent(e);
20534              }
20535            }
20536
20537            self.bind(self.win, "mousedown", self.ontouchstart); // control content dragging
20538
20539            self.onclick = (cap.isios) ? false : function(e) {
20540              if (self.lastmouseup) {
20541                self.lastmouseup = false;
20542                return self.cancelEvent(e);
20543              } else {
20544                return true;
20545              }
20546            };
20547
20548            if (self.opt.grabcursorenabled && cap.cursorgrabvalue) {
20549              self.css((self.ispage) ? self.doc : self.win, {
20550                'cursor': cap.cursorgrabvalue
20551              });
20552              self.css(self.rail, {
20553                'cursor': cap.cursorgrabvalue
20554              });
20555            }
20556
20557          } else {
20558
20559            var checkSelectionScroll = function(e) {
20560              if (!self.selectiondrag) return;
20561
20562              if (e) {
20563                var ww = self.win.outerHeight();
20564                var df = (e.pageY - self.selectiondrag.top);
20565                if (df > 0 && df < ww) df = 0;
20566                if (df >= ww) df -= ww;
20567                self.selectiondrag.df = df;
20568              }
20569              if (self.selectiondrag.df == 0) return;
20570
20571              var rt = -Math.floor(self.selectiondrag.df / 6) * 2;
20572              self.doScrollBy(rt);
20573
20574              self.debounced("doselectionscroll", function() {
20575                checkSelectionScroll()
20576              }, 50);
20577            };
20578
20579            if ("getSelection" in document) { // A grade - Major browsers
20580              self.hasTextSelected = function() {
20581                return (document.getSelection().rangeCount > 0);
20582              };
20583            } else if ("selection" in document) { //IE9-
20584              self.hasTextSelected = function() {
20585                return (document.selection.type != "None");
20586              };
20587            } else {
20588              self.hasTextSelected = function() { // no support
20589                return false;
20590              };
20591            }
20592
20593            self.onselectionstart = function(e) {
20594/*  More testing - severe chrome issues            
20595              if (!self.haswrapper&&(e.which&&e.which==2)) {  // fool browser to manage middle button scrolling
20596                self.win.css({'overflow':'auto'});
20597                setTimeout(function(){
20598                  self.win.css({'overflow':''});
20599                },10);                
20600                return true;
20601              }            
20602*/              
20603              if (self.ispage) return;
20604              self.selectiondrag = self.win.offset();
20605            };
20606            
20607            self.onselectionend = function(e) {
20608              self.selectiondrag = false;
20609            };
20610            self.onselectiondrag = function(e) {
20611              if (!self.selectiondrag) return;
20612              if (self.hasTextSelected()) self.debounced("selectionscroll", function() {
20613                checkSelectionScroll(e)
20614              }, 250);
20615            };
20616
20617
20618          }
20619
20620          if (cap.hasw3ctouch) { //IE11+
20621            self.css(self.rail, {
20622              'touch-action': 'none'
20623            });
20624            self.css(self.cursor, {
20625              'touch-action': 'none'
20626            });
20627            self.bind(self.win, "pointerdown", self.ontouchstart);
20628            self.bind(document, "pointerup", self.ontouchend);
20629            self.bind(document, "pointermove", self.ontouchmove);
20630          } else if (cap.hasmstouch) { //IE10
20631            self.css(self.rail, {
20632              '-ms-touch-action': 'none'
20633            });
20634            self.css(self.cursor, {
20635              '-ms-touch-action': 'none'
20636            });
20637            self.bind(self.win, "MSPointerDown", self.ontouchstart);
20638            self.bind(document, "MSPointerUp", self.ontouchend);
20639            self.bind(document, "MSPointerMove", self.ontouchmove);
20640            self.bind(self.cursor, "MSGestureHold", function(e) {
20641              e.preventDefault()
20642            });
20643            self.bind(self.cursor, "contextmenu", function(e) {
20644              e.preventDefault()
20645            });
20646          } else if (this.istouchcapable) { //desktop with screen touch enabled
20647            self.bind(self.win, "touchstart", self.ontouchstart);
20648            self.bind(document, "touchend", self.ontouchend);
20649            self.bind(document, "touchcancel", self.ontouchend);
20650            self.bind(document, "touchmove", self.ontouchmove);
20651          }
20652
20653          
20654          if (self.opt.cursordragontouch || (!cap.cantouch && !self.opt.touchbehavior)) {
20655
20656            self.rail.css({
20657              "cursor": "default"
20658            });
20659            self.railh && self.railh.css({
20660              "cursor": "default"
20661            });
20662
20663            self.jqbind(self.rail, "mouseenter", function() {
20664              if (!self.ispage && !self.win.is(":visible")) return false;
20665              if (self.canshowonmouseevent) self.showCursor();
20666              self.rail.active = true;
20667            });
20668            self.jqbind(self.rail, "mouseleave", function() {
20669              self.rail.active = false;
20670              if (!self.rail.drag) self.hideCursor();
20671            });
20672
20673            if (self.opt.sensitiverail) {
20674              self.bind(self.rail, "click", function(e) {
20675                self.doRailClick(e, false, false)
20676              });
20677              self.bind(self.rail, "dblclick", function(e) {
20678                self.doRailClick(e, true, false)
20679              });
20680              self.bind(self.cursor, "click", function(e) {
20681                self.cancelEvent(e)
20682              });
20683              self.bind(self.cursor, "dblclick", function(e) {
20684                self.cancelEvent(e)
20685              });
20686            }
20687
20688            if (self.railh) {
20689              self.jqbind(self.railh, "mouseenter", function() {
20690                if (!self.ispage && !self.win.is(":visible")) return false;
20691                if (self.canshowonmouseevent) self.showCursor();
20692                self.rail.active = true;
20693              });
20694              self.jqbind(self.railh, "mouseleave", function() {
20695                self.rail.active = false;
20696                if (!self.rail.drag) self.hideCursor();
20697              });
20698
20699              if (self.opt.sensitiverail) {
20700                self.bind(self.railh, "click", function(e) {
20701                  self.doRailClick(e, false, true)
20702                });
20703                self.bind(self.railh, "dblclick", function(e) {
20704                  self.doRailClick(e, true, true)
20705                });
20706                self.bind(self.cursorh, "click", function(e) {
20707                  self.cancelEvent(e)
20708                });
20709                self.bind(self.cursorh, "dblclick", function(e) {
20710                  self.cancelEvent(e)
20711                });
20712              }
20713
20714            }
20715
20716          }
20717
20718          if (!cap.cantouch && !self.opt.touchbehavior) {
20719
20720            self.bind((cap.hasmousecapture) ? self.win : document, "mouseup", self.onmouseup);
20721            self.bind(document, "mousemove", self.onmousemove);
20722            if (self.onclick) self.bind(document, "click", self.onclick);
20723
20724            self.bind(self.cursor, "mousedown", self.onmousedown);
20725            self.bind(self.cursor, "mouseup", self.onmouseup);
20726
20727            if (self.railh) {
20728              self.bind(self.cursorh, "mousedown", function(e) {
20729                self.onmousedown(e, true)
20730              });
20731              self.bind(self.cursorh, "mouseup", self.onmouseup);
20732            }
20733            
20734            if (!self.ispage && self.opt.enablescrollonselection) {
20735              self.bind(self.win[0], "mousedown", self.onselectionstart);
20736              self.bind(document, "mouseup", self.onselectionend);
20737              self.bind(self.cursor, "mouseup", self.onselectionend);
20738              if (self.cursorh) self.bind(self.cursorh, "mouseup", self.onselectionend);
20739              self.bind(document, "mousemove", self.onselectiondrag);
20740            }
20741
20742            if (self.zoom) {
20743              self.jqbind(self.zoom, "mouseenter", function() {
20744                if (self.canshowonmouseevent) self.showCursor();
20745                self.rail.active = true;
20746              });
20747              self.jqbind(self.zoom, "mouseleave", function() {
20748                self.rail.active = false;
20749                if (!self.rail.drag) self.hideCursor();
20750              });
20751            }
20752
20753          } else {
20754
20755            self.bind((cap.hasmousecapture) ? self.win : document, "mouseup", self.ontouchend);
20756            self.bind(document, "mousemove", self.ontouchmove);
20757            if (self.onclick) self.bind(document, "click", self.onclick);
20758
20759            if (self.opt.cursordragontouch) {
20760              self.bind(self.cursor, "mousedown", self.onmousedown);
20761              self.bind(self.cursor, "mouseup", self.onmouseup);
20762              //self.bind(self.cursor, "mousemove", self.onmousemove);
20763              self.cursorh && self.bind(self.cursorh, "mousedown", function(e) {
20764                self.onmousedown(e, true)
20765              });
20766              //self.cursorh && self.bind(self.cursorh, "mousemove", self.onmousemove);
20767              self.cursorh && self.bind(self.cursorh, "mouseup", self.onmouseup);
20768            }
20769
20770          }
20771
20772          if (self.opt.enablemousewheel) {
20773            if (!self.isiframe) self.bind((cap.isie && self.ispage) ? document : self.win /*self.docscroll*/ , "mousewheel", self.onmousewheel);
20774            self.bind(self.rail, "mousewheel", self.onmousewheel);
20775            if (self.railh) self.bind(self.railh, "mousewheel", self.onmousewheelhr);
20776          }
20777
20778          if (!self.ispage && !cap.cantouch && !(/HTML|^BODY/.test(self.win[0].nodeName))) {
20779            if (!self.win.attr("tabindex")) self.win.attr({
20780              "tabindex": tabindexcounter++
20781            });
20782
20783            self.jqbind(self.win, "focus", function(e) {
20784              domfocus = (self.getTarget(e)).id || true;
20785              self.hasfocus = true;
20786              if (self.canshowonmouseevent) self.noticeCursor();
20787            });
20788            self.jqbind(self.win, "blur", function(e) {
20789              domfocus = false;
20790              self.hasfocus = false;
20791            });
20792
20793            self.jqbind(self.win, "mouseenter", function(e) {
20794              mousefocus = (self.getTarget(e)).id || true;
20795              self.hasmousefocus = true;
20796              if (self.canshowonmouseevent) self.noticeCursor();
20797            });
20798            self.jqbind(self.win, "mouseleave", function() {
20799              mousefocus = false;
20800              self.hasmousefocus = false;
20801              if (!self.rail.drag) self.hideCursor();
20802            });
20803
20804          }
20805
20806        } // !ie9mobile
20807
20808        //Thanks to http://www.quirksmode.org !!
20809        self.onkeypress = function(e) {
20810          if (self.railslocked && self.page.maxh == 0) return true;
20811
20812          e = (e) ? e : window.e;
20813          var tg = self.getTarget(e);
20814          if (tg && /INPUT|TEXTAREA|SELECT|OPTION/.test(tg.nodeName)) {
20815            var tp = tg.getAttribute('type') || tg.type || false;
20816            if ((!tp) || !(/submit|button|cancel/i.tp)) return true;
20817          }
20818
20819          if ($(tg).attr('contenteditable')) return true;
20820
20821          if (self.hasfocus || (self.hasmousefocus && !domfocus) || (self.ispage && !domfocus && !mousefocus)) {
20822            var key = e.keyCode;
20823
20824            if (self.railslocked && key != 27) return self.cancelEvent(e);
20825
20826            var ctrl = e.ctrlKey || false;
20827            var shift = e.shiftKey || false;
20828
20829            var ret = false;
vendor: 4,889 bytes, lines 20830-20959
20830            switch (key) {
20831              case 38:
20832              case 63233: //safari
20833                self.doScrollBy(24 * 3);
20834                ret = true;
20835                break;
20836              case 40:
20837              case 63235: //safari
20838                self.doScrollBy(-24 * 3);
20839                ret = true;
20840                break;
20841              case 37:
20842              case 63232: //safari
20843                if (self.railh) {
20844                  (ctrl) ? self.doScrollLeft(0): self.doScrollLeftBy(24 * 3);
20845                  ret = true;
20846                }
20847                break;
20848              case 39:
20849              case 63234: //safari
20850                if (self.railh) {
20851                  (ctrl) ? self.doScrollLeft(self.page.maxw): self.doScrollLeftBy(-24 * 3);
20852                  ret = true;
20853                }
20854                break;
20855              case 33:
20856              case 63276: // safari
20857                self.doScrollBy(self.view.h);
20858                ret = true;
20859                break;
20860              case 34:
20861              case 63277: // safari
20862                self.doScrollBy(-self.view.h);
20863                ret = true;
20864                break;
20865              case 36:
20866              case 63273: // safari                
20867                (self.railh && ctrl) ? self.doScrollPos(0, 0): self.doScrollTo(0);
20868                ret = true;
20869                break;
20870              case 35:
20871              case 63275: // safari
20872                (self.railh && ctrl) ? self.doScrollPos(self.page.maxw, self.page.maxh): self.doScrollTo(self.page.maxh);
20873                ret = true;
20874                break;
20875              case 32:
20876                if (self.opt.spacebarenabled) {
20877                  (shift) ? self.doScrollBy(self.view.h): self.doScrollBy(-self.view.h);
20878                  ret = true;
20879                }
20880                break;
20881              case 27: // ESC
20882                if (self.zoomactive) {
20883                  self.doZoom();
20884                  ret = true;
20885                }
20886                break;
20887            }
20888            if (ret) return self.cancelEvent(e);
20889          }
20890        };
20891
20892        if (self.opt.enablekeyboard) self.bind(document, (cap.isopera && !cap.isopera12) ? "keypress" : "keydown", self.onkeypress);
20893
20894        self.bind(document, "keydown", function(e) {
20895          var ctrl = e.ctrlKey || false;
20896          if (ctrl) self.wheelprevented = true;
20897        });
20898        self.bind(document, "keyup", function(e) {
20899          var ctrl = e.ctrlKey || false;
20900          if (!ctrl) self.wheelprevented = false;
20901        });
20902        self.bind(window,"blur",function(e){
20903          self.wheelprevented = false;
20904        });        
20905
20906        self.bind(window, 'resize', self.lazyResize);
20907        self.bind(window, 'orientationchange', self.lazyResize);
20908
20909        self.bind(window, "load", self.lazyResize);
20910
20911        if (cap.ischrome && !self.ispage && !self.haswrapper) { //chrome void scrollbar bug - it persists in version 26
20912          var tmp = self.win.attr("style");
20913          var ww = parseFloat(self.win.css("width")) + 1;
20914          self.win.css('width', ww);
20915          self.synched("chromefix", function() {
20916            self.win.attr("style", tmp)
20917          });
20918        }
20919
20920
20921        // Trying a cross-browser implementation - good luck!
20922
20923        self.onAttributeChange = function(e) {
20924          self.lazyResize(self.isieold ? 250 : 30);
20925        };
20926
20927        if (ClsMutationObserver !== false) {
20928          self.observerbody = new ClsMutationObserver(function(mutations) {
20929            mutations.forEach(function(mut){
20930              if (mut.type=="attributes") {
20931                return ($("body").hasClass("modal-open") && !$.contains($('.modal-dialog')[0],self.doc[0])) ? self.hide() : self.show();  // Support for Bootstrap modal; Added check if the nice scroll element is inside a modal
20932              }
20933            });  
20934            if (document.body.scrollHeight!=self.page.maxh) return self.lazyResize(30);
20935          });
20936          self.observerbody.observe(document.body, {
20937            childList: true,
20938            subtree: true,
20939            characterData: false,
20940            attributes: true,
20941            attributeFilter: ['class']
20942          });
20943        }
20944        
20945        if (!self.ispage && !self.haswrapper) {
20946          // redesigned MutationObserver for Chrome18+/Firefox14+/iOS6+ with support for: remove div, add/remove content
20947          if (ClsMutationObserver !== false) {
20948            self.observer = new ClsMutationObserver(function(mutations) {
20949              mutations.forEach(self.onAttributeChange);
20950            });
20951            self.observer.observe(self.win[0], {
20952              childList: true,
20953              characterData: false,
20954              attributes: true,
20955              subtree: false
20956            });
20957            self.observerremover = new ClsMutationObserver(function(mutations) {
20958              mutations.forEach(function(mo) {
20959                if (mo.removedNodes.length > 0) {
20960                  for (var dd in mo.removedNodes) {
20961                    if (!!self && (mo.removedNodes[dd] == self.win[0])) return self.remove();
20962                  }
20963                }
20964              });
20965            });
20966            self.observerremover.observe(self.win[0].parentNode, {
20967              childList: true,
20968              characterData: false,
20969              attributes: false,
20970              subtree: false
20971            });
20972          } else {
20973            self.bind(self.win, (cap.isie && !cap.isie9) ? "propertychange" : "DOMAttrModified", self.onAttributeChange);
20974            if (cap.isie9) self.win[0].attachEvent("onpropertychange", self.onAttributeChange); //IE9 DOMAttrModified bug
20975            self.bind(self.win, "DOMNodeRemoved", function(e) {
20976              if (e.target == self.win[0]) self.remove();
20977            });
20978          }
20979        }
20980
20981        //
20982
20983        if (!self.ispage && self.opt.boxzoom) self.bind(window, "resize", self.resizeZoom);
20984				if (self.istextarea) {
20985					self.bind(self.win, "keydown", self.lazyResize);
20986					self.bind(self.win, "mouseup", self.lazyResize);
20987				}
20988
20989        //        self.checkrtlmode = true;
20990        self.lazyResize(30);
20991
20992      }
20993      
20994      if (this.doc[0].nodeName == 'IFRAME') {
20995        var oniframeload = function() {
20996          self.iframexd = false;
20997          var doc;
20998          try {
20999            doc = 'contentDocument' in this ? this.contentDocument : this.contentWindow.document;
21000            var a = doc.domain;
21001          } catch (e) {
21002            self.iframexd = true;
21003            doc = false
21004          }
21005          
21006          if (self.iframexd) {
21007            if ("console" in window) console.log('NiceScroll error: policy restriced iframe');
21008            return true; //cross-domain - I can't manage this        
21009          }
21010
21011          self.forcescreen = true;
21012
21013          if (self.isiframe) {
21014            self.iframe = {
21015              "doc": $(doc),
21016              "html": self.doc.contents().find('html')[0],
21017              "body": self.doc.contents().find('body')[0]
21018            };
21019            self.getContentSize = function() {
21020              return {
21021                w: Math.max(self.iframe.html.scrollWidth, self.iframe.body.scrollWidth),
21022                h: Math.max(self.iframe.html.scrollHeight, self.iframe.body.scrollHeight)
21023              };
21024            };
21025            self.docscroll = $(self.iframe.body); //$(this.contentWindow);
21026          }
21027
21028          if (!cap.isios && self.opt.iframeautoresize && !self.isiframe) {
21029            self.win.scrollTop(0); // reset position
21030            self.doc.height(""); //reset height to fix browser bug
21031            var hh = Math.max(doc.getElementsByTagName('html')[0].scrollHeight, doc.body.scrollHeight);
21032            self.doc.height(hh);
21033          }
21034          self.lazyResize(30);
21035
21036          if (cap.isie7) self.css($(self.iframe.html), {
21037            'overflow-y': 'hidden'
21038          });
21039          self.css($(self.iframe.body), {
21040            'overflow-y': 'hidden'
21041          });
21042
21043          if (cap.isios && self.haswrapper) {
21044            self.css($(doc.body), {
21045              '-webkit-transform': 'translate3d(0,0,0)'
21046            }); // avoid iFrame content clipping - thanks to http://blog.derraab.com/2012/04/02/avoid-iframe-content-clipping-with-css-transform-on-ios/
21047          }
21048
21049          if ('contentWindow' in this) {
21050            self.bind(this.contentWindow, "scroll", self.onscroll); //IE8 & minor
21051          } else {
21052            self.bind(doc, "scroll", self.onscroll);
21053          }
21054
21055          if (self.opt.enablemousewheel) {
21056            self.bind(doc, "mousewheel", self.onmousewheel);
21057          }
21058
21059          if (self.opt.enablekeyboard) self.bind(doc, (cap.isopera) ? "keypress" : "keydown", self.onkeypress);
21060
21061          if (cap.cantouch || self.opt.touchbehavior) {
21062            self.bind(doc, "mousedown", self.ontouchstart);
21063            self.bind(doc, "mousemove", function(e) {
21064              return self.ontouchmove(e, true)
21065            });
21066            if (self.opt.grabcursorenabled && cap.cursorgrabvalue) self.css($(doc.body), {
21067              'cursor': cap.cursorgrabvalue
21068            });
21069          }
21070
21071          self.bind(doc, "mouseup", self.ontouchend);
21072
21073          if (self.zoom) {
21074            if (self.opt.dblclickzoom) self.bind(doc, 'dblclick', self.doZoom);
21075            if (self.ongesturezoom) self.bind(doc, "gestureend", self.ongesturezoom);
21076          }
21077        };
21078
21079        if (this.doc[0].readyState && this.doc[0].readyState == "complete") {
21080          setTimeout(function() {
21081            oniframeload.call(self.doc[0], false)
21082          }, 500);
21083        }
21084        self.bind(this.doc, "load", oniframeload);
21085
21086      }
21087
21088    };
21089
21090    this.showCursor = function(py, px) {
21091      if (self.cursortimeout) {
21092        clearTimeout(self.cursortimeout);
21093        self.cursortimeout = 0;
21094      }
21095      if (!self.rail) return;
21096      if (self.autohidedom) {
21097        self.autohidedom.stop().css({
21098          opacity: self.opt.cursoropacitymax
21099        });
21100        self.cursoractive = true;
21101      }
21102
21103      if (!self.rail.drag || self.rail.drag.pt != 1) {
21104        if ((typeof py != "undefined") && (py !== false)) {
21105          self.scroll.y = Math.round(py * 1 / self.scrollratio.y);
21106        }
21107        if (typeof px != "undefined") {
21108          self.scroll.x = Math.round(px * 1 / self.scrollratio.x);
21109        }
21110      }
21111
21112      self.cursor.css({
21113        height: self.cursorheight,
21114        top: self.scroll.y
21115      });
21116      if (self.cursorh) {        
21117        var lx = (self.hasreversehr) ? self.scrollvaluemaxw-self.scroll.x : self.scroll.x;
21118        (!self.rail.align && self.rail.visibility) ? self.cursorh.css({
21119          width: self.cursorwidth,
21120          left: lx + self.rail.width
21121        }): self.cursorh.css({
21122          width: self.cursorwidth,
21123          left: lx
21124        });
21125        self.cursoractive = true;
21126      }
21127
21128      if (self.zoom) self.zoom.stop().css({
21129        opacity: self.opt.cursoropacitymax
21130      });
21131    };
21132
21133    this.hideCursor = function(tm) {
21134      if (self.cursortimeout) return;
21135      if (!self.rail) return;
21136      if (!self.autohidedom) return;
21137      if (self.hasmousefocus && self.opt.autohidemode == "leave") return;
21138      self.cursortimeout = setTimeout(function() {
21139        if (!self.rail.active || !self.showonmouseevent) {
21140          self.autohidedom.stop().animate({
21141            opacity: self.opt.cursoropacitymin
21142          });
21143          if (self.zoom) self.zoom.stop().animate({
21144            opacity: self.opt.cursoropacitymin
21145          });
21146          self.cursoractive = false;
21147        }
21148        self.cursortimeout = 0;
21149      }, tm || self.opt.hidecursordelay);
21150    };
21151
21152    this.noticeCursor = function(tm, py, px) {
21153      self.showCursor(py, px);
21154      if (!self.rail.active) self.hideCursor(tm);
21155    };
21156
21157    this.getContentSize =
21158      (self.ispage) ?
21159      function() {
21160        return {
21161          w: Math.max(document.body.scrollWidth, document.documentElement.scrollWidth),
21162          h: Math.max(document.body.scrollHeight, document.documentElement.scrollHeight)
21163        }
21164      } : (self.haswrapper) ?
21165      function() {
21166        return {
21167          w: self.doc.outerWidth() + parseInt(self.win.css('paddingLeft')) + parseInt(self.win.css('paddingRight')),
21168          h: self.doc.outerHeight() + parseInt(self.win.css('paddingTop')) + parseInt(self.win.css('paddingBottom'))
21169        }
21170      } : function() {
21171        return {
21172          w: self.docscroll[0].scrollWidth,
21173          h: self.docscroll[0].scrollHeight
21174        }
21175      };
21176
21177    this.onResize = function(e, page) {
21178    
21179      if (!self || !self.win) return false;
21180
21181      if (!self.haswrapper && !self.ispage) {
21182        if (self.win.css('display') == 'none') {
21183          if (self.visibility) self.hideRail().hideRailHr();
21184          return false;
21185        } else {
21186          if (!self.hidden && !self.visibility) self.showRail().showRailHr();
21187        }
21188      }
21189
21190      var premaxh = self.page.maxh;
21191      var premaxw = self.page.maxw;
21192
21193      var preview = {
21194        h: self.view.h,
21195        w: self.view.w
21196      };
21197
21198      self.view = {
21199        w: (self.ispage) ? self.win.width() : parseInt(self.win[0].clientWidth),
21200        h: (self.ispage) ? self.win.height() : parseInt(self.win[0].clientHeight)
21201      };
21202
21203      self.page = (page) ? page : self.getContentSize();
21204
21205      self.page.maxh = Math.max(0, self.page.h - self.view.h);
21206      self.page.maxw = Math.max(0, self.page.w - self.view.w);
21207      
21208      if ((self.page.maxh == premaxh) && (self.page.maxw == premaxw) && (self.view.w == preview.w) && (self.view.h == preview.h)) {
21209        // test position        
21210        if (!self.ispage) {
21211          var pos = self.win.offset();
21212          if (self.lastposition) {
21213            var lst = self.lastposition;
21214            if ((lst.top == pos.top) && (lst.left == pos.left)) return self; //nothing to do            
21215          }
21216          self.lastposition = pos;
21217        } else {
21218          return self; //nothing to do
21219        }
21220      }
21221
21222      if (self.page.maxh == 0) {
21223        self.hideRail();
21224        self.scrollvaluemax = 0;
21225        self.scroll.y = 0;
21226        self.scrollratio.y = 0;
21227        self.cursorheight = 0;
21228        self.setScrollTop(0);
21229        if (self.rail) self.rail.scrollable = false;
21230      } else {
21231        self.page.maxh -= (self.opt.railpadding.top + self.opt.railpadding.bottom);  //**
21232        self.rail.scrollable = true;
21233      }
21234
21235      if (self.page.maxw == 0) {
21236        self.hideRailHr();
21237        self.scrollvaluemaxw = 0;
21238        self.scroll.x = 0;
21239        self.scrollratio.x = 0;
21240        self.cursorwidth = 0;
21241        self.setScrollLeft(0);
21242        if (self.railh) {
21243          self.railh.scrollable = false;
21244        }
21245      } else {
21246          self.page.maxw -= (self.opt.railpadding.left + self.opt.railpadding.right);  //**
21247          if (self.railh) self.railh.scrollable = (self.opt.horizrailenabled);
21248      }
21249
21250      self.railslocked = (self.locked) || ((self.page.maxh == 0) && (self.page.maxw == 0));
21251      if (self.railslocked) {
21252        if (!self.ispage) self.updateScrollBar(self.view);
21253        return false;
21254      }
21255
21256      if (!self.hidden && !self.visibility) {
21257        self.showRail().showRailHr();
21258      }
21259      else if (self.railh && (!self.hidden && !self.railh.visibility)) self.showRailHr();
21260
21261      if (self.istextarea && self.win.css('resize') && self.win.css('resize') != 'none') self.view.h -= 20;
21262
21263      self.cursorheight = Math.min(self.view.h, Math.round(self.view.h * (self.view.h / self.page.h)));
21264      self.cursorheight = (self.opt.cursorfixedheight) ? self.opt.cursorfixedheight : Math.max(self.opt.cursorminheight, self.cursorheight);
21265
21266      self.cursorwidth = Math.min(self.view.w, Math.round(self.view.w * (self.view.w / self.page.w)));
21267      self.cursorwidth = (self.opt.cursorfixedheight) ? self.opt.cursorfixedheight : Math.max(self.opt.cursorminheight, self.cursorwidth);
21268
21269      self.scrollvaluemax = self.view.h - self.cursorheight - self.cursor.hborder - (self.opt.railpadding.top + self.opt.railpadding.bottom);  //**
21270
21271      if (self.railh) {
21272        self.railh.width = (self.page.maxh > 0) ? (self.view.w - self.rail.width) : self.view.w;
21273        self.scrollvaluemaxw = self.railh.width - self.cursorwidth - self.cursorh.wborder - (self.opt.railpadding.left + self.opt.railpadding.right);  //**
21274      }
21275
21276      /*
21277      if (self.checkrtlmode&&self.railh) {
21278        self.checkrtlmode = false;
21279        if (self.opt.rtlmode&&self.scroll.x==0) self.setScrollLeft(self.page.maxw);
21280      }
21281*/
21282
21283      if (!self.ispage) self.updateScrollBar(self.view);
21284
21285      self.scrollratio = {
21286        x: (self.page.maxw / self.scrollvaluemaxw),
21287        y: (self.page.maxh / self.scrollvaluemax)
21288      };
21289
21290      var sy = self.getScrollTop();
21291      if (sy > self.page.maxh) {
21292        self.doScrollTop(self.page.maxh);
21293      } else {
21294        self.scroll.y = Math.round(self.getScrollTop() * (1 / self.scrollratio.y));
21295        self.scroll.x = Math.round(self.getScrollLeft() * (1 / self.scrollratio.x));
21296        if (self.cursoractive) self.noticeCursor();
21297      }
21298
21299      if (self.scroll.y && (self.getScrollTop() == 0)) self.doScrollTo(Math.floor(self.scroll.y * self.scrollratio.y));
21300
21301      return self;
21302    };
21303
21304    this.resize = self.onResize;
21305
21306    this.lazyResize = function(tm) { // event debounce
21307      tm = (isNaN(tm)) ? 30 : tm;
21308      self.debounced('resize', self.resize, tm);
21309      return self;
21310    };
21311
21312    // modified by MDN https://developer.mozilla.org/en-US/docs/DOM/Mozilla_event_reference/wheel
21313    function _modernWheelEvent(dom, name, fn, bubble) {
21314      self._bind(dom, name, function(e) {
21315        var e = (e) ? e : window.event;
21316        var event = {
21317          original: e,
21318          target: e.target || e.srcElement,
21319          type: "wheel",
21320          deltaMode: e.type == "MozMousePixelScroll" ? 0 : 1,
21321          deltaX: 0,
21322          deltaZ: 0,
21323          preventDefault: function() {
21324            e.preventDefault ? e.preventDefault() : e.returnValue = false;
21325            return false;
21326          },
21327          stopImmediatePropagation: function() {
21328            (e.stopImmediatePropagation) ? e.stopImmediatePropagation(): e.cancelBubble = true;
21329          }
21330        };
21331
21332        if (name == "mousewheel") {
21333          event.deltaY = -1 / 40 * e.wheelDelta;
21334          e.wheelDeltaX && (event.deltaX = -1 / 40 * e.wheelDeltaX);
21335        } else {
21336          event.deltaY = e.detail;
21337        }
21338
21339        return fn.call(dom, event);
21340      }, bubble);
21341    };
21342
21343
21344
21345    this.jqbind = function(dom, name, fn) { // use jquery bind for non-native events (mouseenter/mouseleave)
21346      self.events.push({
21347        e: dom,
21348        n: name,
21349        f: fn,
21350        q: true
21351      });
21352      $(dom).bind(name, fn);
21353    };
21354
21355    this.bind = function(dom, name, fn, bubble) { // touch-oriented & fixing jquery bind
21356      var el = ("jquery" in dom) ? dom[0] : dom;
21357
21358      if (name == 'mousewheel') {
21359        if ("onwheel" in self.win) { // modern brosers & IE9 detection fix
21360          self._bind(el, "wheel", fn, bubble || false);
21361        } else {
21362          var wname = (typeof document.onmousewheel != "undefined") ? "mousewheel" : "DOMMouseScroll"; // older IE/Firefox
21363          _modernWheelEvent(el, wname, fn, bubble || false);
21364
21365          if (wname == "DOMMouseScroll") _modernWheelEvent(el, "MozMousePixelScroll", fn, bubble || false); // Firefox legacy
21366        }
21367      } else if (el.addEventListener) {
21368        if (cap.cantouch && /mouseup|mousedown|mousemove/.test(name)) { // touch device support
21369          var tt = (name == 'mousedown') ? 'touchstart' : (name == 'mouseup') ? 'touchend' : 'touchmove';
21370          self._bind(el, tt, function(e) {
21371            if (e.touches) {
21372              if (e.touches.length < 2) {
21373                var ev = (e.touches.length) ? e.touches[0] : e;
21374                ev.original = e;
21375                fn.call(this, ev);
21376              }
21377            } else if (e.changedTouches) {
21378              var ev = e.changedTouches[0];
21379              ev.original = e;
21380              fn.call(this, ev);
21381            } //blackberry
21382          }, bubble || false);
21383        }
21384        self._bind(el, name, fn, bubble || false);
21385        if (cap.cantouch && name == "mouseup") self._bind(el, "touchcancel", fn, bubble || false);
21386      } else {
21387        self._bind(el, name, function(e) {
21388          e = e || window.event || false;
21389          if (e) {
21390            if (e.srcElement) e.target = e.srcElement;
21391          }
21392          if (!("pageY" in e)) {
21393            e.pageX = e.clientX + document.documentElement.scrollLeft;
21394            e.pageY = e.clientY + document.documentElement.scrollTop;
21395          }
21396          return ((fn.call(el, e) === false) || bubble === false) ? self.cancelEvent(e) : true;
21397        });
21398      }
21399    };
21400
21401    if (cap.haseventlistener) {  // W3C standard model
21402      this._bind = function(el, name, fn, bubble) { // primitive bind
21403        self.events.push({
21404          e: el,
21405          n: name,
21406          f: fn,
21407          b: bubble,
21408          q: false
21409        });
21410        el.addEventListener(name, fn, bubble || false);
21411      };    
21412      this.cancelEvent = function(e) {
21413        if (!e) return false;
21414        var e = (e.original) ? e.original : e;
21415        e.preventDefault();
21416        e.stopPropagation();
21417        if (e.preventManipulation) e.preventManipulation(); //IE10
21418        return false;
21419      };
21420      this.stopPropagation = function(e) {
21421        if (!e) return false;
21422        var e = (e.original) ? e.original : e;
21423        e.stopPropagation();
21424        return false;
21425      };
21426      this._unbind = function(el, name, fn, bub) { // primitive unbind
21427        el.removeEventListener(name, fn, bub);
21428      };
21429    } else {  // old IE model
21430      this._bind = function(el, name, fn, bubble) { // primitive bind
21431        self.events.push({
21432          e: el,
21433          n: name,
21434          f: fn,
21435          b: bubble,
21436          q: false
21437        });
21438        if (el.attachEvent) {
21439          el.attachEvent("on" + name, fn);
21440        } else {
21441          el["on" + name] = fn;
21442        }
21443      };    
21444      // Thanks to http://www.switchonthecode.com !!
21445      this.cancelEvent = function(e) {
21446        var e = window.event || false;
21447        if (!e) return false;
21448        e.cancelBubble = true;
21449        e.cancel = true;
21450        e.returnValue = false;
21451        return false;
21452      };
21453      this.stopPropagation = function(e) {
21454        var e = window.event || false;
21455        if (!e) return false;
21456        e.cancelBubble = true;
21457        return false;
21458      };
21459      this._unbind = function(el, name, fn, bub) { // primitive unbind IE old
21460        if (el.detachEvent) {
21461          el.detachEvent('on' + name, fn);
21462        } else {
21463          el['on' + name] = false;
21464        }
21465      };
21466    }
21467    
21468    this.unbindAll = function() {
21469      for (var a = 0; a < self.events.length; a++) {
21470        var r = self.events[a];
21471        (r.q) ? r.e.unbind(r.n, r.f): self._unbind(r.e, r.n, r.f, r.b);
21472      }
21473    };
21474
21475    this.showRail = function() {
21476      if ((self.page.maxh != 0) && (self.ispage || self.win.css('display') != 'none')) {
21477        self.visibility = true;
21478        self.rail.visibility = true;
21479        self.rail.css('display', 'block');
21480      }
21481      return self;
21482    };
21483
21484    this.showRailHr = function() {
21485      if (!self.railh) return self;
21486      if ((self.page.maxw != 0) && (self.ispage || self.win.css('display') != 'none')) {
21487        self.railh.visibility = true;
21488        self.railh.css('display', 'block');
21489      }
21490      return self;
21491    };
21492
21493    this.hideRail = function() {
21494      self.visibility = false;
21495      self.rail.visibility = false;
21496      self.rail.css('display', 'none');
21497      return self;
21498    };
21499
21500    this.hideRailHr = function() {
21501      if (!self.railh) return self;
21502      self.railh.visibility = false;
21503      self.railh.css('display', 'none');
21504      return self;
21505    };
21506
21507    this.show = function() {
21508      self.hidden = false;
21509      self.railslocked = false;
21510      return self.showRail().showRailHr();
21511    };
21512
21513    this.hide = function() {
21514      self.hidden = true;
21515      self.railslocked = true;
21516      return self.hideRail().hideRailHr();
21517    };
21518
21519    this.toggle = function() {
21520      return (self.hidden) ? self.show() : self.hide();
21521    };
21522
21523    this.remove = function() {
21524      self.stop();
21525      if (self.cursortimeout) clearTimeout(self.cursortimeout);
21526      if (self.debouncedelayed) clearTimeout(self.debouncedelayed);
21527      self.doZoomOut();
21528      self.unbindAll();
21529
21530      if (cap.isie9) self.win[0].detachEvent("onpropertychange", self.onAttributeChange); //IE9 DOMAttrModified bug
21531
21532      if (self.observer !== false) self.observer.disconnect();
21533      if (self.observerremover !== false) self.observerremover.disconnect();
21534      if (self.observerbody !== false) self.observerbody.disconnect();
21535
21536      self.events = null;
21537
21538      if (self.cursor) {
21539        self.cursor.remove();
21540      }
21541      if (self.cursorh) {
21542        self.cursorh.remove();
21543      }
21544      if (self.rail) {
21545        self.rail.remove();
21546      }
21547      if (self.railh) {
21548        self.railh.remove();
21549      }
21550      if (self.zoom) {
21551        self.zoom.remove();
21552      }
21553      for (var a = 0; a < self.saved.css.length; a++) {
21554        var d = self.saved.css[a];
21555        d[0].css(d[1], (typeof d[2] == "undefined") ? '' : d[2]);
21556      }
21557      self.saved = false;
21558      self.me.data('__nicescroll', ''); //erase all traces
21559
21560      // memory leak fixed by GianlucaGuarini - thanks a lot!
21561      // remove the current nicescroll from the $.nicescroll array & normalize array
21562      var lst = $.nicescroll;
21563      lst.each(function(i) {
21564        if (!this) return;
21565        if (this.id === self.id) {
21566          delete lst[i];
21567          for (var b = ++i; b < lst.length; b++, i++) lst[i] = lst[b];
21568          lst.length--;
21569          if (lst.length) delete lst[lst.length];
21570        }
21571      });
21572
21573      for (var i in self) {
21574        self[i] = null;
21575        delete self[i];
21576      }
21577
21578      self = null;
21579
21580    };
21581
21582    this.scrollstart = function(fn) {
21583      this.onscrollstart = fn;
21584      return self;
21585    };
21586    this.scrollend = function(fn) {
21587      this.onscrollend = fn;
21588      return self;
21589    };
21590    this.scrollcancel = function(fn) {
21591      this.onscrollcancel = fn;
21592      return self;
21593    };
21594
21595    this.zoomin = function(fn) {
21596      this.onzoomin = fn;
21597      return self;
21598    };
21599    this.zoomout = function(fn) {
21600      this.onzoomout = fn;
21601      return self;
21602    };
21603
21604    this.isScrollable = function(e) {
21605      var dom = (e.target) ? e.target : e;
21606      if (dom.nodeName == 'OPTION') return true;
21607      while (dom && (dom.nodeType == 1) && !(/^BODY|HTML/.test(dom.nodeName))) {
21608        var dd = $(dom);
21609        var ov = dd.css('overflowY') || dd.css('overflowX') || dd.css('overflow') || '';
21610        if (/scroll|auto/.test(ov)) return (dom.clientHeight != dom.scrollHeight);
21611        dom = (dom.parentNode) ? dom.parentNode : false;
21612      }
21613      return false;
21614    };
21615
21616    this.getViewport = function(me) {
21617      var dom = (me && me.parentNode) ? me.parentNode : false;
21618      while (dom && (dom.nodeType == 1) && !(/^BODY|HTML/.test(dom.nodeName))) {
21619        var dd = $(dom);
21620        if (/fixed|absolute/.test(dd.css("position"))) return dd;
21621        var ov = dd.css('overflowY') || dd.css('overflowX') || dd.css('overflow') || '';
21622        if ((/scroll|auto/.test(ov)) && (dom.clientHeight != dom.scrollHeight)) return dd;
21623        if (dd.getNiceScroll().length > 0) return dd;
21624        dom = (dom.parentNode) ? dom.parentNode : false;
21625      }
21626      return false; //(dom) ? $(dom) : false;
21627    };
21628
21629    this.triggerScrollEnd = function() {
21630      if (!self.onscrollend) return;
21631
21632      var px = self.getScrollLeft();
21633      var py = self.getScrollTop();
21634
21635      var info = {
21636        "type": "scrollend",
21637        "current": {
21638          "x": px,
21639          "y": py
21640        },
21641        "end": {
21642          "x": px,
21643          "y": py
21644        }
21645      };
21646      self.onscrollend.call(self, info);
21647    }
21648
21649    function execScrollWheel(e, hr, chkscroll) {
21650      var px, py;
21651      
21652      if (e.deltaMode == 0) { // PIXEL
21653        px = -Math.floor(e.deltaX * (self.opt.mousescrollstep / (18 * 3)));
21654        py = -Math.floor(e.deltaY * (self.opt.mousescrollstep / (18 * 3)));
21655      } else if (e.deltaMode == 1) { // LINE
21656        px = -Math.floor(e.deltaX * self.opt.mousescrollstep);
21657        py = -Math.floor(e.deltaY * self.opt.mousescrollstep);
21658      }
21659
21660      if (hr && self.opt.oneaxismousemode && (px == 0) && py) { // classic vertical-only mousewheel + browser with x/y support 
21661        px = py;
21662        py = 0;
21663      
21664        if (chkscroll) {
21665          var hrend = (px < 0) ? (self.getScrollLeft() >= self.page.maxw) : (self.getScrollLeft() <= 0);
21666          if (hrend) {  // preserve vertical scrolling
21667            py = px;
21668            px = 0;            
21669          }
21670        }
21671        
21672      }
21673
21674      if (px) {
21675        if (self.scrollmom) {
21676          self.scrollmom.stop()
21677        }
21678        self.lastdeltax += px;
21679        self.debounced("mousewheelx", function() {
21680          var dt = self.lastdeltax;
21681          self.lastdeltax = 0;
21682          if (!self.rail.drag) {
21683            self.doScrollLeftBy(dt)
21684          }
21685        }, 15);
21686      }
21687      if (py) {
21688        if (self.opt.nativeparentscrolling && chkscroll && !self.ispage && !self.zoomactive) {
21689          if (py < 0) {
21690            if (self.getScrollTop() >= self.page.maxh) return true;
21691          } else {
21692            if (self.getScrollTop() <= 0) return true;
21693          }
21694        }
21695        if (self.scrollmom) {
21696          self.scrollmom.stop()
21697        }
21698        self.lastdeltay += py;
21699        self.debounced("mousewheely", function() {
21700          var dt = self.lastdeltay;
21701          self.lastdeltay = 0;
21702          if (!self.rail.drag) {
21703            self.doScrollBy(dt)
21704          }
21705        }, 15);
21706      }
21707
21708      e.stopImmediatePropagation();
21709      return e.preventDefault();
21710    };
21711
21712    this.onmousewheel = function(e) {
21713      if (self.wheelprevented) return;
21714      if (self.railslocked) {
21715        self.debounced("checkunlock", self.resize, 250);
21716        return true;
21717      }
21718      if (self.rail.drag) return self.cancelEvent(e);
21719
21720      if (self.opt.oneaxismousemode == "auto" && e.deltaX != 0) self.opt.oneaxismousemode = false; // check two-axis mouse support (not very elegant)
21721
21722      if (self.opt.oneaxismousemode && e.deltaX == 0) {
21723        if (!self.rail.scrollable) {
21724          if (self.railh && self.railh.scrollable) {
21725            return self.onmousewheelhr(e);
21726          } else {
21727            return true;
21728          }
21729        }
21730      }
21731
21732      var nw = +(new Date());
21733      var chk = false;
21734      if (self.opt.preservenativescrolling && ((self.checkarea + 600) < nw)) {
21735        self.nativescrollingarea = self.isScrollable(e);
21736        chk = true;
21737      }
21738      self.checkarea = nw;
21739      if (self.nativescrollingarea) return true; // this isn't my business
21740      var ret = execScrollWheel(e, false, chk);
21741      if (ret) self.checkarea = 0;
21742      return ret;
21743    };
21744
21745    this.onmousewheelhr = function(e) {
21746      if (self.wheelprevented) return;
21747      if (self.railslocked || !self.railh.scrollable) return true;
21748      if (self.rail.drag) return self.cancelEvent(e);
21749
21750      var nw = +(new Date());
21751      var chk = false;
21752      if (self.opt.preservenativescrolling && ((self.checkarea + 600) < nw)) {
21753        self.nativescrollingarea = self.isScrollable(e);
21754        chk = true;
21755      }
21756      self.checkarea = nw;
21757      if (self.nativescrollingarea) return true; // this isn't my business
21758      if (self.railslocked) return self.cancelEvent(e);
21759
21760      return execScrollWheel(e, true, chk);
21761    };
21762
21763    this.stop = function() {
21764      self.cancelScroll();
21765      if (self.scrollmon) self.scrollmon.stop();
21766      self.cursorfreezed = false;
21767      self.scroll.y = Math.round(self.getScrollTop() * (1 / self.scrollratio.y));
21768      self.noticeCursor();
21769      return self;
21770    };
21771
21772    this.getTransitionSpeed = function(dif) {
21773      var sp = Math.round(self.opt.scrollspeed * 10);
21774      var ex = Math.min(sp, Math.round((dif / 20) * self.opt.scrollspeed));
21775      return (ex > 20) ? ex : 0;
21776    };
21777
21778    if (!self.opt.smoothscroll) {
21779      this.doScrollLeft = function(x, spd) { //direct
21780        var y = self.getScrollTop();
21781        self.doScrollPos(x, y, spd);
21782      };
21783      this.doScrollTop = function(y, spd) { //direct
21784        var x = self.getScrollLeft();
21785        self.doScrollPos(x, y, spd);
21786      };
21787      this.doScrollPos = function(x, y, spd) { //direct
21788        var nx = (x > self.page.maxw) ? self.page.maxw : x;
21789        if (nx < 0) nx = 0;
21790        var ny = (y > self.page.maxh) ? self.page.maxh : y;
21791        if (ny < 0) ny = 0;
21792        self.synched('scroll', function() {
21793          self.setScrollTop(ny);
21794          self.setScrollLeft(nx);
21795        });
21796      };
21797      this.cancelScroll = function() {}; // direct
21798    } else if (self.ishwscroll && cap.hastransition && self.opt.usetransition && !!self.opt.smoothscroll) {
21799      this.prepareTransition = function(dif, istime) {
21800        var ex = (istime) ? ((dif > 20) ? dif : 0) : self.getTransitionSpeed(dif);
21801        var trans = (ex) ? cap.prefixstyle + 'transform ' + ex + 'ms ease-out' : '';
21802        if (!self.lasttransitionstyle || self.lasttransitionstyle != trans) {
21803          self.lasttransitionstyle = trans;
21804          self.doc.css(cap.transitionstyle, trans);
21805        }
21806        return ex;
21807      };
21808
21809      this.doScrollLeft = function(x, spd) { //trans
21810        var y = (self.scrollrunning) ? self.newscrolly : self.getScrollTop();
21811        self.doScrollPos(x, y, spd);
21812      };
21813
21814      this.doScrollTop = function(y, spd) { //trans
21815        var x = (self.scrollrunning) ? self.newscrollx : self.getScrollLeft();
21816        self.doScrollPos(x, y, spd);
21817      };
21818
21819      this.doScrollPos = function(x, y, spd) { //trans
21820
21821        var py = self.getScrollTop();
21822        var px = self.getScrollLeft();
21823
21824        if (((self.newscrolly - py) * (y - py) < 0) || ((self.newscrollx - px) * (x - px) < 0)) self.cancelScroll(); //inverted movement detection      
21825
21826        if (self.opt.bouncescroll == false) {
21827          if (y < 0) y = 0;
21828          else if (y > self.page.maxh) y = self.page.maxh;
21829          if (x < 0) x = 0;
21830          else if (x > self.page.maxw) x = self.page.maxw;
21831        }
21832
21833        if (self.scrollrunning && x == self.newscrollx && y == self.newscrolly) return false;
21834
21835        self.newscrolly = y;
21836        self.newscrollx = x;
21837
21838        self.newscrollspeed = spd || false;
21839
21840        if (self.timer) return false;
21841
21842        self.timer = setTimeout(function() {
21843
21844          var top = self.getScrollTop();
21845          var lft = self.getScrollLeft();
21846
21847          var dst = {};
21848          dst.x = x - lft;
21849          dst.y = y - top;
21850          dst.px = lft;
21851          dst.py = top;
21852
21853          var dd = Math.round(Math.sqrt(Math.pow(dst.x, 2) + Math.pow(dst.y, 2)));
21854          var ms = (self.newscrollspeed && self.newscrollspeed > 1) ? self.newscrollspeed : self.getTransitionSpeed(dd);
21855          if (self.newscrollspeed && self.newscrollspeed <= 1) ms *= self.newscrollspeed;
21856
21857          self.prepareTransition(ms, true);
21858
21859          if (self.timerscroll && self.timerscroll.tm) clearInterval(self.timerscroll.tm);
21860
21861          if (ms > 0) {
21862
21863            if (!self.scrollrunning && self.onscrollstart) {
21864              var info = {
21865                "type": "scrollstart",
21866                "current": {
21867                  "x": lft,
21868                  "y": top
21869                },
21870                "request": {
21871                  "x": x,
21872                  "y": y
21873                },
21874                "end": {
21875                  "x": self.newscrollx,
21876                  "y": self.newscrolly
21877                },
21878                "speed": ms
21879              };
21880              self.onscrollstart.call(self, info);
21881            }
21882
21883            if (cap.transitionend) {
21884              if (!self.scrollendtrapped) {
21885                self.scrollendtrapped = true;
21886                self.bind(self.doc, cap.transitionend, self.onScrollTransitionEnd, false); //I have got to do something usefull!!
21887              }
21888            } else {
21889              if (self.scrollendtrapped) clearTimeout(self.scrollendtrapped);
21890              self.scrollendtrapped = setTimeout(self.onScrollTransitionEnd, ms); // simulate transitionend event
21891            }
21892
21893            var py = top;
21894            var px = lft;
21895            self.timerscroll = {
21896              bz: new BezierClass(py, self.newscrolly, ms, 0, 0, 0.58, 1),
21897              bh: new BezierClass(px, self.newscrollx, ms, 0, 0, 0.58, 1)
21898            };
21899            if (!self.cursorfreezed) self.timerscroll.tm = setInterval(function() {
21900              self.showCursor(self.getScrollTop(), self.getScrollLeft())
21901            }, 60);
21902
21903          }
21904
21905          self.synched("doScroll-set", function() {
21906            self.timer = 0;
21907            if (self.scrollendtrapped) self.scrollrunning = true;
21908            self.setScrollTop(self.newscrolly);
21909            self.setScrollLeft(self.newscrollx);
21910            if (!self.scrollendtrapped) self.onScrollTransitionEnd();
21911          });
21912
21913
21914        }, 50);
21915
21916      };
21917
21918      this.cancelScroll = function() {
21919        if (!self.scrollendtrapped) return true;
21920        var py = self.getScrollTop();
21921        var px = self.getScrollLeft();
21922        self.scrollrunning = false;
21923        if (!cap.transitionend) clearTimeout(cap.transitionend);
21924        self.scrollendtrapped = false;
21925        self._unbind(self.doc[0], cap.transitionend, self.onScrollTransitionEnd);
21926        self.prepareTransition(0);
21927        self.setScrollTop(py); // fire event onscroll
21928        if (self.railh) self.setScrollLeft(px);
21929        if (self.timerscroll && self.timerscroll.tm) clearInterval(self.timerscroll.tm);
21930        self.timerscroll = false;
21931
21932        self.cursorfreezed = false;
21933
21934        self.showCursor(py, px);
21935        return self;
21936      };
21937      this.onScrollTransitionEnd = function() {
21938        if (self.scrollendtrapped) self._unbind(self.doc[0], cap.transitionend, self.onScrollTransitionEnd);
21939        self.scrollendtrapped = false;
21940        self.prepareTransition(0);
21941        if (self.timerscroll && self.timerscroll.tm) clearInterval(self.timerscroll.tm);
21942        self.timerscroll = false;
21943        var py = self.getScrollTop();
21944        var px = self.getScrollLeft();
21945        self.setScrollTop(py); // fire event onscroll        
21946        if (self.railh) self.setScrollLeft(px); // fire event onscroll left
21947
21948        self.noticeCursor(false, py, px);
21949
21950        self.cursorfreezed = false;
21951
21952        if (py < 0) py = 0
21953        else if (py > self.page.maxh) py = self.page.maxh;
21954        if (px < 0) px = 0
21955        else if (px > self.page.maxw) px = self.page.maxw;
21956        if ((py != self.newscrolly) || (px != self.newscrollx)) return self.doScrollPos(px, py, self.opt.snapbackspeed);
21957
21958        if (self.onscrollend && self.scrollrunning) {
21959          self.triggerScrollEnd();
21960        }
21961        self.scrollrunning = false;
21962
21963      };
21964
21965    } else {
21966
21967      this.doScrollLeft = function(x, spd) { //no-trans
21968        var y = (self.scrollrunning) ? self.newscrolly : self.getScrollTop();
21969        self.doScrollPos(x, y, spd);
21970      };
21971
21972      this.doScrollTop = function(y, spd) { //no-trans
21973        var x = (self.scrollrunning) ? self.newscrollx : self.getScrollLeft();
21974        self.doScrollPos(x, y, spd);
21975      };
21976
21977      this.doScrollPos = function(x, y, spd) { //no-trans
21978        var y = ((typeof y == "undefined") || (y === false)) ? self.getScrollTop(true) : y;
21979
21980        if ((self.timer) && (self.newscrolly == y) && (self.newscrollx == x)) return true;
21981
21982        if (self.timer) clearAnimationFrame(self.timer);
21983        self.timer = 0;
21984
21985        var py = self.getScrollTop();
21986        var px = self.getScrollLeft();
21987
21988        if (((self.newscrolly - py) * (y - py) < 0) || ((self.newscrollx - px) * (x - px) < 0)) self.cancelScroll(); //inverted movement detection
21989
21990        self.newscrolly = y;
21991        self.newscrollx = x;
21992
21993        if (!self.bouncescroll || !self.rail.visibility) {
21994          if (self.newscrolly < 0) {
21995            self.newscrolly = 0;
21996          } else if (self.newscrolly > self.page.maxh) {
21997            self.newscrolly = self.page.maxh;
21998          }
21999        }
22000        if (!self.bouncescroll || !self.railh.visibility) {
22001          if (self.newscrollx < 0) {
22002            self.newscrollx = 0;
22003          } else if (self.newscrollx > self.page.maxw) {
22004            self.newscrollx = self.page.maxw;
22005          }
22006        }
22007
22008        self.dst = {};
22009        self.dst.x = x - px;
22010        self.dst.y = y - py;
22011        self.dst.px = px;
22012        self.dst.py = py;
22013
22014        var dst = Math.round(Math.sqrt(Math.pow(self.dst.x, 2) + Math.pow(self.dst.y, 2)));
22015
22016        self.dst.ax = self.dst.x / dst;
22017        self.dst.ay = self.dst.y / dst;
22018
22019        var pa = 0;
22020        var pe = dst;
22021
22022        if (self.dst.x == 0) {
22023          pa = py;
22024          pe = y;
22025          self.dst.ay = 1;
22026          self.dst.py = 0;
22027        } else if (self.dst.y == 0) {
22028          pa = px;
22029          pe = x;
22030          self.dst.ax = 1;
22031          self.dst.px = 0;
22032        }
22033
22034        var ms = self.getTransitionSpeed(dst);
22035        if (spd && spd <= 1) ms *= spd;
22036        if (ms > 0) {
22037          self.bzscroll = (self.bzscroll) ? self.bzscroll.update(pe, ms) : new BezierClass(pa, pe, ms, 0, 1, 0, 1);
22038        } else {
22039          self.bzscroll = false;
22040        }
22041
22042        if (self.timer) return;
22043
22044        if ((py == self.page.maxh && y >= self.page.maxh) || (px == self.page.maxw && x >= self.page.maxw)) self.checkContentSize();
22045
22046        var sync = 1;
22047
22048        function scrolling() {
22049          if (self.cancelAnimationFrame) return true;
22050
22051          self.scrollrunning = true;
22052
22053          sync = 1 - sync;
22054          if (sync) return (self.timer = setAnimationFrame(scrolling) || 1);
22055
22056          var done = 0;
22057          var sx, sy;
22058
22059          var sc = sy = self.getScrollTop();
22060          if (self.dst.ay) {
22061            sc = (self.bzscroll) ? self.dst.py + (self.bzscroll.getNow() * self.dst.ay) : self.newscrolly;
22062            var dr = sc - sy;
22063            if ((dr < 0 && sc < self.newscrolly) || (dr > 0 && sc > self.newscrolly)) sc = self.newscrolly;
22064            self.setScrollTop(sc);
22065            if (sc == self.newscrolly) done = 1;
22066          } else {
22067            done = 1;
22068          }
22069
22070          var scx = sx = self.getScrollLeft();
22071          if (self.dst.ax) {
22072            scx = (self.bzscroll) ? self.dst.px + (self.bzscroll.getNow() * self.dst.ax) : self.newscrollx;
22073            var dr = scx - sx;
22074            if ((dr < 0 && scx < self.newscrollx) || (dr > 0 && scx > self.newscrollx)) scx = self.newscrollx;
22075            self.setScrollLeft(scx);
22076            if (scx == self.newscrollx) done += 1;
22077          } else {
22078            done += 1;
22079          }
22080
22081          if (done == 2) {
22082            self.timer = 0;
22083            self.cursorfreezed = false;
22084            self.bzscroll = false;
22085            self.scrollrunning = false;
22086            if (sc < 0) sc = 0;
22087            else if (sc > self.page.maxh) sc = self.page.maxh;
22088            if (scx < 0) scx = 0;
22089            else if (scx > self.page.maxw) scx = self.page.maxw;
22090            if ((scx != self.newscrollx) || (sc != self.newscrolly)) self.doScrollPos(scx, sc);
22091            else {
22092              if (self.onscrollend) {
22093                self.triggerScrollEnd();
22094              }
22095            }
22096          } else {
22097            self.timer = setAnimationFrame(scrolling) || 1;
22098          }
22099        };
22100        self.cancelAnimationFrame = false;
22101        self.timer = 1;
22102
22103        if (self.onscrollstart && !self.scrollrunning) {
22104          var info = {
22105            "type": "scrollstart",
22106            "current": {
22107              "x": px,
22108              "y": py
22109            },
22110            "request": {
22111              "x": x,
22112              "y": y
22113            },
22114            "end": {
22115              "x": self.newscrollx,
22116              "y": self.newscrolly
22117            },
22118            "speed": ms
22119          };
22120          self.onscrollstart.call(self, info);
22121        }
22122
22123        scrolling();
22124
22125        if ((py == self.page.maxh && y >= py) || (px == self.page.maxw && x >= px)) self.checkContentSize();
22126
22127        self.noticeCursor();
22128      };
22129
22130      this.cancelScroll = function() {
22131        if (self.timer) clearAnimationFrame(self.timer);
22132        self.timer = 0;
22133        self.bzscroll = false;
22134        self.scrollrunning = false;
22135        return self;
22136      };
22137
22138    }
22139
22140    this.doScrollBy = function(stp, relative) {
22141      var ny = 0;
22142      if (relative) {
22143        ny = Math.floor((self.scroll.y - stp) * self.scrollratio.y)
22144      } else {
22145        var sy = (self.timer) ? self.newscrolly : self.getScrollTop(true);
22146        ny = sy - stp;
22147      }
22148      if (self.bouncescroll) {
22149        var haf = Math.round(self.view.h / 2);
22150        if (ny < -haf) ny = -haf
22151        else if (ny > (self.page.maxh + haf)) ny = (self.page.maxh + haf);
22152      }
22153      self.cursorfreezed = false;
22154
22155      var py = self.getScrollTop(true);
22156      if (ny < 0 && py <= 0) return self.noticeCursor();
22157      else if (ny > self.page.maxh && py >= self.page.maxh) {
22158        self.checkContentSize();
22159        return self.noticeCursor();
22160      }
22161
22162      self.doScrollTop(ny);
22163    };
22164
22165    this.doScrollLeftBy = function(stp, relative) {
22166      var nx = 0;
22167      if (relative) {
22168        nx = Math.floor((self.scroll.x - stp) * self.scrollratio.x)
22169      } else {
22170        var sx = (self.timer) ? self.newscrollx : self.getScrollLeft(true);
22171        nx = sx - stp;
22172      }
22173      if (self.bouncescroll) {
22174        var haf = Math.round(self.view.w / 2);
22175        if (nx < -haf) nx = -haf;
22176        else if (nx > (self.page.maxw + haf)) nx = (self.page.maxw + haf);
22177      }
22178      self.cursorfreezed = false;
22179
22180      var px = self.getScrollLeft(true);
22181      if (nx < 0 && px <= 0) return self.noticeCursor();
22182      else if (nx > self.page.maxw && px >= self.page.maxw) return self.noticeCursor();
22183
22184      self.doScrollLeft(nx);
22185    };
22186
22187    this.doScrollTo = function(pos, relative) {
22188      var ny = (relative) ? Math.round(pos * self.scrollratio.y) : pos;
22189      if (ny < 0) ny = 0;
22190      else if (ny > self.page.maxh) ny = self.page.maxh;
22191      self.cursorfreezed = false;
22192      self.doScrollTop(pos);
22193    };
22194
22195    this.checkContentSize = function() {
22196      var pg = self.getContentSize();
22197      if ((pg.h != self.page.h) || (pg.w != self.page.w)) self.resize(false, pg);
22198    };
22199
22200    self.onscroll = function(e) {
22201      if (self.rail.drag) return;
22202      if (!self.cursorfreezed) {
22203        self.synched('scroll', function() {
22204          self.scroll.y = Math.round(self.getScrollTop() * (1 / self.scrollratio.y));
22205          if (self.railh) self.scroll.x = Math.round(self.getScrollLeft() * (1 / self.scrollratio.x));
22206          self.noticeCursor();
22207        });
22208      }
22209    };
22210    self.bind(self.docscroll, "scroll", self.onscroll);
22211
22212    this.doZoomIn = function(e) {
22213      if (self.zoomactive) return;
22214      self.zoomactive = true;
22215
22216      self.zoomrestore = {
22217        style: {}
22218      };
22219      var lst = ['position', 'top', 'left', 'zIndex', 'backgroundColor', 'marginTop', 'marginBottom', 'marginLeft', 'marginRight'];
22220      var win = self.win[0].style;
22221      for (var a in lst) {
22222        var pp = lst[a];
22223        self.zoomrestore.style[pp] = (typeof win[pp] != "undefined") ? win[pp] : '';
22224      }
22225
22226      self.zoomrestore.style.width = self.win.css('width');
22227      self.zoomrestore.style.height = self.win.css('height');
22228
22229      self.zoomrestore.padding = {
22230        w: self.win.outerWidth() - self.win.width(),
22231        h: self.win.outerHeight() - self.win.height()
22232      };
22233
22234      if (cap.isios4) {
22235        self.zoomrestore.scrollTop = $(window).scrollTop();
22236        $(window).scrollTop(0);
22237      }
22238
22239      self.win.css({
22240        "position": (cap.isios4) ? "absolute" : "fixed",
22241        "top": 0,
22242        "left": 0,
22243        "z-index": globalmaxzindex + 100,
22244        "margin": "0px"
22245      });
22246      var bkg = self.win.css("backgroundColor");
vendor: 8,483 bytes, lines 22247-22561
22247      if (bkg == "" || /transparent|rgba\(0, 0, 0, 0\)|rgba\(0,0,0,0\)/.test(bkg)) self.win.css("backgroundColor", "#fff");
22248      self.rail.css({
22249        "z-index": globalmaxzindex + 101
22250      });
22251      self.zoom.css({
22252        "z-index": globalmaxzindex + 102
22253      });
22254      self.zoom.css('backgroundPosition', '0px -18px');
22255      self.resizeZoom();
22256
22257      if (self.onzoomin) self.onzoomin.call(self);
22258
22259      return self.cancelEvent(e);
22260    };
22261
22262    this.doZoomOut = function(e) {
22263      if (!self.zoomactive) return;
22264      self.zoomactive = false;
22265
22266      self.win.css("margin", "");
22267      self.win.css(self.zoomrestore.style);
22268
22269      if (cap.isios4) {
22270        $(window).scrollTop(self.zoomrestore.scrollTop);
22271      }
22272
22273      self.rail.css({
22274        "z-index": self.zindex
22275      });
22276      self.zoom.css({
22277        "z-index": self.zindex
22278      });
22279      self.zoomrestore = false;
22280      self.zoom.css('backgroundPosition', '0px 0px');
22281      self.onResize();
22282
22283      if (self.onzoomout) self.onzoomout.call(self);
22284
22285      return self.cancelEvent(e);
22286    };
22287
22288    this.doZoom = function(e) {
22289      return (self.zoomactive) ? self.doZoomOut(e) : self.doZoomIn(e);
22290    };
22291
22292    this.resizeZoom = function() {
22293      if (!self.zoomactive) return;
22294
22295      var py = self.getScrollTop(); //preserve scrolling position
22296      self.win.css({
22297        width: $(window).width() - self.zoomrestore.padding.w + "px",
22298        height: $(window).height() - self.zoomrestore.padding.h + "px"
22299      });
22300      self.onResize();
22301
22302      self.setScrollTop(Math.min(self.page.maxh, py));
22303    };
22304
22305    this.init();
22306
22307    $.nicescroll.push(this);
22308
22309  };
22310
22311  // Inspired by the work of Kin Blas
22312  // http://webpro.host.adobe.com/people/jblas/momentum/includes/jquery.momentum.0.7.js  
22313
22314
22315  var ScrollMomentumClass2D = function(nc) {
22316    var self = this;
22317    this.nc = nc;
22318
22319    this.lastx = 0;
22320    this.lasty = 0;
22321    this.speedx = 0;
22322    this.speedy = 0;
22323    this.lasttime = 0;
22324    this.steptime = 0;
22325    this.snapx = false;
22326    this.snapy = false;
22327    this.demulx = 0;
22328    this.demuly = 0;
22329
22330    this.lastscrollx = -1;
22331    this.lastscrolly = -1;
22332
22333    this.chkx = 0;
22334    this.chky = 0;
22335
22336    this.timer = 0;
22337
22338    this.time = function() {
22339      return +new Date(); //beautifull hack
22340    };
22341
22342    this.reset = function(px, py) {
22343      self.stop();
22344      var now = self.time();
22345      self.steptime = 0;
22346      self.lasttime = now;
22347      self.speedx = 0;
22348      self.speedy = 0;
22349      self.lastx = px;
22350      self.lasty = py;
22351      self.lastscrollx = -1;
22352      self.lastscrolly = -1;
22353    };
22354
22355    this.update = function(px, py) {
22356      var now = self.time();
22357      self.steptime = now - self.lasttime;
22358      self.lasttime = now;
22359      var dy = py - self.lasty;
22360      var dx = px - self.lastx;
22361      var sy = self.nc.getScrollTop();
22362      var sx = self.nc.getScrollLeft();
22363      var newy = sy + dy;
22364      var newx = sx + dx;
22365      self.snapx = (newx < 0) || (newx > self.nc.page.maxw);
22366      self.snapy = (newy < 0) || (newy > self.nc.page.maxh);
22367      self.speedx = dx;
22368      self.speedy = dy;
22369      self.lastx = px;
22370      self.lasty = py;
22371    };
22372
22373    this.stop = function() {
22374      self.nc.unsynched("domomentum2d");
22375      if (self.timer) clearTimeout(self.timer);
22376      self.timer = 0;
22377      self.lastscrollx = -1;
22378      self.lastscrolly = -1;
22379    };
22380
22381    this.doSnapy = function(nx, ny) {
22382      var snap = false;
22383
22384      if (ny < 0) {
22385        ny = 0;
22386        snap = true;
22387      } else if (ny > self.nc.page.maxh) {
22388        ny = self.nc.page.maxh;
22389        snap = true;
22390      }
22391
22392      if (nx < 0) {
22393        nx = 0;
22394        snap = true;
22395      } else if (nx > self.nc.page.maxw) {
22396        nx = self.nc.page.maxw;
22397        snap = true;
22398      }
22399
22400      (snap) ? self.nc.doScrollPos(nx, ny, self.nc.opt.snapbackspeed): self.nc.triggerScrollEnd();
22401    };
22402
22403    this.doMomentum = function(gp) {
22404      var t = self.time();
22405      var l = (gp) ? t + gp : self.lasttime;
22406
22407      var sl = self.nc.getScrollLeft();
22408      var st = self.nc.getScrollTop();
22409
22410      var pageh = self.nc.page.maxh;
22411      var pagew = self.nc.page.maxw;
22412
22413      self.speedx = (pagew > 0) ? Math.min(60, self.speedx) : 0;
22414      self.speedy = (pageh > 0) ? Math.min(60, self.speedy) : 0;
22415
22416      var chk = l && (t - l) <= 60;
22417
22418      if ((st < 0) || (st > pageh) || (sl < 0) || (sl > pagew)) chk = false;
22419
22420      var sy = (self.speedy && chk) ? self.speedy : false;
22421      var sx = (self.speedx && chk) ? self.speedx : false;
22422
22423      if (sy || sx) {
22424        var tm = Math.max(16, self.steptime); //timeout granularity
22425
22426        if (tm > 50) { // do smooth
22427          var xm = tm / 50;
22428          self.speedx *= xm;
22429          self.speedy *= xm;
22430          tm = 50;
22431        }
22432
22433        self.demulxy = 0;
22434
22435        self.lastscrollx = self.nc.getScrollLeft();
22436        self.chkx = self.lastscrollx;
22437        self.lastscrolly = self.nc.getScrollTop();
22438        self.chky = self.lastscrolly;
22439
22440        var nx = self.lastscrollx;
22441        var ny = self.lastscrolly;
22442
22443        var onscroll = function() {
22444          var df = ((self.time() - t) > 600) ? 0.04 : 0.02;
22445
22446          if (self.speedx) {
22447            nx = Math.floor(self.lastscrollx - (self.speedx * (1 - self.demulxy)));
22448            self.lastscrollx = nx;
22449            if ((nx < 0) || (nx > pagew)) df = 0.10;
22450          }
22451
22452          if (self.speedy) {
22453            ny = Math.floor(self.lastscrolly - (self.speedy * (1 - self.demulxy)));
22454            self.lastscrolly = ny;
22455            if ((ny < 0) || (ny > pageh)) df = 0.10;
22456          }
22457
22458          self.demulxy = Math.min(1, self.demulxy + df);
22459
22460          self.nc.synched("domomentum2d", function() {
22461
22462            if (self.speedx) {
22463              var scx = self.nc.getScrollLeft();
22464              if (scx != self.chkx) self.stop();
22465              self.chkx = nx;
22466              self.nc.setScrollLeft(nx);
22467            }
22468
22469            if (self.speedy) {
22470              var scy = self.nc.getScrollTop();
22471              if (scy != self.chky) self.stop();
22472              self.chky = ny;
22473              self.nc.setScrollTop(ny);
22474            }
22475
22476            if (!self.timer) {
22477              self.nc.hideCursor();
22478              self.doSnapy(nx, ny);
22479            }
22480
22481          });
22482
22483          if (self.demulxy < 1) {
22484            self.timer = setTimeout(onscroll, tm);
22485          } else {
22486            self.stop();
22487            self.nc.hideCursor();
22488            self.doSnapy(nx, ny);
22489          }
22490        };
22491
22492        onscroll();
22493
22494      } else {
22495        self.doSnapy(self.nc.getScrollLeft(), self.nc.getScrollTop());
22496      }
22497
22498    }
22499
22500  };
22501
22502
22503  // override jQuery scrollTop
22504
22505  var _scrollTop = jQuery.fn.scrollTop; // preserve original function
22506
22507  jQuery.cssHooks["pageYOffset"] = {
22508    get: function(elem, computed, extra) {
22509      var nice = $.data(elem, '__nicescroll') || false;
22510      return (nice && nice.ishwscroll) ? nice.getScrollTop() : _scrollTop.call(elem);
22511    },
22512    set: function(elem, value) {
22513      var nice = $.data(elem, '__nicescroll') || false;
22514      (nice && nice.ishwscroll) ? nice.setScrollTop(parseInt(value)): _scrollTop.call(elem, value);
22515      return this;
22516    }
22517  };
22518
22519  /*  
22520  $.fx.step["scrollTop"] = function(fx){    
22521    $.cssHooks["scrollTop"].set( fx.elem, fx.now + fx.unit );
22522  };
22523*/
22524
22525  jQuery.fn.scrollTop = function(value) {
22526    if (typeof value == "undefined") {
22527      var nice = (this[0]) ? $.data(this[0], '__nicescroll') || false : false;
22528      return (nice && nice.ishwscroll) ? nice.getScrollTop() : _scrollTop.call(this);
22529    } else {
22530      return this.each(function() {
22531        var nice = $.data(this, '__nicescroll') || false;
22532        (nice && nice.ishwscroll) ? nice.setScrollTop(parseInt(value)): _scrollTop.call($(this), value);
22533      });
22534    }
22535  };
22536
22537  // override jQuery scrollLeft
22538
22539  var _scrollLeft = jQuery.fn.scrollLeft; // preserve original function
22540
22541  $.cssHooks.pageXOffset = {
22542    get: function(elem, computed, extra) {
22543      var nice = $.data(elem, '__nicescroll') || false;
22544      return (nice && nice.ishwscroll) ? nice.getScrollLeft() : _scrollLeft.call(elem);
22545    },
22546    set: function(elem, value) {
22547      var nice = $.data(elem, '__nicescroll') || false;
22548      (nice && nice.ishwscroll) ? nice.setScrollLeft(parseInt(value)): _scrollLeft.call(elem, value);
22549      return this;
22550    }
22551  };
22552
22553  /*  
22554  $.fx.step["scrollLeft"] = function(fx){
22555    $.cssHooks["scrollLeft"].set( fx.elem, fx.now + fx.unit );
22556  };  
22557*/
22558
22559  jQuery.fn.scrollLeft = function(value) {
22560    if (typeof value == "undefined") {
22561      var nice = (this[0]) ? $.data(this[0], '__nicescroll') || false : false;
22562      return (nice && nice.ishwscroll) ? nice.getScrollLeft() : _scrollLeft.call(this);
22563    } else {
22564      return this.each(function() {
22565        var nice = $.data(this, '__nicescroll') || false;
22566        (nice && nice.ishwscroll) ? nice.setScrollLeft(parseInt(value)): _scrollLeft.call($(this), value);
22567      });
22568    }
22569  };
22570
22571  var NiceScrollArray = function(doms) {
22572    var self = this;
22573    this.length = 0;
22574    this.name = "nicescrollarray";
22575
22576    this.each = function(fn) {
22577      for (var a = 0, i = 0; a < self.length; a++) fn.call(self[a], i++);
22578      return self;
22579    };
22580
22581    this.push = function(nice) {
22582      self[self.length] = nice;
22583      self.length++;
22584    };
22585
22586    this.eq = function(idx) {
22587      return self[idx];
22588    };
22589
22590    if (doms) {
22591      for (var a = 0; a < doms.length; a++) {
22592        var nice = $.data(doms[a], '__nicescroll') || false;
22593        if (nice) {
22594          this[this.length] = nice;
22595          this.length++;
22596        }
22597      };
22598    }
22599
22600    return this;
22601  };
22602
22603  function mplex(el, lst, fn) {
22604    for (var a = 0; a < lst.length; a++) fn(el, lst[a]);
22605  };
22606  mplex(
22607    NiceScrollArray.prototype, ['show', 'hide', 'toggle', 'onResize', 'resize', 'remove', 'stop', 'doScrollPos'],
22608    function(e, n) {
22609      e[n] = function() {
22610        var args = arguments;
22611        return this.each(function() {
22612          this[n].apply(this, args);
22613        });
22614      };
22615    }
22616  );
22617
22618  jQuery.fn.getNiceScroll = function(index) {
22619    if (typeof index == "undefined") {
22620      return new NiceScrollArray(this);
22621    } else {
22622      var nice = this[index] && $.data(this[index], '__nicescroll') || false;
22623      return nice;
22624    }
22625  };
22626
22627  jQuery.extend(jQuery.expr[':'], {
22628    nicescroll: function(a) {
22629      return ($.data(a, '__nicescroll')) ? true : false;
22630    }
22631  });
22632
22633  $.fn.niceScroll = function(wrapper, opt) {
22634    if (typeof opt == "undefined") {
22635      if ((typeof wrapper == "object") && !("jquery" in wrapper)) {
22636        opt = wrapper;
22637        wrapper = false;
22638      }
22639    }
22640    opt = $.extend({},opt); // cloning
22641    var ret = new NiceScrollArray();
22642    if (typeof opt == "undefined") opt = {};
22643
22644    if (wrapper || false) {
22645      opt.doc = $(wrapper);
22646      opt.win = $(this);
22647    }
22648    var docundef = !("doc" in opt);
22649    if (!docundef && !("win" in opt)) opt.win = $(this);
22650
22651    this.each(function() {
22652      var nice = $(this).data('__nicescroll') || false;
22653      if (!nice) {
22654        opt.doc = (docundef) ? $(this) : opt.doc;
22655        nice = new NiceScrollClass(opt, $(this));
22656        $(this).data('__nicescroll', nice);
22657      }
22658      ret.push(nice);
22659    });
22660    return (ret.length == 1) ? ret[0] : ret;
22661  };
22662
22663  window.NiceScroll = {
22664    getjQuery: function() {
22665      return jQuery
22666    }
22667  };
22668
22669  if (!$.nicescroll) {
22670    $.nicescroll = new NiceScrollArray();
22671    $.nicescroll.options = _globaloptions;
22672  }
22673
22674}));
22675
22676/*
22677 * validate2.js 0.0.2
22678 *
22679 * (c) Alex Buturlakin [email protected]
22680 */
22681(function (window, document, undefined) {
22682  /*
22683   * Use the setMessage() function to overwrite specific messages.
22684   * Or $.validatorMessages() if you use jquery
22685   * Or set message directly in rule
22686   *
22687   * "{0}" - field name, {1...} - rule parameters
22688   */
22689  var defaults = {
22690    messages: {
22691      required: 'The {0} field is required.',
22692      matches: 'The {0} field does not match the {1} field.',
22693      "default": 'The {0} field is still set to default, please change.',
22694      valid_email: 'The {0} field must contain a valid email address.',
22695      valid_emails: 'The {0} field must contain all valid email addresses.',
22696      english: 'The {0} field must contain only english characters',
22697      english_numeric: 'The {0} field must contain only english characters or numeric',
22698      company_name: 'The {0} field shoould be a valid comapny name',
22699      min_length: 'The {0} field must be at least {1} characters in length.',
22700      max_length: 'The {0} field must not exceed {1} characters in length.',
22701      exact_length: 'The {0} field must be exactly {1} characters in length.',
22702      length_one_or_two: 'The {0} field must be exactly {1} or {2} characters in length.',
22703      greater_than: 'The {0} field must contain a number greater than {1}.',
22704      less_than: 'The {0} field must contain a number less than {1}.',
22705      alpha: 'The {0} field must only contain alphabetical characters.',
22706      alpha_numeric: 'The {0} field must only contain alpha-numeric characters.',
22707      alpha_numeric_space: 'The {0} field must only contain alpha-numeric and space characters.',
22708      alpha_numeric_space_dots: 'The {0} field must only contain alpha-numeric, space and dots characters.',
22709      alpha_dash: 'The {0} field must only contain alpha-numeric characters, underscores, and dashes.',
22710      numeric: 'The {0} field must contain only numbers.',
22711      integer: 'The {0} field must contain an integer.',
22712      decimal: 'The {0} field must contain a decimal number.',
22713      is_natural: 'The {0} field must contain only positive numbers.',
22714      is_natural_no_zero: 'The {0} field must contain a number greater than zero.',
22715      valid_ip: 'The {0} field must contain a valid IP.',
22716      valid_base64: 'The {0} field must contain a base64 string.',
22717      valid_credit_card: 'The {0} field must contain a valid credit card number.',
22718      is_file_type: 'The {0} field must contain only {1} files.',
22719      valid_url: 'The {0} field must contain a valid URL.',
22720      greater_than_date: 'The {0} field must contain a more recent date than {1}.',
22721      less_than_date: 'The {0} field must contain an older date than {1}.',
22722      greater_than_or_equal_date: 'The {0} field must contain a date that\'s at least as recent as {1}.',
22723      less_than_or_equal_date: 'The {0} field must contain a date that\'s {1} or older.',
22724      password: 'At least eight characters: one number and one uppercase or lowercase English or Hebrew letter.',
22725      one_word: 'The {0} field must contain only one word.',
22726      two_words: 'The {0} field must contain only two words.',
22727      words_count: 'The {0} field must contain only {1} words.',
22728      words_count_max: 'The {0} field must contain a words less than {1}.',
22729      words_count_min: 'The {0} field must have at least {1} words.',
22730      street: 'The {0} field must contain a valid street address.'
22731    },
22732    formCallback: function (status, errors) { },
22733    fieldCallback: function (status, field, errors) { }
22734  };
22735
22736  /*
22737   * Define the regular expressions that will be used
22738   */
22739  var ruleRegex = /^(.+?)\[(.+)\]$/,
22740      numericRegex = /^[0-9]+$/,
22741      integerRegex = /^\-?[0-9]+$/,
22742      decimalRegex = /^\-?[0-9]*\.?[0-9]+$/,
22743      // emailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
22744      emailRegex = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/,
22745      alphaRegex = /^[a-z]+$/i,
22746      alphaNumericRegex = /^[a-z0-9]+$/i,
22747      alphaDashRegex = /^[a-z0-9_\-]+$/i,
22748      naturalRegex = /^[0-9]+$/i,
22749      naturalNoZeroRegex = /^[1-9][0-9]*$/i,
22750      ipRegex = /^((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})\.){3}(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})$/i,
22751      base64Regex = /[^a-zA-Z0-9\/\+=]/i,
22752      numericDashRegex = /^[\d\-\s]+$/,
22753      urlRegex = /^((http|https):\/\/(\w+:{0,1}\w*@)?(\S+)|)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/,
22754      dateRegex = /\d{4}-\d{1,2}-\d{1,2}/,
22755      englishRegex = /^[a-zA-Z\s]+$/,
22756      englishNumericRegex = /^[a-zA-Z0-9\s]+$/,
22757      passwordRegex = /^(?=.*[0-9])(?=.*[a-z|A-Z]).{8,}$/,
22758      wordsCountRegex = /\b\S+\b/g,
22759      alphaNumericSpaceRegex = /^[a-z0-9\s]+$/i,
22760      alphaNumericSpaceDotRegex = /^[a-z0-9\s\.]+$/i,
22761      streetRegex = /^\s*\S+(?:\s+\S+){1}/,
22762      hasHebrewCharsRegex = /[\u0590-\u05FF]/,
22763  // companyRegex = /(?:^|\s)(?:Corporation|Corp|Inc|Incorporated|Company|LTD|PLLC|P\.C)\.?$/ig
22764      companyRegex = /\bLTD\b/;
22765
22766
22767  /*
22768   * The exposed public object to validate a form:
22769   *
22770   * @param formNameOrNode - String - The name attribute of the form (i.e. <form name="myForm"></form>) or node of the form element
22771   * @param fields - Array - [{
22772   *     name: The name of the element (i.e. <input name="myField" />)
22773   *     display: 'Field Name'
22774   *     rules: required|matches[password_confirm],
22775   *     messages: {
22776   *        'rule_name': 'Custom message'
22777   *     }
22778   * }]
22779   *
22780   * @param options - Options
22781   */
22782  var FormValidator = function (formNameOrNode, fields, options) {
22783    this.o = {
22784      callbacks: {
22785        fields: [defaults.fieldCallback],
22786        form: [defaults.formCallback]
22787      }
22788    };
22789
22790    // todo@alexbuturlakin: Remove jQuery usage
22791    jQuery.extend(this.o, options);
22792
22793    this.errors = {};
22794    this.fields = {};
22795    this.form = this._formByNameOrNode(formNameOrNode) || {};
22796    this.messages = {};
22797    this.handlers = {};
22798    this.conditionals = {};
22799    this.defaultGroup = 'default';
22800    this.disableGroupValidation = false;
22801
22802    for (var i = 0, fieldLength = fields.length; i < fieldLength; i++) {
22803      var field = fields[i];
22804
22805      // If passed in incorrectly, we need to skip the field.
22806      if ((!field.name && !field.names) || !field.rules) {
22807        continue;
22808      }
22809
22810      /*
22811       * Build the master fields array that has all the information needed to validate
22812       */
22813      if (field.names) {
22814        for (var j = 0, fieldNamesLength = field.names.length; j < fieldNamesLength; j++) {
22815          this._addField(field, field.names[j]);
22816        }
22817      } else {
22818        this._addField(field, field.name);
22819      }
22820    }
22821  };
22822
22823  /**
22824   * Get element attribute.
22825   *
22826   * @param {HTMLInputElement} element
22827   * @param {String} attributeName
22828   *
22829   * @returns {String}
22830   */
22831  FormValidator.prototype.getAttributeValue = function (element, attributeName) {
22832    var i;
22833
22834    if ((element.length > 0) && (element[0].type === 'radio' || element[0].type === 'checkbox')) {
22835      for (i = 0, elementLength = element.length; i < elementLength; i++) {
22836        if (element[i].checked) {
22837          return element[i][attributeName];
22838        }
22839      }
22840
22841      return '';
22842    }
22843
22844    return element[attributeName];
22845  };
22846
22847  /*
22848   * @public
22849   * Sets a custom message for one of the rules
22850   */
22851
22852  FormValidator.prototype.setMessage = function (rule, message) {
22853    this.messages[rule] = message;
22854
22855    // return this for chaining
22856    return this;
22857  };
22858
22859  /*
22860   * @public
22861   * Registers a callback for a custom rule (i.e. callback_username_check)
22862   */
22863
22864  FormValidator.prototype.registerCallback = function (name, handler) {
22865    if (name && typeof name === 'string' && handler && typeof handler === 'function') {
22866      this.handlers[name] = handler;
22867    }
22868
22869    // return this for chaining
22870    return this;
22871  };
22872
22873  /*
22874   * @public
22875   * Registers a conditional for a custom 'depends' rule
22876   */
22877
22878  FormValidator.prototype.registerConditional = function (name, conditional) {
22879    if (name && typeof name === 'string' && conditional && typeof conditional === 'function') {
22880      this.conditionals[name] = conditional;
22881    }
22882
22883    // return this for chaining
22884    return this;
22885  };
22886
22887  /*
22888   * @private
22889   * Determines if a form dom node was passed in or just a string representing the form name
22890   */
22891
22892  FormValidator.prototype._formByNameOrNode = function (formNameOrNode) {
22893    return (typeof formNameOrNode === 'object') ? formNameOrNode : document.forms[formNameOrNode];
22894  };
22895
22896  /*
22897   * @private
22898   * Adds a file to the master fields array
22899   */
22900
22901  FormValidator.prototype._addField = function (field, nameValue) {
22902    this.fields[nameValue] = {
22903      name: nameValue,
22904      display: field.display || nameValue,
22905      rules: field.rules,
22906      depends: field.depends,
22907      group: typeof field.group === typeof undefined ? this.defaultGroup : field.group,
22908      id: null,
22909      element: null,
22910      type: null,
22911      value: null,
22912      checked: null
22913    };
22914
22915    // add custom validation rules for current field
22916    if('custom' in field) {
22917      for(var k in field.custom) {
22918        if('function' == typeof field.custom[k]) {
22919          this._hooks[k + '.' + nameValue] = field.custom[k];
22920        }
22921      }
22922    }
22923  };
22924
22925  /**
22926   * Change rules for field.
22927   *
22928   * @param {String} name
22929   * @param {String} rules
22930   * @param {{}}     [messages]
22931   * @returns {boolean}
22932   */
22933  FormValidator.prototype.changeFiledRules = function (name, rules, messages) {
22934    messages = messages || {};
22935    
22936    // field not exists
22937    if(!(name in this.fields)) {
22938      return false;
22939    }
22940
22941    // set rules
22942    this.fields[name]['rules'] = rules;
22943
22944    // set messages
22945    for(var k in messages) {
22946      this.setMessage(name+'.'+k, messages[k]);
22947    }
22948  };
22949
22950  /*
22951   * @private
22952   * Runs the validation when the form is submitted.
22953   */
22954
22955  FormValidator.prototype._validateForm = function (groups) {
22956    groups = groups || [];
22957
22958    // clean errors
22959    this.cleanErrors();
22960
22961    // validate fields
22962    for (var key in this.fields) {
22963      this.validateField(key, 'form', groups);
22964    }
22965
22966    // execute callbacks
22967    this._executeCallbacks('form', [
22968      0 === Object.keys(this.errors).length,
22969      this.errors,
22970      0 == groups.length ? ['default'] : groups
22971    ], this.form);
22972
22973    // result
22974    var result = 0 == Object.keys(this.errors).length;
22975    this.cleanErrors();
22976
22977    return result;
22978  };
22979
22980  /**
22981   * Execute callbacks.
22982   *
22983   * @param {String} type
22984   * @param {[]} params
22985   * @param {Object} [context]
22986   *
22987   * @returns {boolean}
22988   *
22989   * @private
22990   */
22991  FormValidator.prototype._executeCallbacks = function (type, params, context) {
22992    context = context || this;
22993
22994    if (this.o.callbacks === typeof undefined || this.o.callbacks[type] === typeof undefined) {
22995      return false;
22996    }
22997
22998    var callbacks = this.o.callbacks[type];
22999
23000    for (var k in callbacks) {
23001      var callback = callbacks[k];
23002      callback.apply(context, params);
23003    }
23004
23005    return true;
23006  };
23007
23008  /**
23009   * @param {String} fieldName
23010   */
23011  FormValidator.prototype.validateField = function (fieldName, type, groups) {
23012    type   = type   || 'single';
23013    groups = groups || [];
23014
23015    if (this.fields.hasOwnProperty(fieldName)) {
23016      var field   = this.fields[fieldName] || {},
23017          group   = field.group,
23018          element = this.form[field.name];
23019      
23020      if (element && element !== undefined &&
23021          (false === this.disableGroupValidation || group != this.disableGroupValidation) &&
23022          (0 == groups.length || groups.indexOf(group) > -1)) {
23023        field.id      = this.getAttributeValue(element, 'id');
23024        field.element = element;
23025        field.type    = (element.length > 0) ? element[0].type : element.type;
23026        field.value   = this.getAttributeValue(element, 'value');
23027        field.checked = this.getAttributeValue(element, 'checked');
23028
23029        /*
23030         * Run through the rules for each field.
23031         * If the field has a depends conditional, only validate the field
23032         * if it passes the custom function
23033         */
23034        if (field.depends && typeof field.depends === "function") {
23035          if (field.depends.call(this, field)) {
23036            this._validateField(field);
23037          }
23038        } else if (field.depends && typeof field.depends === "string" && this.conditionals[field.depends]) {
23039          if (this.conditionals[field.depends].call(this, field)) {
23040            this._validateField(field);
23041          }
23042        } else {
23043          this._validateField(field);
23044        }
23045      }
23046
23047      this._executeCallbacks('fields', [
23048        !(fieldName in this.errors),
23049        type,
23050        field,
23051        fieldName in this.errors ? this.errors[fieldName] : [],
23052        0 == groups.length ? ['default'] : groups
23053      ], field.element);
23054    }
23055  };
23056
23057  /*
23058   * @private
23059   * Looks at the fields value and evaluates it against the given rules
23060   */
23061  FormValidator.prototype._validateField = function (field) {
23062    var rules = field.rules.split('|'),
23063        indexOfRequired = field.rules.indexOf('required'),
23064        isEmpty = (!field.value || field.value === '' || field.value === undefined);
23065
23066    /*
23067     * Run through the rules and execute the validation methods as needed
23068     */
23069    for (var i = 0, ruleLength = rules.length; i < ruleLength; i++) {
23070      var method = rules[i],
23071          param = null,
23072          failed = false,
23073          parts = ruleRegex.exec(method);
23074
23075      /*
23076       * If this field is not required and the value is empty, continue on to the next rule unless it's a callback.
23077       * This ensures that a callback will always be called but other rules will be skipped.
23078       */
23079      if (indexOfRequired === -1 && method.indexOf('!callback_') === -1 && isEmpty) {
23080        continue;
23081      }
23082
23083      /*
23084       * If the rule has a parameter (i.e. matches[param]) split it out
23085       */
23086      if (parts) {
23087        method = parts[1];
23088        param = this._getParams(parts);
23089      }
23090
23091      if (method.charAt(0) === '!') {
23092        method = method.substring(1, method.length);
23093      }
23094
23095      /*
23096       * If the hook is defined, run it to find any validation errors
23097       */
23098      if (typeof this._hooks[method] === 'function') {
23099        if (!this._hooks[method].apply(this, [field, param])) {
23100          failed = true;
23101        }
23102
23103        // personal custom rule
23104      } else if(typeof this._hooks[method + '.' + field.name] === 'function') {
23105        if (!this._hooks[method + '.' + field.name].apply(this, [field, param])) {
23106          failed = true;
23107        }
23108      } else if (method.substring(0, 9) === 'callback_') {
23109        // Custom method. Execute the handler if it was registered
23110        method = method.substring(9, method.length);
23111
23112        if (typeof this.handlers[method] === 'function') {
23113          if (this.handlers[method].apply(this, [field.value, param, field]) === false) {
23114            failed = true;
23115          }
23116        }
23117      }
23118
23119      /*
23120       * If the hook failed, add a message to the errors array
23121       */
23122      if (failed) {
23123        this._addError(field.name, {
23124          id: field.id,
23125          element: field.element,
23126          name: field.name,
23127          message: this._getMessage(field.name, method, param),
23128          rule: method
23129        });
23130
23131        // Break out so as to not spam with validation errors (i.e. required and valid_email)
23132        // break;
23133      }
23134    }
23135  };
23136
23137  /**
23138   * Add related error.
23139   *
23140   * @param {String} name
23141   * @param {{}} data
23142   *
23143   * @private
23144   */
23145  FormValidator.prototype._addError = function (name, data) {
23146    if (!(name in this.errors)) {
23147      this.errors[name] = [];
23148    }
23149
23150    this.errors[name].push(data);
23151  };
23152
23153  /**
23154   * Disable validation.
23155   *
23156   * @param {String} [group]
23157   */
23158  FormValidator.prototype.disable = function (group) {
23159    group = group || this.defaultGroup;
23160
23161    this.disableGroupValidation = group;
23162  };
23163
23164  /**
23165   * Disable validation.
23166   */
23167  FormValidator.prototype.enable = function () {
23168    this.disableGroupValidation = false;
23169  };
23170
23171  /**
23172   * private function _getValidDate: helper function to convert a string date to a Date object
23173   * @param date (String) must be in format yyyy-mm-dd or use keyword: today
23174   * @returns {Date} returns false if invalid
23175   */
23176  FormValidator.prototype._getValidDate = function (date) {
23177    if (!date.match('today') && !date.match(dateRegex)) {
23178      return false;
23179    }
23180
23181    var validDate = new Date(),
23182        validDateArray;
23183
23184    if (!date.match('today')) {
23185      validDateArray = date.split('-');
23186      validDate.setFullYear(validDateArray[0]);
23187      validDate.setMonth(validDateArray[1] - 1);
23188      validDate.setDate(validDateArray[2]);
23189    }
23190    return validDate;
23191  };
23192
23193  /**
23194   * Get error message
23195   *
23196   * @param {String} fieldName
23197   * @param {String} method
23198   * @param {String} [param]
23199   *
23200   * @returns {string}
23201   */
23202  FormValidator.prototype._getMessage = function (fieldName, method, param) {
23203    var field   = this.fields[fieldName] || {},
23204        source  = this.messages[fieldName + '.' + method] || this.messages[method] || defaults.messages[method],
23205        message = 'An error has occurred with the ' + field.display + ' field.',
23206        params  = param ? this.fields[param] ? this.fields[param].display : param : [];
23207
23208    if (null === source) {
23209      return '';
23210    }
23211
23212    if (source) {
23213      message = this.replace(source, field.display, params);
23214    }
23215
23216    return message;
23217  };
23218
23219
23220  /**
23221   * Replace in message.
23222   *
23223   * @param {String|String[]} source
23224   * @param {String|String[]} display
23225   * @param {String|String[]} params
23226   */
23227  FormValidator.prototype.replace = function (source, display, params) {
23228    var replace = [];
23229
23230    source = Array.isArray(source) ? source : [source];
23231    params = Array.isArray(params) ? params : [params];
23232
23233    replace.push(display);
23234    replace = replace.concat(params);
23235
23236    for(var s in source) {
23237      source[s] = FormValidator.prototype.formatString.apply(source[s], replace);
23238    }
23239
23240    return 1 == source.length ? source[0] : source;
23241  };
23242
23243  /**
23244   * Format string
23245   *
23246   * @returns {FormValidator}
23247   */
23248  FormValidator.prototype.formatString = function() {
23249    var s = this,
23250        i = arguments.length;
23251
23252    while (i--) {
23253      s = s.replace(new RegExp('\\{' + i + '\\}', 'gm'), arguments[i]);
23254    }
23255
23256    return s;
23257  };
23258
23259  /**
23260   * Clean errors.
23261   */
23262  FormValidator.prototype.cleanErrors = function () {
23263    this.errors = {};
23264  };
23265
23266  /**
23267   * Get rule info
23268   *
23269   * @param {String} rule
23270   * @returns {{}}
23271   */
23272  FormValidator.prototype._getRuleInfo = function (rule) {
23273    var parts = ruleRegex.exec(rule);
23274
23275    if (parts) {
23276      return {
23277        'method': parts[1],
23278        'params': this._getParams(parts)
23279      };
23280    }
23281
23282    return {
23283      'method': rule,
23284      'params': false
23285    };
23286  };
23287
23288  /**
23289   * Get params for method.
23290   *
23291   * @param {Array|*} parts
23292   *
23293   * @returns {*}
23294   *
23295   * @private
23296   */
23297  FormValidator.prototype._getParams = function (parts) {
23298    if (false == parts) {
23299      return false;
23300    }
23301
23302    var params = parts[2];
23303
23304    if (false == params) {
23305      return false;
23306    }
23307
23308    params = params.split(',');
23309
23310    return 1 === params.length ? params[0] : params;
23311  };
23312
23313  /*
23314   * @private
23315   * Object containing all of the validation hooks
23316   */
23317
23318  FormValidator.prototype._hooks = {
23319    required: function (field) {
23320      var value = field.value;
23321
23322      if ((field.type === 'checkbox') || (field.type === 'radio')) {
23323        return (field.checked === true);
23324      }
23325
23326      return (value !== null && value !== '');
23327    },
23328
23329    "default": function (field, defaultName) {
23330      return field.value !== defaultName;
23331    },
23332
23333    matches: function (field, matchName) {
23334      var el = this.form[matchName];
23335
23336      if (el) {
23337        return field.value === el.value;
23338      }
23339
23340      return false;
23341    },
23342
23343    valid_email: function (field) {
23344      return emailRegex.test(field.value);
23345    },
23346
23347    english: function (field) {
23348      return englishRegex.test(field.value);
23349    },
23350
23351    english_numeric: function (field) {
23352      return englishNumericRegex.test(field.value)
23353    },
23354
23355    company_name: function (field) {
23356      return companyRegex.test(field.value);
23357    },
23358
23359    valid_emails: function (field) {
23360      var result = field.value.split(/\s*,\s*/g);
23361
23362      for (var i = 0, resultLength = result.length; i < resultLength; i++) {
23363        if (!emailRegex.test(result[i])) {
23364          return false;
23365        }
23366      }
23367
23368      return true;
23369    },
23370
23371    min_length: function (field, length) {
23372      if (!numericRegex.test(length)) {
23373        return false;
23374      }
23375
23376      return (field.value.length >= parseInt(length, 10));
23377    },
23378
23379    max_length: function (field, length) {
23380      if (!numericRegex.test(length)) {
23381        return false;
23382      }
23383
23384      return (field.value.length <= parseInt(length, 10));
23385    },
23386
23387    exact_length: function (field, length) {
23388      if (!numericRegex.test(length)) {
23389        return false;
23390      }
23391
23392      return (field.value.length === parseInt(length, 10));
23393    },
23394
23395    greater_than: function (field, param) {
23396      if (!decimalRegex.test(field.value)) {
23397        return false;
23398      }
23399
23400      return (parseFloat(field.value) > parseFloat(param));
23401    },
23402
23403    less_than: function (field, param) {
23404      if (!decimalRegex.test(field.value)) {
23405        return false;
23406      }
23407
23408      return (parseFloat(field.value) < parseFloat(param));
23409    },
23410
23411    length_one_or_two: function (field, params) {
23412
23413      for (var k in params) {
23414        if (field.value.length === parseInt(params[k], 10)) {
23415          return true;
23416        }
23417      }
23418
23419      return false;
23420    },
23421
23422    alpha: function (field) {
23423      return (alphaRegex.test(field.value));
23424    },
23425
23426    alpha_numeric: function (field) {
23427      return (alphaNumericRegex.test(field.value));
23428    },
23429
23430    street: function (field) {
23431      return (streetRegex.test(field.value));
23432    },
23433    
23434    alpha_numeric_space: function(field) {
23435      return (alphaNumericSpaceRegex.test(field.value));
23436    },
23437
23438    alpha_numeric_space_dot: function(field) {
23439      return (alphaNumericSpaceDotRegex.test(field.value));
23440    },
23441
23442    alpha_dash: function (field) {
23443      return (alphaDashRegex.test(field.value));
23444    },
23445
23446    numeric: function (field) {
23447      return (numericRegex.test(field.value));
23448    },
23449
23450    integer: function (field) {
23451      return (integerRegex.test(field.value));
23452    },
23453
23454    decimal: function (field) {
23455      return (decimalRegex.test(field.value));
23456    },
23457
23458    is_natural: function (field) {
23459      return (naturalRegex.test(field.value));
23460    },
23461
23462    is_natural_no_zero: function (field) {
23463      return (naturalNoZeroRegex.test(field.value));
23464    },
23465
23466    valid_ip: function (field) {
23467      return (ipRegex.test(field.value));
23468    },
23469
23470    valid_base64: function (field) {
23471      return (base64Regex.test(field.value));
23472    },
23473
23474    valid_url: function (field) {
23475      return (urlRegex.test(field.value));
23476    },
23477
23478    password: function (field) {
23479      return passwordRegex.test(field.value) && !hasHebrewCharsRegex.test(field.value);
23480    },
23481
23482    words_count: function (field, value) {
23483      var count = field.value.split(wordsCountRegex).length - 1;
23484
23485      return count == value;
23486    },
23487
23488    words_count_max: function (field, max) {
23489      var count = field.value.split(wordsCountRegex).length - 1;
23490
23491      return count <= max;
23492    },
23493
23494    words_count_min: function (field, min) {
23495      var count = field.value.split(wordsCountRegex).length - 1;
23496
23497      return count >= min;
23498    },
23499
23500    // todo@alexbuturlakin: remove one_word and two_words or add words_count validator
23501    one_word: function (field) {
23502      var count = field.value.split(wordsCountRegex).length;
23503
23504      return 1 === count - 1 || 2 <= count - 1;
23505    },
23506
23507    two_words: function (field) {
23508      var count = field.value.split(wordsCountRegex).length;
23509
23510      return 2 <= count - 1;
23511    },
23512
23513    valid_credit_card: function (field) {
23514      // Luhn Check Code from https://gist.github.com/4075533
23515      // accept only digits, dashes or spaces
23516      if (!numericDashRegex.test(field.value)) return false;
23517
23518      // The Luhn Algorithm. It's so pretty.
23519      var nCheck = 0, nDigit = 0, bEven = false;
23520      var strippedField = field.value.replace(/\D/g, "");
23521
23522      for (var n = strippedField.length - 1; n >= 0; n--) {
23523        var cDigit = strippedField.charAt(n);
23524        nDigit = parseInt(cDigit, 10);
23525        if (bEven) {
23526          if ((nDigit *= 2) > 9) nDigit -= 9;
23527        }
23528
23529        nCheck += nDigit;
23530        bEven = !bEven;
23531      }
23532
23533      return (nCheck % 10) === 0;
23534    },
23535
23536    is_file_type: function (field, type) {
23537      if (field.type !== 'file') {
23538        return true;
23539      }
23540
23541      var ext = field.value.substr((field.value.lastIndexOf('.') + 1)),
23542          typeArray = type.split(','),
23543          inArray = false,
23544          i = 0,
23545          len = typeArray.length;
23546
23547      for (i; i < len; i++) {
23548        if (ext == typeArray[i]) inArray = true;
23549      }
23550
23551      return inArray;
23552    },
23553
23554    greater_than_date: function (field, date) {
23555      var enteredDate = this._getValidDate(field.value),
23556          validDate = this._getValidDate(date);
23557
23558      if (!validDate || !enteredDate) {
23559        return false;
23560      }
23561
23562      return enteredDate > validDate;
23563    },
23564
23565    less_than_date: function (field, date) {
23566      var enteredDate = this._getValidDate(field.value),
23567          validDate = this._getValidDate(date);
23568
23569      if (!validDate || !enteredDate) {
23570        return false;
23571      }
23572
23573      return enteredDate < validDate;
23574    },
23575
23576    greater_than_or_equal_date: function (field, date) {
23577      var enteredDate = this._getValidDate(field.value),
23578          validDate = this._getValidDate(date);
23579
23580      if (!validDate || !enteredDate) {
23581        return false;
23582      }
23583
23584      return enteredDate >= validDate;
23585    },
23586
23587    less_than_or_equal_date: function (field, date) {
23588      var enteredDate = this._getValidDate(field.value),
23589          validDate = this._getValidDate(date);
23590
23591      if (!validDate || !enteredDate) {
23592        return false;
23593      }
23594
23595      return enteredDate <= validDate;
23596    }
23597  };
23598
23599  window.FormValidator = FormValidator;
23600
23601  // jQuery integration
23602  (function ($) {
23603    /**
23604     * Get or set messages for validation errors.
23605     *
23606     * @param {{}} [messages]
23607     */
23608    $.validatorMessages = function (messages) {
23609      messages = messages || {};
23610
23611      return $.extend(defaults.messages, messages);
23612    };
23613
23614  })(jQuery);
23615
23616})(window, document);
23617
23618/*
23619 * Export as a CommonJS module
23620 */
23621if (typeof module !== 'undefined' && module.exports) {
23622  module.exports = FormValidator;
23623}
23624/*
23625 * jQuery Storage API Plugin
23626 *
23627 * Copyright (c) 2013 Julien Maurel
23628 *
23629 * Licensed under the MIT license:
23630 * http://www.opensource.org/licenses/mit-license.php
23631 *
23632 * Project home:
23633 * https://github.com/julien-maurel/jQuery-Storage-API
23634 *
23635 * Version: 1.9.2
23636 */
23637(function (factory) {
23638    if (typeof define === 'function' && define.amd) {
23639        // AMD
23640        define(['jquery'], factory);
23641    } else if (typeof exports === 'object') {
23642        // CommonJS
23643        factory(require('jquery'));
23644    } else {
23645        // Browser globals
23646        factory(jQuery);
23647    }
23648}(function ($) {
23649    // Prefix to use with cookie fallback
23650    var cookie_local_prefix = "ls_";
23651    var cookie_session_prefix = "ss_";
23652
23653    // Get items from a storage
23654    function _get() {
23655        var storage = this._type, l = arguments.length, s = window[storage], a = arguments, a0 = a[0], vi, ret, tmp;
23656        if (l < 1) {
23657            throw new Error('Minimum 1 argument must be given');
23658        } else if ($.isArray(a0)) {
23659            // If second argument is an array, return an object with value of storage for each item in this array
23660            ret = {};
23661            for (var i in a0) {
23662                vi = a0[i];
23663                try {
23664                    ret[vi] = JSON.parse(s.getItem(vi));
23665                } catch (e) {
23666                    ret[vi] = s.getItem(vi);
23667                }
23668            }
23669            return ret;
23670        } else if (l == 1) {
23671            // If only 1 argument, return value directly
23672            try {
23673                return JSON.parse(s.getItem(a0));
23674            } catch (e) {
23675                return s.getItem(a0);
23676            }
23677        } else {
23678            // If more than 1 argument, parse storage to retrieve final value to return it
23679            // Get first level
23680            try {
23681                ret = JSON.parse(s.getItem(a0));
23682            } catch (e) {
23683                throw new ReferenceError(a0 + ' is not defined in this storage');
23684            }
23685            // Parse next levels
23686            for (var i = 1; i < l - 1; i++) {
23687                ret = ret[a[i]];
23688                if (ret === undefined) {
23689                    throw new ReferenceError([].slice.call(a, 1, i + 1).join('.') + ' is not defined in this storage');
23690                }
23691            }
23692            // If last argument is an array, return an object with value for each item in this array
23693            // Else return value normally
23694            if ($.isArray(a[i])) {
23695                tmp = ret;
23696                ret = {};
23697                for (var j in a[i]) {
23698                    ret[a[i][j]] = tmp[a[i][j]];
23699                }
23700                return ret;
23701            } else {
23702                return ret[a[i]];
23703            }
23704        }
23705    }
23706
23707    // Set items of a storage
23708    function _set() {
23709        var storage = this._type, l = arguments.length, s = window[storage], a = arguments, a0 = a[0], a1 = a[1], vi, to_store = isNaN(a1)?{}:[], type, tmp;
23710        if (l < 1 || !$.isPlainObject(a0) && l < 2) {
23711            throw new Error('Minimum 2 arguments must be given or first parameter must be an object');
23712        } else if ($.isPlainObject(a0)) {
23713            // If first argument is an object, set values of storage for each property of this object
23714            for (var i in a0) {
23715                vi = a0[i];
23716                if (!$.isPlainObject(vi) && !this.alwaysUseJson) {
23717                    s.setItem(i, vi);
23718                } else {
23719                    s.setItem(i, JSON.stringify(vi));
23720                }
23721            }
23722            return a0;
23723        } else if (l == 2) {
23724            // If only 2 arguments, set value of storage directly
23725            if (typeof a1 === 'object' || this.alwaysUseJson) {
23726                s.setItem(a0, JSON.stringify(a1));
23727            } else {
23728                s.setItem(a0, a1);
23729            }
23730            return a1;
23731        } else {
23732            // If more than 3 arguments, parse storage to retrieve final node and set value
23733            // Get first level
23734            try {
23735                tmp = s.getItem(a0);
23736                if (tmp != null) {
23737                    to_store = JSON.parse(tmp);
23738                }
23739            } catch (e) {
23740            }
23741            tmp = to_store;
23742            // Parse next levels and set value
23743            for (var i = 1; i < l - 2; i++) {
23744                vi = a[i];
23745                type = isNaN(a[i+1])?"object":"array";
23746                if (!tmp[vi] || type == "object" && !$.isPlainObject(tmp[vi]) || type=="array" && !$.isArray(tmp[vi])) {
23747                    if(type=="array") tmp[vi] = [];
23748                    else tmp[vi] = {};
23749                }
23750                tmp = tmp[vi];
23751            }
23752            tmp[a[i]] = a[i + 1];
23753            s.setItem(a0, JSON.stringify(to_store));
23754            return to_store;
23755        }
23756    }
23757
23758    // Remove items from a storage
23759    function _remove() {
23760        var storage = this._type, l = arguments.length, s = window[storage], a = arguments, a0 = a[0], to_store, tmp;
23761        if (l < 1) {
23762            throw new Error('Minimum 1 argument must be given');
23763        } else if ($.isArray(a0)) {
23764            // If first argument is an array, remove values from storage for each item of this array
23765            for (var i in a0) {
23766                s.removeItem(a0[i]);
23767            }
23768            return true;
23769        } else if (l == 1) {
23770            // If only 2 arguments, remove value from storage directly
23771            s.removeItem(a0);
23772            return true;
23773        } else {
23774            // If more than 2 arguments, parse storage to retrieve final node and remove value
23775            // Get first level
23776            try {
23777                to_store = tmp = JSON.parse(s.getItem(a0));
23778            } catch (e) {
23779                throw new ReferenceError(a0 + ' is not defined in this storage');
23780            }
23781            // Parse next levels and remove value
23782            for (var i = 1; i < l - 1; i++) {
23783                tmp = tmp[a[i]];
23784                if (tmp === undefined) {
23785                    throw new ReferenceError([].slice.call(a, 1, i).join('.') + ' is not defined in this storage');
23786                }
23787            }
23788            // If last argument is an array,remove value for each item in this array
23789            // Else remove value normally
23790            if ($.isArray(a[i])) {
23791                for (var j in a[i]) {
23792                    delete tmp[a[i][j]];
23793                }
23794            } else {
23795                delete tmp[a[i]];
23796            }
23797            s.setItem(a0, JSON.stringify(to_store));
23798            return true;
23799        }
23800    }
23801
23802    // Remove all items from a storage
23803    function _removeAll(reinit_ns) {
23804        var keys = _keys.call(this);
23805        for (var i in keys) {
23806            _remove.call(this, keys[i]);
23807        }
23808        // Reinitialize all namespace storages
23809        if (reinit_ns) {
23810            for (var i in $.namespaceStorages) {
23811                _createNamespace(i);
23812            }
23813        }
23814    }
23815
23816    // Check if items of a storage are empty
23817    function _isEmpty() {
23818        var l = arguments.length, a = arguments, a0 = a[0];
23819        if (l == 0) {
23820            // If no argument, test if storage is empty
23821            return (_keys.call(this).length == 0);
23822        } else if ($.isArray(a0)) {
23823            // If first argument is an array, test each item of this array and return true only if all items are empty
23824            for (var i = 0; i < a0.length; i++) {
23825                if (!_isEmpty.call(this, a0[i])) {
23826                    return false;
23827                }
23828            }
23829            return true;
23830        } else {
23831            // If at least 1 argument, try to get value and test it
23832            try {
23833                var v = _get.apply(this, arguments);
23834                // Convert result to an object (if last argument is an array, _get return already an object) and test each item
23835                if (!$.isArray(a[l - 1])) {
23836                    v = {'totest': v};
23837                }
23838                for (var i in v) {
23839                    if (!(
23840                            ($.isPlainObject(v[i]) && $.isEmptyObject(v[i])) ||
23841                            ($.isArray(v[i]) && !v[i].length) ||
23842                            (!v[i])
23843                        )) {
23844                        return false;
23845                    }
23846                }
23847                return true;
23848            } catch (e) {
23849                return true;
23850            }
23851        }
23852    }
23853
23854    // Check if items of a storage exist
23855    function _isSet() {
23856        var l = arguments.length, a = arguments, a0 = a[0];
23857        if (l < 1) {
23858            throw new Error('Minimum 1 argument must be given');
23859        }
23860        if ($.isArray(a0)) {
23861            // If first argument is an array, test each item of this array and return true only if all items exist
23862            for (var i = 0; i < a0.length; i++) {
23863                if (!_isSet.call(this, a0[i])) {
23864                    return false;
23865                }
23866            }
23867            return true;
23868        } else {
23869            // For other case, try to get value and test it
23870            try {
23871                var v = _get.apply(this, arguments);
23872                // Convert result to an object (if last argument is an array, _get return already an object) and test each item
23873                if (!$.isArray(a[l - 1])) {
23874                    v = {'totest': v};
23875                }
23876                for (var i in v) {
23877                    if (!(v[i] !== undefined && v[i] !== null)) {
23878                        return false;
23879                    }
23880                }
23881                return true;
23882            } catch (e) {
23883                return false;
23884            }
23885        }
23886    }
23887
23888    // Get keys of a storage or of an item of the storage
23889    function _keys() {
23890        var storage = this._type, l = arguments.length, s = window[storage], a = arguments, keys = [], o = {};
23891        // If at least 1 argument, get value from storage to retrieve keys
23892        // Else, use storage to retrieve keys
23893        if (l > 0) {
23894            o = _get.apply(this, a);
23895        } else {
23896            o = s;
23897        }
23898        if (o && o._cookie) {
23899            // If storage is a cookie, use js-cookie to retrieve keys
23900            for (var key in Cookies.get()) {
23901                if (key != '') {
23902                    keys.push(key.replace(o._prefix, ''));
23903                }
23904            }
23905        } else {
23906            for (var i in o) {
23907                if (o.hasOwnProperty(i)) {
23908                    keys.push(i);
23909                }
23910            }
23911        }
23912        return keys;
23913    }
23914
23915    // Create new namespace storage
23916    function _createNamespace(name) {
23917        if (!name || typeof name != "string") {
23918            throw new Error('First parameter must be a string');
23919        }
23920        if (storage_available) {
23921            if (!window.localStorage.getItem(name)) {
23922                window.localStorage.setItem(name, '{}');
23923            }
23924            if (!window.sessionStorage.getItem(name)) {
23925                window.sessionStorage.setItem(name, '{}');
23926            }
23927        } else {
23928            if (!window.localCookieStorage.getItem(name)) {
23929                window.localCookieStorage.setItem(name, '{}');
23930            }
23931            if (!window.sessionCookieStorage.getItem(name)) {
23932                window.sessionCookieStorage.setItem(name, '{}');
23933            }
23934        }
23935        var ns = {
23936            localStorage: $.extend({}, $.localStorage, {_ns: name}),
23937            sessionStorage: $.extend({}, $.sessionStorage, {_ns: name})
23938        };
23939        if (typeof Cookies === 'object') {
23940            if (!window.cookieStorage.getItem(name)) {
23941                window.cookieStorage.setItem(name, '{}');
23942            }
23943            ns.cookieStorage = $.extend({}, $.cookieStorage, {_ns: name});
23944        }
23945        $.namespaceStorages[name] = ns;
23946        return ns;
23947    }
23948
23949    // Test if storage is natively available on browser
23950    function _testStorage(name) {
23951        var foo = 'jsapi';
23952        try {
23953            if (!window[name]) {
23954                return false;
23955            }
23956            window[name].setItem(foo, foo);
23957            window[name].removeItem(foo);
23958            return true;
23959        } catch (e) {
23960            return false;
23961        }
23962    }
23963
23964    // Check if storages are natively available on browser
23965    var storage_available = _testStorage('localStorage');
23966
23967    // Namespace object
23968    var storage = {
23969        _type: '',
23970        _ns: '',
23971        _callMethod: function (f, a) {
23972            var p = [], a = Array.prototype.slice.call(a), a0 = a[0];
23973
23974            if (this._ns) {
23975                p.push(this._ns);
23976            }
23977            if (typeof a0 === 'string' && a0.indexOf('.') !== -1) {
23978                a.shift();
23979                [].unshift.apply(a, a0.split('.'));
23980            }
23981            [].push.apply(p, a);
23982            return f.apply(this, p);
23983        },
23984        // Define if plugin always use JSON to store values (even to store simple values like string, int...) or not
23985        alwaysUseJson: false,
23986        // Get items. If no parameters and storage have a namespace, return all namespace
23987        get: function () {
23988            return this._callMethod(_get, arguments);
23989        },
23990        // Set items
23991        set: function () {
23992            var l = arguments.length, a = arguments, a0 = a[0];
23993            if (l < 1 || !$.isPlainObject(a0) && l < 2) {
23994                throw new Error('Minimum 2 arguments must be given or first parameter must be an object');
23995            }
23996            // If first argument is an object and storage is a namespace storage, set values individually
23997            if ($.isPlainObject(a0) && this._ns) {
23998                for (var i in a0) {
23999                    this._callMethod(_set, [i, a0[i]]);
24000                }
24001                return a0;
24002            } else {
24003                var r = this._callMethod(_set, a);
24004                if (this._ns) {
24005                    return r[a0.split('.')[0]];
24006                } else {
24007                    return r;
24008                }
24009            }
24010        },
24011        // Delete items
24012        remove: function () {
24013            if (arguments.length < 1) {
24014                throw new Error('Minimum 1 argument must be given');
24015            }
24016            return this._callMethod(_remove, arguments);
24017        },
24018        // Delete all items
24019        removeAll: function (reinit_ns) {
24020            if (this._ns) {
24021                this._callMethod(_set, [{}]);
24022                return true;
24023            } else {
24024                return this._callMethod(_removeAll, [reinit_ns]);
24025            }
24026        },
24027        // Items empty
24028        isEmpty: function () {
24029            return this._callMethod(_isEmpty, arguments);
24030        },
24031        // Items exists
24032        isSet: function () {
24033            if (arguments.length < 1) {
24034                throw new Error('Minimum 1 argument must be given');
24035            }
24036            return this._callMethod(_isSet, arguments);
24037        },
24038        // Get keys of items
24039        keys: function () {
24040            return this._callMethod(_keys, arguments);
24041        }
24042    };
24043
24044    // Use js-cookie for compatibility with old browsers and give access to cookieStorage
24045    if (typeof Cookies === 'object') {
24046        // sessionStorage is valid for one window/tab. To simulate that with cookie, we set a name for the window and use it for the name of the cookie
24047        if (!window.name) {
24048            window.name = Math.floor(Math.random() * 100000000);
24049        }
24050        var cookie_storage = {
24051            _cookie: true,
24052            _prefix: '',
24053            _expires: null,
24054            _path: null,
24055            _domain: null,
24056            setItem: function (n, v) {
24057                Cookies.set(this._prefix + n, v, {expires: this._expires, path: this._path, domain: this._domain});
24058            },
24059            getItem: function (n) {
24060                return Cookies.get(this._prefix + n);
24061            },
24062            removeItem: function (n) {
24063                return Cookies.remove(this._prefix + n, {path: this._path});
24064            },
24065            clear: function () {
24066                for (var key in Cookies.get()) {
24067                    if (key != '') {
24068                        if (!this._prefix && key.indexOf(cookie_local_prefix) === -1 && key.indexOf(cookie_session_prefix) === -1 || this._prefix && key.indexOf(this._prefix) === 0) {
24069                            $.removeCookie(key);
24070                        }
24071                    }
24072                }
24073            },
24074            setExpires: function (e) {
24075                this._expires = e;
24076                return this;
24077            },
24078            setPath: function (p) {
24079                this._path = p;
24080                return this;
24081            },
24082            setDomain: function (d) {
24083                this._domain = d;
24084                return this;
24085            },
24086            setConf: function (c) {
24087                if (c.path) {
24088                    this._path = c.path;
24089                }
24090                if (c.domain) {
24091                    this._domain = c.domain;
24092                }
24093                if (c.expires) {
24094                    this._expires = c.expires;
24095                }
24096                return this;
24097            },
24098            setDefaultConf: function () {
24099                this._path = this._domain = this._expires = null;
24100            }
24101        };
24102        if (!storage_available) {
24103            window.localCookieStorage = $.extend({}, cookie_storage, {
24104                _prefix: cookie_local_prefix,
24105                _expires: 365 * 10
24106            });
24107            window.sessionCookieStorage = $.extend({}, cookie_storage, {_prefix: cookie_session_prefix + window.name + '_'});
24108        }
24109        window.cookieStorage = $.extend({}, cookie_storage);
24110        // cookieStorage API
24111        $.cookieStorage = $.extend({}, storage, {
24112            _type: 'cookieStorage',
24113            setExpires: function (e) {
24114                window.cookieStorage.setExpires(e);
24115                return this;
24116            },
24117            setPath: function (p) {
24118                window.cookieStorage.setPath(p);
24119                return this;
24120            },
24121            setDomain: function (d) {
24122                window.cookieStorage.setDomain(d);
24123                return this;
24124            },
24125            setConf: function (c) {
24126                window.cookieStorage.setConf(c);
24127                return this;
24128            },
24129            setDefaultConf: function () {
24130                window.cookieStorage.setDefaultConf();
24131                return this;
24132            }
24133        });
24134    }
24135
24136    // Get a new API on a namespace
24137    $.initNamespaceStorage = function (ns) {
24138        return _createNamespace(ns);
24139    };
24140    if (storage_available) {
24141        // About alwaysUseJson
24142        // By default, all values are string on html storages and the plugin don't use json to store simple values (strings, int, float...)
24143        // So by default, if you do storage.setItem('test',2), value in storage will be "2", not 2
24144        // If you set this property to true, all values set with the plugin will be stored as json to have typed values in any cases
24145
24146        // localStorage API
24147        $.localStorage = $.extend({}, storage, {_type: 'localStorage'});
24148        // sessionStorage API
24149        $.sessionStorage = $.extend({}, storage, {_type: 'sessionStorage'});
24150    } else {
24151        // localStorage API
24152        $.localStorage = $.extend({}, storage, {_type: 'localCookieStorage'});
24153        // sessionStorage API
24154        $.sessionStorage = $.extend({}, storage, {_type: 'sessionCookieStorage'});
24155    }
24156    // List of all namespace storage
24157    $.namespaceStorages = {};
24158    // Remove all items in all storages
24159    $.removeAllStorages = function (reinit_ns) {
24160        $.localStorage.removeAll(reinit_ns);
24161        $.sessionStorage.removeAll(reinit_ns);
24162        if ($.cookieStorage) {
24163            $.cookieStorage.removeAll(reinit_ns);
24164        }
24165        if (!reinit_ns) {
24166            $.namespaceStorages = {};
24167        }
24168    }
24169    $.alwaysUseJsonInStorage = function (value) {
24170        storage.alwaysUseJson = value;
24171        $.localStorage.alwaysUseJson = value;
24172        $.sessionStorage.alwaysUseJson = value;
24173        if ($.cookieStorage) {
24174            $.cookieStorage.alwaysUseJson = value;
24175        }
24176    }
24177}));
24178
24179/*!
24180 * imagesLoaded v4.1.0
24181 * JavaScript is all like "You images are done yet or what?"
24182 * MIT License
24183 */
24184
24185( function( window, factory ) { 'use strict';
24186  // universal module definition
24187
24188  /*global define: false, module: false, require: false */
24189
24190  if ( typeof define == 'function' && define.amd ) {
24191    // AMD
24192    define( [
24193      'ev-emitter/ev-emitter'
24194    ], function( EvEmitter ) {
24195      return factory( window, EvEmitter );
24196    });
24197  } else if ( typeof module == 'object' && module.exports ) {
24198    // CommonJS
24199    module.exports = factory(
24200      window,
24201      require('ev-emitter')
24202    );
24203  } else {
24204    // browser global
24205    window.imagesLoaded = factory(
24206      window,
24207      window.EvEmitter
24208    );
24209  }
24210
24211})( window,
24212
24213// --------------------------  factory -------------------------- //
24214
24215function factory( window, EvEmitter ) {
24216
24217'use strict';
24218
24219var $ = window.jQuery;
24220var console = window.console;
24221
24222// -------------------------- helpers -------------------------- //
24223
24224// extend objects
24225function extend( a, b ) {
24226  for ( var prop in b ) {
24227    a[ prop ] = b[ prop ];
24228  }
24229  return a;
24230}
24231
24232// turn element or nodeList into an array
24233function makeArray( obj ) {
24234  var ary = [];
24235  if ( Array.isArray( obj ) ) {
24236    // use object if already an array
24237    ary = obj;
24238  } else if ( typeof obj.length == 'number' ) {
24239    // convert nodeList to array
24240    for ( var i=0; i < obj.length; i++ ) {
24241      ary.push( obj[i] );
24242    }
24243  } else {
24244    // array of single index
24245    ary.push( obj );
24246  }
24247  return ary;
24248}
24249
24250// -------------------------- imagesLoaded -------------------------- //
24251
24252/**
24253 * @param {Array, Element, NodeList, String} elem
24254 * @param {Object or Function} options - if function, use as callback
24255 * @param {Function} onAlways - callback function
24256 */
24257function ImagesLoaded( elem, options, onAlways ) {
24258  // coerce ImagesLoaded() without new, to be new ImagesLoaded()
24259  if ( !( this instanceof ImagesLoaded ) ) {
24260    return new ImagesLoaded( elem, options, onAlways );
24261  }
24262  // use elem as selector string
24263  if ( typeof elem == 'string' ) {
24264    elem = document.querySelectorAll( elem );
24265  }
24266
24267  this.elements = makeArray( elem );
24268  this.options = extend( {}, this.options );
24269
24270  if ( typeof options == 'function' ) {
24271    onAlways = options;
24272  } else {
24273    extend( this.options, options );
24274  }
24275
24276  if ( onAlways ) {
24277    this.on( 'always', onAlways );
24278  }
24279
24280  this.getImages();
24281
24282  if ( $ ) {
24283    // add jQuery Deferred object
24284    this.jqDeferred = new $.Deferred();
24285  }
24286
24287  // HACK check async to allow time to bind listeners
24288  setTimeout( function() {
24289    this.check();
24290  }.bind( this ));
24291}
24292
24293ImagesLoaded.prototype = Object.create( EvEmitter.prototype );
24294
24295ImagesLoaded.prototype.options = {};
24296
24297ImagesLoaded.prototype.getImages = function() {
24298  this.images = [];
24299
24300  // filter & find items if we have an item selector
vendor: 6,811 bytes, lines 24301-24549
24301  this.elements.forEach( this.addElementImages, this );
24302};
24303
24304/**
24305 * @param {Node} element
24306 */
24307ImagesLoaded.prototype.addElementImages = function( elem ) {
24308  // filter siblings
24309  if ( elem.nodeName == 'IMG' ) {
24310    this.addImage( elem );
24311  }
24312  // get background image on element
24313  if ( this.options.background === true ) {
24314    this.addElementBackgroundImages( elem );
24315  }
24316
24317  // find children
24318  // no non-element nodes, #143
24319  var nodeType = elem.nodeType;
24320  if ( !nodeType || !elementNodeTypes[ nodeType ] ) {
24321    return;
24322  }
24323  var childImgs = elem.querySelectorAll('img');
24324  // concat childElems to filterFound array
24325  for ( var i=0; i < childImgs.length; i++ ) {
24326    var img = childImgs[i];
24327    this.addImage( img );
24328  }
24329
24330  // get child background images
24331  if ( typeof this.options.background == 'string' ) {
24332    var children = elem.querySelectorAll( this.options.background );
24333    for ( i=0; i < children.length; i++ ) {
24334      var child = children[i];
24335      this.addElementBackgroundImages( child );
24336    }
24337  }
24338};
24339
24340var elementNodeTypes = {
24341  1: true,
24342  9: true,
24343  11: true
24344};
24345
24346ImagesLoaded.prototype.addElementBackgroundImages = function( elem ) {
24347  var style = getComputedStyle( elem );
24348  if ( !style ) {
24349    // Firefox returns null if in a hidden iframe https://bugzil.la/548397
24350    return;
24351  }
24352  // get url inside url("...")
24353  var reURL = /url\((['"])?(.*?)\1\)/gi;
24354  var matches = reURL.exec( style.backgroundImage );
24355  while ( matches !== null ) {
24356    var url = matches && matches[2];
24357    if ( url ) {
24358      this.addBackground( url, elem );
24359    }
24360    matches = reURL.exec( style.backgroundImage );
24361  }
24362};
24363
24364/**
24365 * @param {Image} img
24366 */
24367ImagesLoaded.prototype.addImage = function( img ) {
24368  var loadingImage = new LoadingImage( img );
24369  this.images.push( loadingImage );
24370};
24371
24372ImagesLoaded.prototype.addBackground = function( url, elem ) {
24373  var background = new Background( url, elem );
24374  this.images.push( background );
24375};
24376
24377ImagesLoaded.prototype.check = function() {
24378  var _this = this;
24379  this.progressedCount = 0;
24380  this.hasAnyBroken = false;
24381  // complete if no images
24382  if ( !this.images.length ) {
24383    this.complete();
24384    return;
24385  }
24386
24387  function onProgress( image, elem, message ) {
24388    // HACK - Chrome triggers event before object properties have changed. #83
24389    setTimeout( function() {
24390      _this.progress( image, elem, message );
24391    });
24392  }
24393
24394  this.images.forEach( function( loadingImage ) {
24395    loadingImage.once( 'progress', onProgress );
24396    loadingImage.check();
24397  });
24398};
24399
24400ImagesLoaded.prototype.progress = function( image, elem, message ) {
24401  this.progressedCount++;
24402  this.hasAnyBroken = this.hasAnyBroken || !image.isLoaded;
24403  // progress event
24404  this.emitEvent( 'progress', [ this, image, elem ] );
24405  if ( this.jqDeferred && this.jqDeferred.notify ) {
24406    this.jqDeferred.notify( this, image );
24407  }
24408  // check if completed
24409  if ( this.progressedCount == this.images.length ) {
24410    this.complete();
24411  }
24412
24413  if ( this.options.debug && console ) {
24414    console.log( 'progress: ' + message, image, elem );
24415  }
24416};
24417
24418ImagesLoaded.prototype.complete = function() {
24419  var eventName = this.hasAnyBroken ? 'fail' : 'done';
24420  this.isComplete = true;
24421  this.emitEvent( eventName, [ this ] );
24422  this.emitEvent( 'always', [ this ] );
24423  if ( this.jqDeferred ) {
24424    var jqMethod = this.hasAnyBroken ? 'reject' : 'resolve';
24425    this.jqDeferred[ jqMethod ]( this );
24426  }
24427};
24428
24429// --------------------------  -------------------------- //
24430
24431function LoadingImage( img ) {
24432  this.img = img;
24433}
24434
24435LoadingImage.prototype = Object.create( EvEmitter.prototype );
24436
24437LoadingImage.prototype.check = function() {
24438  // If complete is true and browser supports natural sizes,
24439  // try to check for image status manually.
24440  var isComplete = this.getIsImageComplete();
24441  if ( isComplete ) {
24442    // report based on naturalWidth
24443    this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' );
24444    return;
24445  }
24446
24447  // If none of the checks above matched, simulate loading on detached element.
24448  this.proxyImage = new Image();
24449  this.proxyImage.addEventListener( 'load', this );
24450  this.proxyImage.addEventListener( 'error', this );
24451  // bind to image as well for Firefox. #191
24452  this.img.addEventListener( 'load', this );
24453  this.img.addEventListener( 'error', this );
24454  this.proxyImage.src = this.img.src;
24455};
24456
24457LoadingImage.prototype.getIsImageComplete = function() {
24458  return this.img.complete && this.img.naturalWidth !== undefined;
24459};
24460
24461LoadingImage.prototype.confirm = function( isLoaded, message ) {
24462  this.isLoaded = isLoaded;
24463  this.emitEvent( 'progress', [ this, this.img, message ] );
24464};
24465
24466// ----- events ----- //
24467
24468// trigger specified handler for event type
24469LoadingImage.prototype.handleEvent = function( event ) {
24470  var method = 'on' + event.type;
24471  if ( this[ method ] ) {
24472    this[ method ]( event );
24473  }
24474};
24475
24476LoadingImage.prototype.onload = function() {
24477  this.confirm( true, 'onload' );
24478  this.unbindEvents();
24479};
24480
24481LoadingImage.prototype.onerror = function() {
24482  this.confirm( false, 'onerror' );
24483  this.unbindEvents();
24484};
24485
24486LoadingImage.prototype.unbindEvents = function() {
24487  this.proxyImage.removeEventListener( 'load', this );
24488  this.proxyImage.removeEventListener( 'error', this );
24489  this.img.removeEventListener( 'load', this );
24490  this.img.removeEventListener( 'error', this );
24491};
24492
24493// -------------------------- Background -------------------------- //
24494
24495function Background( url, element ) {
24496  this.url = url;
24497  this.element = element;
24498  this.img = new Image();
24499}
24500
24501// inherit LoadingImage prototype
24502Background.prototype = Object.create( LoadingImage.prototype );
24503
24504Background.prototype.check = function() {
24505  this.img.addEventListener( 'load', this );
24506  this.img.addEventListener( 'error', this );
24507  this.img.src = this.url;
24508  // check if image is already complete
24509  var isComplete = this.getIsImageComplete();
24510  if ( isComplete ) {
24511    this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' );
24512    this.unbindEvents();
24513  }
24514};
24515
24516Background.prototype.unbindEvents = function() {
24517  this.img.removeEventListener( 'load', this );
24518  this.img.removeEventListener( 'error', this );
24519};
24520
24521Background.prototype.confirm = function( isLoaded, message ) {
24522  this.isLoaded = isLoaded;
24523  this.emitEvent( 'progress', [ this, this.element, message ] );
24524};
24525
24526// -------------------------- jQuery -------------------------- //
24527
24528ImagesLoaded.makeJQueryPlugin = function( jQuery ) {
24529  jQuery = jQuery || window.jQuery;
24530  if ( !jQuery ) {
24531    return;
24532  }
24533  // set local variable
24534  $ = jQuery;
24535  // $().imagesLoaded()
24536  $.fn.imagesLoaded = function( options, callback ) {
24537    var instance = new ImagesLoaded( this, options, callback );
24538    return instance.jqDeferred.promise( $(this) );
24539  };
24540};
24541// try making plugin
24542ImagesLoaded.makeJQueryPlugin();
24543
24544// --------------------------  -------------------------- //
24545
24546return ImagesLoaded;
24547
24548});
24549
vendor: 44,277 bytes, lines 24550-26381
24550/*!
24551 * fancyBox - jQuery Plugin
24552 * version: 2.1.5 (Fri, 14 Jun 2013)
24553 * requires jQuery v1.6 or later
24554 *
24555 * Examples at http://fancyapps.com/fancybox/
24556 * License: www.fancyapps.com/fancybox/#license
24557 *
24558 * Copyright 2012 Janis Skarnelis - [email protected]
24559 *
24560 */
24561
24562;(function (window, document, $, undefined) {
24563	"use strict";
24564
24565	var H = $("html"),
24566		W = $(window),
24567		D = $(document),
24568		F = $.fancybox = function () {
24569			F.open.apply( this, arguments );
24570		},
24571		IE =  navigator.userAgent.match(/msie/i),
24572		didUpdate	= null,
24573		isTouch		= document.createTouch !== undefined,
24574
24575		isQuery	= function(obj) {
24576			return obj && obj.hasOwnProperty && obj instanceof $;
24577		},
24578		isString = function(str) {
24579			return str && $.type(str) === "string";
24580		},
24581		isPercentage = function(str) {
24582			return isString(str) && str.indexOf('%') > 0;
24583		},
24584		isScrollable = function(el) {
24585			return (el && !(el.style.overflow && el.style.overflow === 'hidden') && ((el.clientWidth && el.scrollWidth > el.clientWidth) || (el.clientHeight && el.scrollHeight > el.clientHeight)));
24586		},
24587		getScalar = function(orig, dim) {
24588			var value = parseInt(orig, 10) || 0;
24589
24590			if (dim && isPercentage(orig)) {
24591				value = F.getViewport()[ dim ] / 100 * value;
24592			}
24593
24594			return Math.ceil(value);
24595		},
24596		getValue = function(value, dim) {
24597			return getScalar(value, dim) + 'px';
24598		};
24599
24600	$.extend(F, {
24601		// The current version of fancyBox
24602		version: '2.1.5',
24603
24604		defaults: {
24605			padding : 15,
24606			margin  : 20,
24607
24608			width     : 800,
24609			height    : 600,
24610			minWidth  : 100,
24611			minHeight : 100,
24612			maxWidth  : 9999,
24613			maxHeight : 9999,
24614			pixelRatio: 1, // Set to 2 for retina display support
24615
24616			autoSize   : true,
24617			autoHeight : false,
24618			autoWidth  : false,
24619
24620			autoResize  : true,
24621			autoCenter  : !isTouch,
24622			fitToView   : true,
24623			aspectRatio : false,
24624			topRatio    : 0.5,
24625			leftRatio   : 0.5,
24626
24627			scrolling : 'auto', // 'auto', 'yes' or 'no'
24628			wrapCSS   : '',
24629
24630			arrows     : true,
24631			closeBtn   : true,
24632			closeClick : false,
24633			nextClick  : false,
24634			mouseWheel : true,
24635			autoPlay   : false,
24636			playSpeed  : 3000,
24637			preload    : 3,
24638			modal      : false,
24639			loop       : true,
24640
24641			ajax  : {
24642				dataType : 'html',
24643				headers  : { 'X-fancyBox': true }
24644			},
24645			iframe : {
24646				scrolling : 'auto',
24647				preload   : true
24648			},
24649			swf : {
24650				wmode: 'transparent',
24651				allowfullscreen   : 'true',
24652				allowscriptaccess : 'always'
24653			},
24654
24655			keys  : {
24656				next : {
24657					13 : 'left', // enter
24658					34 : 'up',   // page down
24659					39 : 'left', // right arrow
24660					40 : 'up'    // down arrow
24661				},
24662				prev : {
24663					8  : 'right',  // backspace
24664					33 : 'down',   // page up
24665					37 : 'right',  // left arrow
24666					38 : 'down'    // up arrow
24667				},
24668				close  : [27], // escape key
24669				play   : [32], // space - start/stop slideshow
24670				toggle : [70]  // letter "f" - toggle fullscreen
24671			},
24672
24673			direction : {
24674				next : 'left',
24675				prev : 'right'
24676			},
24677
24678			scrollOutside  : true,
24679
24680			// Override some properties
24681			index   : 0,
24682			type    : null,
24683			href    : null,
24684			content : null,
24685			title   : null,
24686
24687			// HTML templates
24688			tpl: {
24689				wrap     : '<div class="fancybox-wrap" tabIndex="-1"><div class="fancybox-skin"><div class="fancybox-outer"><div class="fancybox-inner"></div></div></div></div>',
24690				image    : '<img class="fancybox-image" src="{href}" alt="" />',
24691				iframe   : '<iframe id="fancybox-frame{rnd}" name="fancybox-frame{rnd}" class="fancybox-iframe" frameborder="0" vspace="0" hspace="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen' + (IE ? ' allowtransparency="true"' : '') + '></iframe>',
24692				error    : '<p class="fancybox-error">The requested content cannot be loaded.<br/>Please try again later.</p>',
24693				closeBtn : '<a title="Close" class="fancybox-item fancybox-close" href="javascript:;"></a>',
24694				next     : '<a title="Next" class="fancybox-nav fancybox-next" href="javascript:;"><span></span></a>',
24695				prev     : '<a title="Previous" class="fancybox-nav fancybox-prev" href="javascript:;"><span></span></a>',
24696				loading  : '<div id="fancybox-loading"><div></div></div>'
24697			},
24698
24699			// Properties for each animation type
24700			// Opening fancyBox
24701			openEffect  : 'fade', // 'elastic', 'fade' or 'none'
24702			openSpeed   : 250,
24703			openEasing  : 'swing',
24704			openOpacity : true,
24705			openMethod  : 'zoomIn',
24706
24707			// Closing fancyBox
24708			closeEffect  : 'fade', // 'elastic', 'fade' or 'none'
24709			closeSpeed   : 250,
24710			closeEasing  : 'swing',
24711			closeOpacity : true,
24712			closeMethod  : 'zoomOut',
24713
24714			// Changing next gallery item
24715			nextEffect : 'elastic', // 'elastic', 'fade' or 'none'
24716			nextSpeed  : 250,
24717			nextEasing : 'swing',
24718			nextMethod : 'changeIn',
24719
24720			// Changing previous gallery item
24721			prevEffect : 'elastic', // 'elastic', 'fade' or 'none'
24722			prevSpeed  : 250,
24723			prevEasing : 'swing',
24724			prevMethod : 'changeOut',
24725
24726			// Enable default helpers
24727			helpers : {
24728				overlay : true,
24729				title   : true
24730			},
24731
24732			// Callbacks
24733			onCancel     : $.noop, // If canceling
24734			beforeLoad   : $.noop, // Before loading
24735			afterLoad    : $.noop, // After loading
24736			beforeShow   : $.noop, // Before changing in current item
24737			afterShow    : $.noop, // After opening
24738			beforeChange : $.noop, // Before changing gallery item
24739			beforeClose  : $.noop, // Before closing
24740			afterClose   : $.noop  // After closing
24741		},
24742
24743		//Current state
24744		group    : {}, // Selected group
24745		opts     : {}, // Group options
24746		previous : null,  // Previous element
24747		coming   : null,  // Element being loaded
24748		current  : null,  // Currently loaded element
24749		isActive : false, // Is activated
24750		isOpen   : false, // Is currently open
24751		isOpened : false, // Have been fully opened at least once
24752
24753		wrap  : null,
24754		skin  : null,
24755		outer : null,
24756		inner : null,
24757
24758		player : {
24759			timer    : null,
24760			isActive : false
24761		},
24762
24763		// Loaders
24764		ajaxLoad   : null,
24765		imgPreload : null,
24766
24767		// Some collections
24768		transitions : {},
24769		helpers     : {},
24770
24771		/*
24772		 *	Static methods
24773		 */
24774
24775		open: function (group, opts) {
24776			if (!group) {
24777				return;
24778			}
24779
24780			if (!$.isPlainObject(opts)) {
24781				opts = {};
24782			}
24783
24784			// Close if already active
24785			if (false === F.close(true)) {
24786				return;
24787			}
24788
24789			// Normalize group
24790			if (!$.isArray(group)) {
24791				group = isQuery(group) ? $(group).get() : [group];
24792			}
24793
24794			// Recheck if the type of each element is `object` and set content type (image, ajax, etc)
24795			$.each(group, function(i, element) {
24796				var obj = {},
24797					href,
24798					title,
24799					content,
24800					type,
24801					rez,
24802					hrefParts,
24803					selector;
24804
24805				if ($.type(element) === "object") {
24806					// Check if is DOM element
24807					if (element.nodeType) {
24808						element = $(element);
24809					}
24810
24811					if (isQuery(element)) {
24812						obj = {
24813							href    : element.data('fancybox-href') || element.attr('href'),
24814							title   : $('<div/>').text( element.data('fancybox-title') || element.attr('title') || '' ).html(),
24815							isDom   : true,
24816							element : element
24817						};
24818
24819						if ($.metadata) {
24820							$.extend(true, obj, element.metadata());
24821						}
24822
24823					} else {
24824						obj = element;
24825					}
24826				}
24827
24828				href  = opts.href  || obj.href || (isString(element) ? element : null);
24829				title = opts.title !== undefined ? opts.title : obj.title || '';
24830
24831				content = opts.content || obj.content;
24832				type    = content ? 'html' : (opts.type  || obj.type);
24833
24834				if (!type && obj.isDom) {
24835					type = element.data('fancybox-type');
24836
24837					if (!type) {
24838						rez  = element.prop('class').match(/fancybox\.(\w+)/);
24839						type = rez ? rez[1] : null;
24840					}
24841				}
24842
24843				if (isString(href)) {
24844					// Try to guess the content type
24845					if (!type) {
24846						if (F.isImage(href)) {
24847							type = 'image';
24848
24849						} else if (F.isSWF(href)) {
24850							type = 'swf';
24851
24852						} else if (href.charAt(0) === '#') {
24853							type = 'inline';
24854
24855						} else if (isString(element)) {
24856							type    = 'html';
24857							content = element;
24858						}
24859					}
24860
24861					// Split url into two pieces with source url and content selector, e.g,
24862					// "/mypage.html #my_id" will load "/mypage.html" and display element having id "my_id"
24863					if (type === 'ajax') {
24864						hrefParts = href.split(/\s+/, 2);
24865						href      = hrefParts.shift();
24866						selector  = hrefParts.shift();
24867					}
24868				}
24869
24870				if (!content) {
24871					if (type === 'inline') {
24872						if (href) {
24873							content = $( isString(href) ? href.replace(/.*(?=#[^\s]+$)/, '') : href ); //strip for ie7
24874
24875						} else if (obj.isDom) {
24876							content = element;
24877						}
24878
24879					} else if (type === 'html') {
24880						content = href;
24881
24882					} else if (!type && !href && obj.isDom) {
24883						type    = 'inline';
24884						content = element;
24885					}
24886				}
24887
24888				$.extend(obj, {
24889					href     : href,
24890					type     : type,
24891					content  : content,
24892					title    : title,
24893					selector : selector
24894				});
24895
24896				group[ i ] = obj;
24897			});
24898
24899			// Extend the defaults
24900			F.opts = $.extend(true, {}, F.defaults, opts);
24901
24902			// All options are merged recursive except keys
24903			if (opts.keys !== undefined) {
24904				F.opts.keys = opts.keys ? $.extend({}, F.defaults.keys, opts.keys) : false;
24905			}
24906
24907			F.group = group;
24908
24909			return F._start(F.opts.index);
24910		},
24911
24912		// Cancel image loading or abort ajax request
24913		cancel: function () {
24914			var coming = F.coming;
24915
24916			if (coming && false === F.trigger('onCancel')) {
24917				return;
24918			}
24919
24920			F.hideLoading();
24921
24922			if (!coming) {
24923				return;
24924			}
24925
24926			if (F.ajaxLoad) {
24927				F.ajaxLoad.abort();
24928			}
24929
24930			F.ajaxLoad = null;
24931
24932			if (F.imgPreload) {
24933				F.imgPreload.onload = F.imgPreload.onerror = null;
24934			}
24935
24936			if (coming.wrap) {
24937				coming.wrap.stop(true, true).trigger('onReset').remove();
24938			}
24939
24940			F.coming = null;
24941
24942			// If the first item has been canceled, then clear everything
24943			if (!F.current) {
24944				F._afterZoomOut( coming );
24945			}
24946		},
24947
24948		// Start closing animation if is open; remove immediately if opening/closing
24949		close: function (event) {
24950			F.cancel();
24951
24952			if (false === F.trigger('beforeClose')) {
24953				return;
24954			}
24955
24956			F.unbindEvents();
24957
24958			if (!F.isActive) {
24959				return;
24960			}
24961
24962			if (!F.isOpen || event === true) {
24963				$('.fancybox-wrap').stop(true).trigger('onReset').remove();
24964
24965				F._afterZoomOut();
24966
24967			} else {
24968				F.isOpen = F.isOpened = false;
24969				F.isClosing = true;
24970
24971				$('.fancybox-item, .fancybox-nav').remove();
24972
24973				F.wrap.stop(true, true).removeClass('fancybox-opened');
24974
24975				F.transitions[ F.current.closeMethod ]();
24976			}
24977		},
24978
24979		// Manage slideshow:
24980		//   $.fancybox.play(); - toggle slideshow
24981		//   $.fancybox.play( true ); - start
24982		//   $.fancybox.play( false ); - stop
24983		play: function ( action ) {
24984			var clear = function () {
24985					clearTimeout(F.player.timer);
24986				},
24987				set = function () {
24988					clear();
24989
24990					if (F.current && F.player.isActive) {
24991						F.player.timer = setTimeout(F.next, F.current.playSpeed);
24992					}
24993				},
24994				stop = function () {
24995					clear();
24996
24997					D.unbind('.player');
24998
24999					F.player.isActive = false;
25000
25001					F.trigger('onPlayEnd');
25002				},
25003				start = function () {
25004					if (F.current && (F.current.loop || F.current.index < F.group.length - 1)) {
25005						F.player.isActive = true;
25006
25007						D.bind({
25008							'onCancel.player beforeClose.player' : stop,
25009							'onUpdate.player'   : set,
25010							'beforeLoad.player' : clear
25011						});
25012
25013						set();
25014
25015						F.trigger('onPlayStart');
25016					}
25017				};
25018
25019			if (action === true || (!F.player.isActive && action !== false)) {
25020				start();
25021			} else {
25022				stop();
25023			}
25024		},
25025
25026		// Navigate to next gallery item
25027		next: function ( direction ) {
25028			var current = F.current;
25029
25030			if (current) {
25031				if (!isString(direction)) {
25032					direction = current.direction.next;
25033				}
25034
25035				F.jumpto(current.index + 1, direction, 'next');
25036			}
25037		},
25038
25039		// Navigate to previous gallery item
25040		prev: function ( direction ) {
25041			var current = F.current;
25042
25043			if (current) {
25044				if (!isString(direction)) {
25045					direction = current.direction.prev;
25046				}
25047
25048				F.jumpto(current.index - 1, direction, 'prev');
25049			}
25050		},
25051
25052		// Navigate to gallery item by index
25053		jumpto: function ( index, direction, router ) {
25054			var current = F.current;
25055
25056			if (!current) {
25057				return;
25058			}
25059
25060			index = getScalar(index);
25061
25062			F.direction = direction || current.direction[ (index >= current.index ? 'next' : 'prev') ];
25063			F.router    = router || 'jumpto';
25064
25065			if (current.loop) {
25066				if (index < 0) {
25067					index = current.group.length + (index % current.group.length);
25068				}
25069
25070				index = index % current.group.length;
25071			}
25072
25073			if (current.group[ index ] !== undefined) {
25074				F.cancel();
25075
25076				F._start(index);
25077			}
25078		},
25079
25080		// Center inside viewport and toggle position type to fixed or absolute if needed
25081		reposition: function (e, onlyAbsolute) {
25082			var current = F.current,
25083				wrap    = current ? current.wrap : null,
25084				pos;
25085
25086			if (wrap) {
25087				pos = F._getPosition(onlyAbsolute);
25088
25089				if (e && e.type === 'scroll') {
25090					delete pos.position;
25091
25092					wrap.stop(true, true).animate(pos, 200);
25093
25094				} else {
25095					wrap.css(pos);
25096
25097					current.pos = $.extend({}, current.dim, pos);
25098				}
25099			}
25100		},
25101
25102		update: function (e) {
25103			var type = (e && e.originalEvent && e.originalEvent.type),
25104				anyway = !type || type === 'orientationchange';
25105
25106			if (anyway) {
25107				clearTimeout(didUpdate);
25108
25109				didUpdate = null;
25110			}
25111
25112			if (!F.isOpen || didUpdate) {
25113				return;
25114			}
25115
25116			didUpdate = setTimeout(function() {
25117				var current = F.current;
25118
25119				if (!current || F.isClosing) {
25120					return;
25121				}
25122
25123				F.wrap.removeClass('fancybox-tmp');
25124
25125				if (anyway || type === 'load' || (type === 'resize' && current.autoResize)) {
25126					F._setDimension();
25127				}
25128
25129				if (!(type === 'scroll' && current.canShrink)) {
25130					F.reposition(e);
25131				}
25132
25133				F.trigger('onUpdate');
25134
25135				didUpdate = null;
25136
25137			}, (anyway && !isTouch ? 0 : 300));
25138		},
25139
25140		// Shrink content to fit inside viewport or restore if resized
25141		toggle: function ( action ) {
25142			if (F.isOpen) {
25143				F.current.fitToView = $.type(action) === "boolean" ? action : !F.current.fitToView;
25144
25145				// Help browser to restore document dimensions
25146				if (isTouch) {
25147					F.wrap.removeAttr('style').addClass('fancybox-tmp');
25148
25149					F.trigger('onUpdate');
25150				}
25151
25152				F.update();
25153			}
25154		},
25155
25156		hideLoading: function () {
25157			D.unbind('.loading');
25158
25159			$('#fancybox-loading').remove();
25160		},
25161
25162		showLoading: function () {
25163			var el, viewport;
25164
25165			F.hideLoading();
25166
25167			el = $(F.opts.tpl.loading).click(F.cancel).appendTo('body');
25168
25169			// If user will press the escape-button, the request will be canceled
25170			D.bind('keydown.loading', function(e) {
25171				if ((e.which || e.keyCode) === 27) {
25172					e.preventDefault();
25173
25174					F.cancel();
25175				}
25176			});
25177
25178			if (!F.defaults.fixed) {
25179				viewport = F.getViewport();
25180
25181				el.css({
25182					position : 'absolute',
25183					top  : (viewport.h * 0.5) + viewport.y,
25184					left : (viewport.w * 0.5) + viewport.x
25185				});
25186			}
25187
25188			F.trigger('onLoading');
25189		},
25190
25191		getViewport: function () {
25192			var locked = (F.current && F.current.locked) || false,
25193				rez    = {
25194					x: W.scrollLeft(),
25195					y: W.scrollTop()
25196				};
25197
25198			if (locked && locked.length) {
25199				rez.w = locked[0].clientWidth;
25200				rez.h = locked[0].clientHeight;
25201
25202			} else {
25203				// See http://bugs.jquery.com/ticket/6724
25204				rez.w = isTouch && window.innerWidth  ? window.innerWidth  : W.width();
25205				rez.h = isTouch && window.innerHeight ? window.innerHeight : W.height();
25206			}
25207
25208			return rez;
25209		},
25210
25211		// Unbind the keyboard / clicking actions
25212		unbindEvents: function () {
25213			if (F.wrap && isQuery(F.wrap)) {
25214				F.wrap.unbind('.fb');
25215			}
25216
25217			D.unbind('.fb');
25218			W.unbind('.fb');
25219		},
25220
25221		bindEvents: function () {
25222			var current = F.current,
25223				keys;
25224
25225			if (!current) {
25226				return;
25227			}
25228
25229			// Changing document height on iOS devices triggers a 'resize' event,
25230			// that can change document height... repeating infinitely
25231			W.bind('orientationchange.fb' + (isTouch ? '' : ' resize.fb') + (current.autoCenter && !current.locked ? ' scroll.fb' : ''), F.update);
25232
25233			keys = current.keys;
25234
25235			if (keys) {
25236				D.bind('keydown.fb', function (e) {
25237					var code   = e.which || e.keyCode,
25238						target = e.target || e.srcElement;
25239
25240					// Skip esc key if loading, because showLoading will cancel preloading
25241					if (code === 27 && F.coming) {
25242						return false;
25243					}
25244
25245					// Ignore key combinations and key events within form elements
25246					if (!e.ctrlKey && !e.altKey && !e.shiftKey && !e.metaKey && !(target && (target.type || $(target).is('[contenteditable]')))) {
25247						$.each(keys, function(i, val) {
25248							if (current.group.length > 1 && val[ code ] !== undefined) {
25249								F[ i ]( val[ code ] );
25250
25251								e.preventDefault();
25252								return false;
25253							}
25254
25255							if ($.inArray(code, val) > -1) {
25256								F[ i ] ();
25257
25258								e.preventDefault();
25259								return false;
25260							}
25261						});
25262					}
25263				});
25264			}
25265
25266			if ($.fn.mousewheel && current.mouseWheel) {
25267				F.wrap.bind('mousewheel.fb', function (e, delta, deltaX, deltaY) {
25268					var target = e.target || null,
25269						parent = $(target),
25270						canScroll = false;
25271
25272					while (parent.length) {
25273						if (canScroll || parent.is('.fancybox-skin') || parent.is('.fancybox-wrap')) {
25274							break;
25275						}
25276
25277						canScroll = isScrollable( parent[0] );
25278						parent    = $(parent).parent();
25279					}
25280
25281					if (delta !== 0 && !canScroll) {
25282						if (F.group.length > 1 && !current.canShrink) {
25283							if (deltaY > 0 || deltaX > 0) {
25284								F.prev( deltaY > 0 ? 'down' : 'left' );
25285
25286							} else if (deltaY < 0 || deltaX < 0) {
25287								F.next( deltaY < 0 ? 'up' : 'right' );
25288							}
25289
25290							e.preventDefault();
25291						}
25292					}
25293				});
25294			}
25295		},
25296
25297		trigger: function (event, o) {
25298			var ret, obj = o || F.coming || F.current;
25299
25300			if (obj) {
25301				if ($.isFunction( obj[event] )) {
25302					ret = obj[event].apply(obj, Array.prototype.slice.call(arguments, 1));
25303				}
25304
25305				if (ret === false) {
25306					return false;
25307				}
25308
25309				if (obj.helpers) {
25310					$.each(obj.helpers, function (helper, opts) {
25311						if (opts && F.helpers[helper] && $.isFunction(F.helpers[helper][event])) {
25312							F.helpers[helper][event]($.extend(true, {}, F.helpers[helper].defaults, opts), obj);
25313						}
25314					});
25315				}
25316			}
25317
25318			D.trigger(event);
25319		},
25320
25321		isImage: function (str) {
25322			return isString(str) && str.match(/(^data:image\/.*,)|(\.(jp(e|g|eg)|gif|png|bmp|webp|svg)((\?|#).*)?$)/i);
25323		},
25324
25325		isSWF: function (str) {
25326			return isString(str) && str.match(/\.(swf)((\?|#).*)?$/i);
25327		},
25328
25329		_start: function (index) {
25330			var coming = {},
25331				obj,
25332				href,
25333				type,
25334				margin,
25335				padding;
25336
25337			index = getScalar( index );
25338			obj   = F.group[ index ] || null;
25339
25340			if (!obj) {
25341				return false;
25342			}
25343
25344			coming = $.extend(true, {}, F.opts, obj);
25345
25346			// Convert margin and padding properties to array - top, right, bottom, left
25347			margin  = coming.margin;
25348			padding = coming.padding;
25349
25350			if ($.type(margin) === 'number') {
25351				coming.margin = [margin, margin, margin, margin];
25352			}
25353
25354			if ($.type(padding) === 'number') {
25355				coming.padding = [padding, padding, padding, padding];
25356			}
25357
25358			// 'modal' propery is just a shortcut
25359			if (coming.modal) {
25360				$.extend(true, coming, {
25361					closeBtn   : false,
25362					closeClick : false,
25363					nextClick  : false,
25364					arrows     : false,
25365					mouseWheel : false,
25366					keys       : null,
25367					helpers: {
25368						overlay : {
25369							closeClick : false
25370						}
25371					}
25372				});
25373			}
25374
25375			// 'autoSize' property is a shortcut, too
25376			if (coming.autoSize) {
25377				coming.autoWidth = coming.autoHeight = true;
25378			}
25379
25380			if (coming.width === 'auto') {
25381				coming.autoWidth = true;
25382			}
25383
25384			if (coming.height === 'auto') {
25385				coming.autoHeight = true;
25386			}
25387
25388			/*
25389			 * Add reference to the group, so it`s possible to access from callbacks, example:
25390			 * afterLoad : function() {
25391			 *     this.title = 'Image ' + (this.index + 1) + ' of ' + this.group.length + (this.title ? ' - ' + this.title : '');
25392			 * }
25393			 */
25394
25395			coming.group  = F.group;
25396			coming.index  = index;
25397
25398			// Give a chance for callback or helpers to update coming item (type, title, etc)
25399			F.coming = coming;
25400
25401			if (false === F.trigger('beforeLoad')) {
25402				F.coming = null;
25403
25404				return;
25405			}
25406
25407			type = coming.type;
25408			href = coming.href;
25409
25410			if (!type) {
25411				F.coming = null;
25412
25413				//If we can not determine content type then drop silently or display next/prev item if looping through gallery
25414				if (F.current && F.router && F.router !== 'jumpto') {
25415					F.current.index = index;
25416
25417					return F[ F.router ]( F.direction );
25418				}
25419
25420				return false;
25421			}
25422
25423			F.isActive = true;
25424
25425			if (type === 'image' || type === 'swf') {
25426				coming.autoHeight = coming.autoWidth = false;
25427				coming.scrolling  = 'visible';
25428			}
25429
25430			if (type === 'image') {
25431				coming.aspectRatio = true;
25432			}
25433
25434			if (type === 'iframe' && isTouch) {
25435				coming.scrolling = 'scroll';
25436			}
25437
25438			// Build the neccessary markup
25439			coming.wrap = $(coming.tpl.wrap).addClass('fancybox-' + (isTouch ? 'mobile' : 'desktop') + ' fancybox-type-' + type + ' fancybox-tmp ' + coming.wrapCSS).appendTo( coming.parent || 'body' );
25440
25441			$.extend(coming, {
25442				skin  : $('.fancybox-skin',  coming.wrap),
25443				outer : $('.fancybox-outer', coming.wrap),
25444				inner : $('.fancybox-inner', coming.wrap)
25445			});
25446
25447			$.each(["Top", "Right", "Bottom", "Left"], function(i, v) {
25448				coming.skin.css('padding' + v, getValue(coming.padding[ i ]));
25449			});
25450
25451			F.trigger('onReady');
25452
25453			// Check before try to load; 'inline' and 'html' types need content, others - href
25454			if (type === 'inline' || type === 'html') {
25455				if (!coming.content || !coming.content.length) {
25456					return F._error( 'content' );
25457				}
25458
25459			} else if (!href) {
25460				return F._error( 'href' );
25461			}
25462
25463			if (type === 'image') {
25464				F._loadImage();
25465
25466			} else if (type === 'ajax') {
25467				F._loadAjax();
25468
25469			} else if (type === 'iframe') {
25470				F._loadIframe();
25471
25472			} else {
25473				F._afterLoad();
25474			}
25475		},
25476
25477		_error: function ( type ) {
25478			$.extend(F.coming, {
25479				type       : 'html',
25480				autoWidth  : true,
25481				autoHeight : true,
25482				minWidth   : 0,
25483				minHeight  : 0,
25484				scrolling  : 'no',
25485				hasError   : type,
25486				content    : F.coming.tpl.error
25487			});
25488
25489			F._afterLoad();
25490		},
25491
25492		_loadImage: function () {
25493			// Reset preload image so it is later possible to check "complete" property
25494			var img = F.imgPreload = new Image();
25495
25496			img.onload = function () {
25497				this.onload = this.onerror = null;
25498
25499				F.coming.width  = this.width / F.opts.pixelRatio;
25500				F.coming.height = this.height / F.opts.pixelRatio;
25501
25502				F._afterLoad();
25503			};
25504
25505			img.onerror = function () {
25506				this.onload = this.onerror = null;
25507
25508				F._error( 'image' );
25509			};
25510
25511			img.src = F.coming.href;
25512
25513			if (img.complete !== true) {
25514				F.showLoading();
25515			}
25516		},
25517
25518		_loadAjax: function () {
25519			var coming = F.coming;
25520
25521			F.showLoading();
25522
25523			F.ajaxLoad = $.ajax($.extend({}, coming.ajax, {
25524				url: coming.href,
25525				error: function (jqXHR, textStatus) {
25526					if (F.coming && textStatus !== 'abort') {
25527						F._error( 'ajax', jqXHR );
25528
25529					} else {
25530						F.hideLoading();
25531					}
25532				},
25533				success: function (data, textStatus) {
25534					if (textStatus === 'success') {
25535						coming.content = data;
25536
25537						F._afterLoad();
25538					}
25539				}
25540			}));
25541		},
25542
25543		_loadIframe: function() {
25544			var coming = F.coming,
25545				iframe = $(coming.tpl.iframe.replace(/\{rnd\}/g, new Date().getTime()))
25546					.attr('scrolling', isTouch ? 'auto' : coming.iframe.scrolling)
25547					.attr('src', coming.href);
25548
25549			// This helps IE
25550			$(coming.wrap).bind('onReset', function () {
25551				try {
25552					$(this).find('iframe').hide().attr('src', '//about:blank').end().empty();
25553				} catch (e) {}
25554			});
25555
25556			if (coming.iframe.preload) {
25557				F.showLoading();
25558
25559				iframe.one('load', function() {
25560					$(this).data('ready', 1);
25561
25562					// iOS will lose scrolling if we resize
25563					if (!isTouch) {
25564						$(this).bind('load.fb', F.update);
25565					}
25566
25567					// Without this trick:
25568					//   - iframe won't scroll on iOS devices
25569					//   - IE7 sometimes displays empty iframe
25570					$(this).parents('.fancybox-wrap').width('100%').removeClass('fancybox-tmp').show();
25571
25572					F._afterLoad();
25573				});
25574			}
25575
25576			coming.content = iframe.appendTo( coming.inner );
25577
25578			if (!coming.iframe.preload) {
25579				F._afterLoad();
25580			}
25581		},
25582
25583		_preloadImages: function() {
25584			var group   = F.group,
25585				current = F.current,
25586				len     = group.length,
25587				cnt     = current.preload ? Math.min(current.preload, len - 1) : 0,
25588				item,
25589				i;
25590
25591			for (i = 1; i <= cnt; i += 1) {
25592				item = group[ (current.index + i ) % len ];
25593
25594				if (item.type === 'image' && item.href) {
25595					new Image().src = item.href;
25596				}
25597			}
25598		},
25599
25600		_afterLoad: function () {
25601			var coming   = F.coming,
25602				previous = F.current,
25603				placeholder = 'fancybox-placeholder',
25604				current,
25605				content,
25606				type,
25607				scrolling,
25608				href,
25609				embed;
25610
25611			F.hideLoading();
25612
25613			if (!coming || F.isActive === false) {
25614				return;
25615			}
25616
25617			if (false === F.trigger('afterLoad', coming, previous)) {
25618				coming.wrap.stop(true).trigger('onReset').remove();
25619
25620				F.coming = null;
25621
25622				return;
25623			}
25624
25625			if (previous) {
25626				F.trigger('beforeChange', previous);
25627
25628				previous.wrap.stop(true).removeClass('fancybox-opened')
25629					.find('.fancybox-item, .fancybox-nav')
25630					.remove();
25631			}
25632
25633			F.unbindEvents();
25634
25635			current   = coming;
25636			content   = coming.content;
25637			type      = coming.type;
25638			scrolling = coming.scrolling;
25639
25640			$.extend(F, {
25641				wrap  : current.wrap,
25642				skin  : current.skin,
25643				outer : current.outer,
25644				inner : current.inner,
25645				current  : current,
25646				previous : previous
25647			});
25648
25649			href = current.href;
25650
25651			switch (type) {
25652				case 'inline':
25653				case 'ajax':
25654				case 'html':
25655					if (current.selector) {
25656						content = $('<div>').html(content).find(current.selector);
25657
25658					} else if (isQuery(content)) {
25659						if (!content.data(placeholder)) {
25660							content.data(placeholder, $('<div class="' + placeholder + '"></div>').insertAfter( content ).hide() );
25661						}
25662
25663						content = content.show().detach();
25664
25665						current.wrap.bind('onReset', function () {
25666							if ($(this).find(content).length) {
25667								content.hide().replaceAll( content.data(placeholder) ).data(placeholder, false);
25668							}
25669						});
25670					}
25671				break;
25672
25673				case 'image':
25674					content = current.tpl.image.replace(/\{href\}/g, href);
25675				break;
25676
25677				case 'swf':
25678					content = '<object id="fancybox-swf" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="100%" height="100%"><param name="movie" value="' + href + '"></param>';
25679					embed   = '';
25680
25681					$.each(current.swf, function(name, val) {
25682						content += '<param name="' + name + '" value="' + val + '"></param>';
25683						embed   += ' ' + name + '="' + val + '"';
25684					});
25685
25686					content += '<embed src="' + href + '" type="application/x-shockwave-flash" width="100%" height="100%"' + embed + '></embed></object>';
25687				break;
25688			}
25689
25690			if (!(isQuery(content) && content.parent().is(current.inner))) {
25691				current.inner.append( content );
25692			}
25693
25694			// Give a chance for helpers or callbacks to update elements
25695			F.trigger('beforeShow');
25696
25697			// Set scrolling before calculating dimensions
25698			current.inner.css('overflow', scrolling === 'yes' ? 'scroll' : (scrolling === 'no' ? 'hidden' : scrolling));
25699
25700			// Set initial dimensions and start position
25701			F._setDimension();
25702
25703			F.reposition();
25704
25705			F.isOpen = false;
25706			F.coming = null;
25707
25708			F.bindEvents();
25709
25710			if (!F.isOpened) {
25711				$('.fancybox-wrap').not( current.wrap ).stop(true).trigger('onReset').remove();
25712
25713			} else if (previous.prevMethod) {
25714				F.transitions[ previous.prevMethod ]();
25715			}
25716
25717			F.transitions[ F.isOpened ? current.nextMethod : current.openMethod ]();
25718
25719			F._preloadImages();
25720		},
25721
25722		_setDimension: function () {
25723			var viewport   = F.getViewport(),
25724				steps      = 0,
25725				canShrink  = false,
25726				canExpand  = false,
25727				wrap       = F.wrap,
25728				skin       = F.skin,
25729				inner      = F.inner,
25730				current    = F.current,
25731				width      = current.width,
25732				height     = current.height,
25733				minWidth   = current.minWidth,
25734				minHeight  = current.minHeight,
25735				maxWidth   = current.maxWidth,
25736				maxHeight  = current.maxHeight,
25737				scrolling  = current.scrolling,
25738				scrollOut  = current.scrollOutside ? current.scrollbarWidth : 0,
25739				margin     = current.margin,
25740				wMargin    = getScalar(margin[1] + margin[3]),
25741				hMargin    = getScalar(margin[0] + margin[2]),
25742				wPadding,
25743				hPadding,
25744				wSpace,
25745				hSpace,
25746				origWidth,
25747				origHeight,
25748				origMaxWidth,
25749				origMaxHeight,
25750				ratio,
25751				width_,
25752				height_,
25753				maxWidth_,
25754				maxHeight_,
25755				iframe,
25756				body;
25757
25758			// Reset dimensions so we could re-check actual size
25759			wrap.add(skin).add(inner).width('auto').height('auto').removeClass('fancybox-tmp');
25760
25761			wPadding = getScalar(skin.outerWidth(true)  - skin.width());
25762			hPadding = getScalar(skin.outerHeight(true) - skin.height());
25763
25764			// Any space between content and viewport (margin, padding, border, title)
25765			wSpace = wMargin + wPadding;
25766			hSpace = hMargin + hPadding;
25767
25768			origWidth  = isPercentage(width)  ? (viewport.w - wSpace) * getScalar(width)  / 100 : width;
25769			origHeight = isPercentage(height) ? (viewport.h - hSpace) * getScalar(height) / 100 : height;
25770
25771			if (current.type === 'iframe') {
25772				iframe = current.content;
25773
25774				if (current.autoHeight && iframe.data('ready') === 1) {
25775					try {
25776						if (iframe[0].contentWindow.document.location) {
25777							inner.width( origWidth ).height(9999);
25778
25779							body = iframe.contents().find('body');
25780
25781							if (scrollOut) {
25782								body.css('overflow-x', 'hidden');
25783							}
25784
25785							origHeight = body.outerHeight(true);
25786						}
25787
25788					} catch (e) {}
25789				}
25790
25791			} else if (current.autoWidth || current.autoHeight) {
25792				inner.addClass( 'fancybox-tmp' );
25793
25794				// Set width or height in case we need to calculate only one dimension
25795				if (!current.autoWidth) {
25796					inner.width( origWidth );
25797				}
25798
25799				if (!current.autoHeight) {
25800					inner.height( origHeight );
25801				}
25802
25803				if (current.autoWidth) {
25804					origWidth = inner.width();
25805				}
25806
25807				if (current.autoHeight) {
25808					origHeight = inner.height();
25809				}
25810
25811				inner.removeClass( 'fancybox-tmp' );
25812			}
25813
25814			width  = getScalar( origWidth );
25815			height = getScalar( origHeight );
25816
25817			ratio  = origWidth / origHeight;
25818
25819			// Calculations for the content
25820			minWidth  = getScalar(isPercentage(minWidth) ? getScalar(minWidth, 'w') - wSpace : minWidth);
25821			maxWidth  = getScalar(isPercentage(maxWidth) ? getScalar(maxWidth, 'w') - wSpace : maxWidth);
25822
25823			minHeight = getScalar(isPercentage(minHeight) ? getScalar(minHeight, 'h') - hSpace : minHeight);
25824			maxHeight = getScalar(isPercentage(maxHeight) ? getScalar(maxHeight, 'h') - hSpace : maxHeight);
25825
25826			// These will be used to determine if wrap can fit in the viewport
25827			origMaxWidth  = maxWidth;
25828			origMaxHeight = maxHeight;
25829
25830			if (current.fitToView) {
25831				maxWidth  = Math.min(viewport.w - wSpace, maxWidth);
25832				maxHeight = Math.min(viewport.h - hSpace, maxHeight);
25833			}
25834
25835			maxWidth_  = viewport.w - wMargin;
25836			maxHeight_ = viewport.h - hMargin;
25837
25838			if (current.aspectRatio) {
25839				if (width > maxWidth) {
25840					width  = maxWidth;
25841					height = getScalar(width / ratio);
25842				}
25843
25844				if (height > maxHeight) {
25845					height = maxHeight;
25846					width  = getScalar(height * ratio);
25847				}
25848
25849				if (width < minWidth) {
25850					width  = minWidth;
25851					height = getScalar(width / ratio);
25852				}
25853
25854				if (height < minHeight) {
25855					height = minHeight;
25856					width  = getScalar(height * ratio);
25857				}
25858
25859			} else {
25860				width = Math.max(minWidth, Math.min(width, maxWidth));
25861
25862				if (current.autoHeight && current.type !== 'iframe') {
25863					inner.width( width );
25864
25865					height = inner.height();
25866				}
25867
25868				height = Math.max(minHeight, Math.min(height, maxHeight));
25869			}
25870
25871			// Try to fit inside viewport (including the title)
25872			if (current.fitToView) {
25873				inner.width( width ).height( height );
25874
25875				wrap.width( width + wPadding );
25876
25877				// Real wrap dimensions
25878				width_  = wrap.width();
25879				height_ = wrap.height();
25880
25881				if (current.aspectRatio) {
25882					while ((width_ > maxWidth_ || height_ > maxHeight_) && width > minWidth && height > minHeight) {
25883						if (steps++ > 19) {
25884							break;
25885						}
25886
25887						height = Math.max(minHeight, Math.min(maxHeight, height - 10));
25888						width  = getScalar(height * ratio);
25889
25890						if (width < minWidth) {
25891							width  = minWidth;
25892							height = getScalar(width / ratio);
25893						}
25894
25895						if (width > maxWidth) {
25896							width  = maxWidth;
25897							height = getScalar(width / ratio);
25898						}
25899
25900						inner.width( width ).height( height );
25901
25902						wrap.width( width + wPadding );
25903
25904						width_  = wrap.width();
25905						height_ = wrap.height();
25906					}
25907
25908				} else {
25909					width  = Math.max(minWidth,  Math.min(width,  width  - (width_  - maxWidth_)));
25910					height = Math.max(minHeight, Math.min(height, height - (height_ - maxHeight_)));
25911				}
25912			}
25913
25914			if (scrollOut && scrolling === 'auto' && height < origHeight && (width + wPadding + scrollOut) < maxWidth_) {
25915				width += scrollOut;
25916			}
25917
25918			inner.width( width ).height( height );
25919
25920			wrap.width( width + wPadding );
25921
25922			width_  = wrap.width();
25923			height_ = wrap.height();
25924
25925			canShrink = (width_ > maxWidth_ || height_ > maxHeight_) && width > minWidth && height > minHeight;
25926			canExpand = current.aspectRatio ? (width < origMaxWidth && height < origMaxHeight && width < origWidth && height < origHeight) : ((width < origMaxWidth || height < origMaxHeight) && (width < origWidth || height < origHeight));
25927
25928			$.extend(current, {
25929				dim : {
25930					width	: getValue( width_ ),
25931					height	: getValue( height_ )
25932				},
25933				origWidth  : origWidth,
25934				origHeight : origHeight,
25935				canShrink  : canShrink,
25936				canExpand  : canExpand,
25937				wPadding   : wPadding,
25938				hPadding   : hPadding,
25939				wrapSpace  : height_ - skin.outerHeight(true),
25940				skinSpace  : skin.height() - height
25941			});
25942
25943			if (!iframe && current.autoHeight && height > minHeight && height < maxHeight && !canExpand) {
25944				inner.height('auto');
25945			}
25946		},
25947
25948		_getPosition: function (onlyAbsolute) {
25949			var current  = F.current,
25950				viewport = F.getViewport(),
25951				margin   = current.margin,
25952				width    = F.wrap.width()  + margin[1] + margin[3],
25953				height   = F.wrap.height() + margin[0] + margin[2],
25954				rez      = {
25955					position: 'absolute',
25956					top  : margin[0],
25957					left : margin[3]
25958				};
25959
25960			if (current.autoCenter && current.fixed && !onlyAbsolute && height <= viewport.h && width <= viewport.w) {
25961				rez.position = 'fixed';
25962
25963			} else if (!current.locked) {
25964				rez.top  += viewport.y;
25965				rez.left += viewport.x;
25966			}
25967
25968			rez.top  = getValue(Math.max(rez.top,  rez.top  + ((viewport.h - height) * current.topRatio)));
25969			rez.left = getValue(Math.max(rez.left, rez.left + ((viewport.w - width)  * current.leftRatio)));
25970
25971			return rez;
25972		},
25973
25974		_afterZoomIn: function () {
25975			var current = F.current;
25976
25977			if (!current) {
25978				return;
25979			}
25980
25981			F.isOpen = F.isOpened = true;
25982
25983			F.wrap.css('overflow', 'visible').addClass('fancybox-opened').hide().show(0);
25984
25985			F.update();
25986
25987			// Assign a click event
25988			if ( current.closeClick || (current.nextClick && F.group.length > 1) ) {
25989				F.inner.css('cursor', 'pointer').bind('click.fb', function(e) {
25990					if (!$(e.target).is('a') && !$(e.target).parent().is('a')) {
25991						e.preventDefault();
25992
25993						F[ current.closeClick ? 'close' : 'next' ]();
25994					}
25995				});
25996			}
25997
25998			// Create a close button
25999			if (current.closeBtn) {
26000				$(current.tpl.closeBtn).appendTo(F.skin).bind('click.fb', function(e) {
26001					e.preventDefault();
26002
26003					F.close();
26004				});
26005			}
26006
26007			// Create navigation arrows
26008			if (current.arrows && F.group.length > 1) {
26009				if (current.loop || current.index > 0) {
26010					$(current.tpl.prev).appendTo(F.outer).bind('click.fb', F.prev);
26011				}
26012
26013				if (current.loop || current.index < F.group.length - 1) {
26014					$(current.tpl.next).appendTo(F.outer).bind('click.fb', F.next);
26015				}
26016			}
26017
26018			F.trigger('afterShow');
26019
26020			// Stop the slideshow if this is the last item
26021			if (!current.loop && current.index === current.group.length - 1) {
26022
26023				F.play( false );
26024
26025			} else if (F.opts.autoPlay && !F.player.isActive) {
26026				F.opts.autoPlay = false;
26027
26028				F.play(true);
26029			}
26030		},
26031
26032		_afterZoomOut: function ( obj ) {
26033			obj = obj || F.current;
26034
26035			$('.fancybox-wrap').trigger('onReset').remove();
26036
26037			$.extend(F, {
26038				group  : {},
26039				opts   : {},
26040				router : false,
26041				current   : null,
26042				isActive  : false,
26043				isOpened  : false,
26044				isOpen    : false,
26045				isClosing : false,
26046				wrap   : null,
26047				skin   : null,
26048				outer  : null,
26049				inner  : null
26050			});
26051
26052			F.trigger('afterClose', obj);
26053		}
26054	});
26055
26056	/*
26057	 *	Default transitions
26058	 */
26059
26060	F.transitions = {
26061		getOrigPosition: function () {
26062			var current  = F.current,
26063				element  = current.element,
26064				orig     = current.orig,
26065				pos      = {},
26066				width    = 50,
26067				height   = 50,
26068				hPadding = current.hPadding,
26069				wPadding = current.wPadding,
26070				viewport = F.getViewport();
26071
26072			if (!orig && current.isDom && element.is(':visible')) {
26073				orig = element.find('img:first');
26074
26075				if (!orig.length) {
26076					orig = element;
26077				}
26078			}
26079
26080			if (isQuery(orig)) {
26081				pos = orig.offset();
26082
26083				if (orig.is('img')) {
26084					width  = orig.outerWidth();
26085					height = orig.outerHeight();
26086				}
26087
26088			} else {
26089				pos.top  = viewport.y + (viewport.h - height) * current.topRatio;
26090				pos.left = viewport.x + (viewport.w - width)  * current.leftRatio;
26091			}
26092
26093			if (F.wrap.css('position') === 'fixed' || current.locked) {
26094				pos.top  -= viewport.y;
26095				pos.left -= viewport.x;
26096			}
26097
26098			pos = {
26099				top     : getValue(pos.top  - hPadding * current.topRatio),
26100				left    : getValue(pos.left - wPadding * current.leftRatio),
26101				width   : getValue(width  + wPadding),
26102				height  : getValue(height + hPadding)
26103			};
26104
26105			return pos;
26106		},
26107
26108		step: function (now, fx) {
26109			var ratio,
26110				padding,
26111				value,
26112				prop       = fx.prop,
26113				current    = F.current,
26114				wrapSpace  = current.wrapSpace,
26115				skinSpace  = current.skinSpace;
26116
26117			if (prop === 'width' || prop === 'height') {
26118				ratio = fx.end === fx.start ? 1 : (now - fx.start) / (fx.end - fx.start);
26119
26120				if (F.isClosing) {
26121					ratio = 1 - ratio;
26122				}
26123
26124				padding = prop === 'width' ? current.wPadding : current.hPadding;
26125				value   = now - padding;
26126
26127				F.skin[ prop ](  getScalar( prop === 'width' ?  value : value - (wrapSpace * ratio) ) );
26128				F.inner[ prop ]( getScalar( prop === 'width' ?  value : value - (wrapSpace * ratio) - (skinSpace * ratio) ) );
26129			}
26130		},
26131
26132		zoomIn: function () {
26133			var current  = F.current,
26134				startPos = current.pos,
26135				effect   = current.openEffect,
26136				elastic  = effect === 'elastic',
26137				endPos   = $.extend({opacity : 1}, startPos);
26138
26139			// Remove "position" property that breaks older IE
26140			delete endPos.position;
26141
26142			if (elastic) {
26143				startPos = this.getOrigPosition();
26144
26145				if (current.openOpacity) {
26146					startPos.opacity = 0.1;
26147				}
26148
26149			} else if (effect === 'fade') {
26150				startPos.opacity = 0.1;
26151			}
26152
26153			F.wrap.css(startPos).animate(endPos, {
26154				duration : effect === 'none' ? 0 : current.openSpeed,
26155				easing   : current.openEasing,
26156				step     : elastic ? this.step : null,
26157				complete : F._afterZoomIn
26158			});
26159		},
26160
26161		zoomOut: function () {
26162			var current  = F.current,
26163				effect   = current.closeEffect,
26164				elastic  = effect === 'elastic',
26165				endPos   = {opacity : 0.1};
26166
26167			if (elastic) {
26168				endPos = this.getOrigPosition();
26169
26170				if (current.closeOpacity) {
26171					endPos.opacity = 0.1;
26172				}
26173			}
26174
26175			F.wrap.animate(endPos, {
26176				duration : effect === 'none' ? 0 : current.closeSpeed,
26177				easing   : current.closeEasing,
26178				step     : elastic ? this.step : null,
26179				complete : F._afterZoomOut
26180			});
26181		},
26182
26183		changeIn: function () {
26184			var current   = F.current,
26185				effect    = current.nextEffect,
26186				startPos  = current.pos,
26187				endPos    = { opacity : 1 },
26188				direction = F.direction,
26189				distance  = 200,
26190				field;
26191
26192			startPos.opacity = 0.1;
26193
26194			if (effect === 'elastic') {
26195				field = direction === 'down' || direction === 'up' ? 'top' : 'left';
26196
26197				if (direction === 'down' || direction === 'right') {
26198					startPos[ field ] = getValue(getScalar(startPos[ field ]) - distance);
26199					endPos[ field ]   = '+=' + distance + 'px';
26200
26201				} else {
26202					startPos[ field ] = getValue(getScalar(startPos[ field ]) + distance);
26203					endPos[ field ]   = '-=' + distance + 'px';
26204				}
26205			}
26206
26207			// Workaround for http://bugs.jquery.com/ticket/12273
26208			if (effect === 'none') {
26209				F._afterZoomIn();
26210
26211			} else {
26212				F.wrap.css(startPos).animate(endPos, {
26213					duration : current.nextSpeed,
26214					easing   : current.nextEasing,
26215					complete : F._afterZoomIn
26216				});
26217			}
26218		},
26219
26220		changeOut: function () {
26221			var previous  = F.previous,
26222				effect    = previous.prevEffect,
26223				endPos    = { opacity : 0.1 },
26224				direction = F.direction,
26225				distance  = 200;
26226
26227			if (effect === 'elastic') {
26228				endPos[ direction === 'down' || direction === 'up' ? 'top' : 'left' ] = ( direction === 'up' || direction === 'left' ? '-' : '+' ) + '=' + distance + 'px';
26229			}
26230
26231			previous.wrap.animate(endPos, {
26232				duration : effect === 'none' ? 0 : previous.prevSpeed,
26233				easing   : previous.prevEasing,
26234				complete : function () {
26235					$(this).trigger('onReset').remove();
26236				}
26237			});
26238		}
26239	};
26240
26241	/*
26242	 *	Overlay helper
26243	 */
26244
26245	F.helpers.overlay = {
26246		defaults : {
26247			closeClick : true,      // if true, fancyBox will be closed when user clicks on the overlay
26248			speedOut   : 200,       // duration of fadeOut animation
26249			showEarly  : true,      // indicates if should be opened immediately or wait until the content is ready
26250			css        : {},        // custom CSS properties
26251			locked     : !isTouch,  // if true, the content will be locked into overlay
26252			fixed      : true       // if false, the overlay CSS position property will not be set to "fixed"
26253		},
26254
26255		overlay : null,      // current handle
26256		fixed   : false,     // indicates if the overlay has position "fixed"
26257		el      : $('html'), // element that contains "the lock"
26258
26259		// Public methods
26260		create : function(opts) {
26261			var parent;
26262
26263			opts = $.extend({}, this.defaults, opts);
26264
26265			if (this.overlay) {
26266				this.close();
26267			}
26268
26269			parent = F.coming ? F.coming.parent : opts.parent;
26270
26271			this.overlay = $('<div class="fancybox-overlay"></div>').appendTo( parent && parent.length ? parent : 'body' );
26272			this.fixed   = false;
26273
26274			if (opts.fixed && F.defaults.fixed) {
26275				this.overlay.addClass('fancybox-overlay-fixed');
26276
26277				this.fixed = true;
26278			}
26279		},
26280
26281		open : function(opts) {
26282			var that = this;
26283
26284			opts = $.extend({}, this.defaults, opts);
26285
26286			if (this.overlay) {
26287				this.overlay.unbind('.overlay').width('auto').height('auto');
26288
26289			} else {
26290				this.create(opts);
26291			}
26292
26293			if (!this.fixed) {
26294				W.bind('resize.overlay', $.proxy( this.update, this) );
26295
26296				this.update();
26297			}
26298
26299			if (opts.closeClick) {
26300				this.overlay.bind('click.overlay', function(e) {
26301					if ($(e.target).hasClass('fancybox-overlay')) {
26302						if (F.isActive) {
26303							F.close();
26304						} else {
26305							that.close();
26306						}
26307
26308						return false;
26309					}
26310				});
26311			}
26312
26313			this.overlay.css( opts.css ).show();
26314		},
26315
26316		close : function() {
26317			W.unbind('resize.overlay');
26318
26319			if (this.el.hasClass('fancybox-lock')) {
26320				$('.fancybox-margin').removeClass('fancybox-margin');
26321
26322				this.el.removeClass('fancybox-lock');
26323
26324				W.scrollTop( this.scrollV ).scrollLeft( this.scrollH );
26325			}
26326
26327			$('.fancybox-overlay').remove().hide();
26328
26329			$.extend(this, {
26330				overlay : null,
26331				fixed   : false
26332			});
26333		},
26334
26335		// Private, callbacks
26336
26337		update : function () {
26338			var width = '100%', offsetWidth;
26339
26340			// Reset width/height so it will not mess
26341			this.overlay.width(width).height('100%');
26342
26343			// jQuery does not return reliable result for IE
26344			if (IE) {
26345				offsetWidth = Math.max(document.documentElement.offsetWidth, document.body.offsetWidth);
26346
26347				if (D.width() > offsetWidth) {
26348					width = D.width();
26349				}
26350
26351			} else if (D.width() > W.width()) {
26352				width = D.width();
26353			}
26354
26355			this.overlay.width(width).height(D.height());
26356		},
26357
26358		// This is where we can manipulate DOM, because later it would cause iframes to reload
26359		onReady : function (opts, obj) {
26360			var overlay = this.overlay;
26361
26362			$('.fancybox-overlay').stop(true, true);
26363
26364			if (!overlay) {
26365				this.create(opts);
26366			}
26367
26368			if (opts.locked && this.fixed && obj.fixed) {
26369				obj.locked = this.overlay.append( obj.wrap );
26370				obj.fixed  = false;
26371			}
26372
26373			if (opts.showEarly === true) {
26374				this.beforeShow.apply(this, arguments);
26375			}
26376		},
26377
26378		beforeShow : function(opts, obj) {
26379			if (obj.locked && !this.el.hasClass('fancybox-lock')) {
26380				if (this.fixPosition !== false) {
26381					$('*
vendor: 1,346 bytes, lines 26381-26439
26381:not(object)').filter(function(){
26382						return ($(this).css('position') === 'fixed' && !$(this).hasClass("fancybox-overlay") && !$(this).hasClass("fancybox-wrap") );
26383					}).addClass('fancybox-margin');
26384				}
26385
26386				this.el.addClass('fancybox-margin');
26387
26388				this.scrollV = W.scrollTop();
26389				this.scrollH = W.scrollLeft();
26390
26391				this.el.addClass('fancybox-lock');
26392
26393				W.scrollTop( this.scrollV ).scrollLeft( this.scrollH );
26394			}
26395
26396			this.open(opts);
26397		},
26398
26399		onUpdate : function() {
26400			if (!this.fixed) {
26401				this.update();
26402			}
26403		},
26404
26405		afterClose: function (opts) {
26406			// Remove overlay if exists and fancyBox is not opening
26407			// (e.g., it is not being open using afterClose callback)
26408			if (this.overlay && !F.coming) {
26409				this.overlay.fadeOut(opts.speedOut, $.proxy( this.close, this ));
26410			}
26411		}
26412	};
26413
26414	/*
26415	 *	Title helper
26416	 */
26417
26418	F.helpers.title = {
26419		defaults : {
26420			type     : 'float', // 'float', 'inside', 'outside' or 'over',
26421			position : 'bottom' // 'top' or 'bottom'
26422		},
26423
26424		beforeShow: function (opts) {
26425			var current = F.current,
26426				text    = current.title,
26427				type    = opts.type,
26428				title,
26429				target;
26430
26431			if ($.isFunction(text)) {
26432				text = text.call(current.element, current);
26433			}
26434
26435			if (!isString(text) || $.trim(text) === '') {
26436				return;
26437			}
26438
26439			title = $('<div class="fancybox-title fancybox-title-' + type + '-wrap">
vendor: 3,163 bytes, lines 26439-26568
26439' + text + '</div>');
26440
26441			switch (type) {
26442				case 'inside':
26443					target = F.skin;
26444				break;
26445
26446				case 'outside':
26447					target = F.wrap;
26448				break;
26449
26450				case 'over':
26451					target = F.inner;
26452				break;
26453
26454				default: // 'float'
26455					target = F.skin;
26456
26457					title.appendTo('body');
26458
26459					if (IE) {
26460						title.width( title.width() );
26461					}
26462
26463					title.wrapInner('<span class="child"></span>');
26464
26465					//Increase bottom margin so this title will also fit into viewport
26466					F.current.margin[2] += Math.abs( getScalar(title.css('margin-bottom')) );
26467				break;
26468			}
26469
26470			title[ (opts.position === 'top' ? 'prependTo'  : 'appendTo') ](target);
26471		}
26472	};
26473
26474	// jQuery plugin initialization
26475	$.fn.fancybox = function (options) {
26476		var index,
26477			that     = $(this),
26478			selector = this.selector || '',
26479			run      = function(e) {
26480				var what = $(this).blur(), idx = index, relType, relVal;
26481
26482				if (!(e.ctrlKey || e.altKey || e.shiftKey || e.metaKey) && !what.is('.fancybox-wrap')) {
26483					relType = options.groupAttr || 'data-fancybox-group';
26484					relVal  = what.attr(relType);
26485
26486					if (!relVal) {
26487						relType = 'rel';
26488						relVal  = what.get(0)[ relType ];
26489					}
26490
26491					if (relVal && relVal !== '' && relVal !== 'nofollow') {
26492						what = selector.length ? $(selector) : that;
26493						what = what.filter('[' + relType + '="' + relVal + '"]');
26494						idx  = what.index(this);
26495					}
26496
26497					options.index = idx;
26498
26499					// Stop an event from bubbling if everything is fine
26500					if (F.open(what, options) !== false) {
26501						e.preventDefault();
26502					}
26503				}
26504			};
26505
26506		options = options || {};
26507		index   = options.index || 0;
26508
26509		if (!selector || options.live === false) {
26510			that.unbind('click.fb-start').bind('click.fb-start', run);
26511
26512		} else {
26513			D.undelegate(selector, 'click.fb-start').delegate(selector + ":not('.fancybox-item, .fancybox-nav')", 'click.fb-start', run);
26514		}
26515
26516		this.filter('[data-fancybox-start=1]').trigger('click');
26517
26518		return this;
26519	};
26520
26521	// Tests that need a body at doc ready
26522	D.ready(function() {
26523		var w1, w2;
26524
26525		if ( $.scrollbarWidth === undefined ) {
26526			// http://benalman.com/projects/jquery-misc-plugins/#scrollbarwidth
26527			$.scrollbarWidth = function() {
26528				var parent = $('<div style="width:50px;height:50px;overflow:auto"><div/></div>').appendTo('body'),
26529					child  = parent.children(),
26530					width  = child.innerWidth() - child.height( 99 ).innerWidth();
26531
26532				parent.remove();
26533
26534				return width;
26535			};
26536		}
26537
26538		if ( $.support.fixedPosition === undefined ) {
26539			$.support.fixedPosition = (function() {
26540				var elem  = $('<div style="position:fixed;top:20px;"></div>').appendTo('body'),
26541					fixed = ( elem[0].offsetTop === 20 || elem[0].offsetTop === 15 );
26542
26543				elem.remove();
26544
26545				return fixed;
26546			}());
26547		}
26548
26549		$.extend(F.defaults, {
26550			scrollbarWidth : $.scrollbarWidth(),
26551			fixed  : $.support.fixedPosition,
26552			parent : $('body')
26553		});
26554
26555		//Get real width of page scroll-bar
26556		w1 = $(window).width();
26557
26558		H.addClass('fancybox-lock-test');
26559
26560		w2 = $(window).width();
26561
26562		H.removeClass('fancybox-lock-test');
26563
26564		$("<style type='text/css'>.fancybox-margin{margin-right:" + (w2 - w1) + "px;}</style>").appendTo("head");
26565	});
26566
26567}(window, document, jQuery));
26568
vendor: 23,187 bytes, lines 26569-26614
26569/*! fancyBox v2.1.5 fancyapps.com | fancyapps.com/fancybox/#license */
26570(function(s,H,f,w){var K=f("html"),q=f(s),p=f(H),b=f.fancybox=function(){b.open.apply(this,arguments)},J=navigator.userAgent.match(/msie/i),C=null,t=H.createTouch!==w,u=function(a){return a&&a.hasOwnProperty&&a instanceof f},r=function(a){return a&&"string"===f.type(a)},F=function(a){return r(a)&&0<a.indexOf("%")},m=function(a,d){var e=parseInt(a,10)||0;d&&F(a)&&(e*=b.getViewport()[d]/100);return Math.ceil(e)},x=function(a,b){return m(a,b)+"px"};f.extend(b,{version:"2.1.5",defaults:{padding:15,margin:20,
26571width:800,height:600,minWidth:100,minHeight:100,maxWidth:9999,maxHeight:9999,pixelRatio:1,autoSize:!0,autoHeight:!1,autoWidth:!1,autoResize:!0,autoCenter:!t,fitToView:!0,aspectRatio:!1,topRatio:0.5,leftRatio:0.5,scrolling:"auto",wrapCSS:"",arrows:!0,closeBtn:!0,closeClick:!1,nextClick:!1,mouseWheel:!0,autoPlay:!1,playSpeed:3E3,preload:3,modal:!1,loop:!0,ajax:{dataType:"html",headers:{"X-fancyBox":!0}},iframe:{scrolling:"auto",preload:!0},swf:{wmode:"transparent",allowfullscreen:"true",allowscriptaccess:"always"},
26572keys:{next:{13:"left",34:"up",39:"left",40:"up"},prev:{8:"right",33:"down",37:"right",38:"down"},close:[27],play:[32],toggle:[70]},direction:{next:"left",prev:"right"},scrollOutside:!0,index:0,type:null,href:null,content:null,title:null,tpl:{wrap:'<div class="fancybox-wrap" tabIndex="-1"><div class="fancybox-skin"><div class="fancybox-outer"><div class="fancybox-inner"></div></div></div></div>',image:'<img class="fancybox-image" src="{href}" alt="" />',iframe:'<iframe id="fancybox-frame{rnd}" name="fancybox-frame{rnd}" class="fancybox-iframe" frameborder="0" vspace="0" hspace="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen'+
26573(J?' allowtransparency="true"':"")+"></iframe>",error:'<p class="fancybox-error">The requested content cannot be loaded.<br/>Please try again later.</p>',closeBtn:'<a title="Close" class="fancybox-item fancybox-close" href="javascript:;"></a>',next:'<a title="Next" class="fancybox-nav fancybox-next" href="javascript:;"><span></span></a>',prev:'<a title="Previous" class="fancybox-nav fancybox-prev" href="javascript:;"><span></span></a>'},openEffect:"fade",openSpeed:250,openEasing:"swing",openOpacity:!0,
26574openMethod:"zoomIn",closeEffect:"fade",closeSpeed:250,closeEasing:"swing",closeOpacity:!0,closeMethod:"zoomOut",nextEffect:"elastic",nextSpeed:250,nextEasing:"swing",nextMethod:"changeIn",prevEffect:"elastic",prevSpeed:250,prevEasing:"swing",prevMethod:"changeOut",helpers:{overlay:!0,title:!0},onCancel:f.noop,beforeLoad:f.noop,afterLoad:f.noop,beforeShow:f.noop,afterShow:f.noop,beforeChange:f.noop,beforeClose:f.noop,afterClose:f.noop},group:{},opts:{},previous:null,coming:null,current:null,isActive:!1,
26575isOpen:!1,isOpened:!1,wrap:null,skin:null,outer:null,inner:null,player:{timer:null,isActive:!1},ajaxLoad:null,imgPreload:null,transitions:{},helpers:{},open:function(a,d){if(a&&(f.isPlainObject(d)||(d={}),!1!==b.close(!0)))return f.isArray(a)||(a=u(a)?f(a).get():[a]),f.each(a,function(e,c){var l={},g,h,k,n,m;"object"===f.type(c)&&(c.nodeType&&(c=f(c)),u(c)?(l={href:c.data("fancybox-href")||c.attr("href"),title:f("<div/>").text(c.data("fancybox-title")||c.attr("title")).html(),isDom:!0,element:c},
26576f.metadata&&f.extend(!0,l,c.metadata())):l=c);g=d.href||l.href||(r(c)?c:null);h=d.title!==w?d.title:l.title||"";n=(k=d.content||l.content)?"html":d.type||l.type;!n&&l.isDom&&(n=c.data("fancybox-type"),n||(n=(n=c.prop("class").match(/fancybox\.(\w+)/))?n[1]:null));r(g)&&(n||(b.isImage(g)?n="image":b.isSWF(g)?n="swf":"#"===g.charAt(0)?n="inline":r(c)&&(n="html",k=c)),"ajax"===n&&(m=g.split(/\s+/,2),g=m.shift(),m=m.shift()));k||("inline"===n?g?k=f(r(g)?g.replace(/.*(?=#[^\s]+$)/,""):g):l.isDom&&(k=c):
26577"html"===n?k=g:n||g||!l.isDom||(n="inline",k=c));f.extend(l,{href:g,type:n,content:k,title:h,selector:m});a[e]=l}),b.opts=f.extend(!0,{},b.defaults,d),d.keys!==w&&(b.opts.keys=d.keys?f.extend({},b.defaults.keys,d.keys):!1),b.group=a,b._start(b.opts.index)},cancel:function(){var a=b.coming;a&&!1===b.trigger("onCancel")||(b.hideLoading(),a&&(b.ajaxLoad&&b.ajaxLoad.abort(),b.ajaxLoad=null,b.imgPreload&&(b.imgPreload.onload=b.imgPreload.onerror=null),a.wrap&&a.wrap.stop(!0,!0).trigger("onReset").remove(),
26578b.coming=null,b.current||b._afterZoomOut(a)))},close:function(a){b.cancel();!1!==b.trigger("beforeClose")&&(b.unbindEvents(),b.isActive&&(b.isOpen&&!0!==a?(b.isOpen=b.isOpened=!1,b.isClosing=!0,f(".fancybox-item, .fancybox-nav").remove(),b.wrap.stop(!0,!0).removeClass("fancybox-opened"),b.transitions[b.current.closeMethod]()):(f(".fancybox-wrap").stop(!0).trigger("onReset").remove(),b._afterZoomOut())))},play:function(a){var d=function(){clearTimeout(b.player.timer)},e=function(){d();b.current&&b.player.isActive&&
26579(b.player.timer=setTimeout(b.next,b.current.playSpeed))},c=function(){d();p.unbind(".player");b.player.isActive=!1;b.trigger("onPlayEnd")};!0===a||!b.player.isActive&&!1!==a?b.current&&(b.current.loop||b.current.index<b.group.length-1)&&(b.player.isActive=!0,p.bind({"onCancel.player beforeClose.player":c,"onUpdate.player":e,"beforeLoad.player":d}),e(),b.trigger("onPlayStart")):c()},next:function(a){var d=b.current;d&&(r(a)||(a=d.direction.next),b.jumpto(d.index+1,a,"next"))},prev:function(a){var d=
26580b.current;d&&(r(a)||(a=d.direction.prev),b.jumpto(d.index-1,a,"prev"))},jumpto:function(a,d,e){var c=b.current;c&&(a=m(a),b.direction=d||c.direction[a>=c.index?"next":"prev"],b.router=e||"jumpto",c.loop&&(0>a&&(a=c.group.length+a%c.group.length),a%=c.group.length),c.group[a]!==w&&(b.cancel(),b._start(a)))},reposition:function(a,d){var e=b.current,c=e?e.wrap:null,l;c&&(l=b._getPosition(d),a&&"scroll"===a.type?(delete l.position,c.stop(!0,!0).animate(l,200)):(c.css(l),e.pos=f.extend({},e.dim,l)))},
26581update:function(a){var d=a&&a.originalEvent&&a.originalEvent.type,e=!d||"orientationchange"===d;e&&(clearTimeout(C),C=null);b.isOpen&&!C&&(C=setTimeout(function(){var c=b.current;c&&!b.isClosing&&(b.wrap.removeClass("fancybox-tmp"),(e||"load"===d||"resize"===d&&c.autoResize)&&b._setDimension(),"scroll"===d&&c.canShrink||b.reposition(a),b.trigger("onUpdate"),C=null)},e&&!t?0:300))},toggle:function(a){b.isOpen&&(b.current.fitToView="boolean"===f.type(a)?a:!b.current.fitToView,t&&(b.wrap.removeAttr("style").addClass("fancybox-tmp"),
26582b.trigger("onUpdate")),b.update())},hideLoading:function(){p.unbind(".loading");f("#fancybox-loading").remove()},showLoading:function(){var a,d;b.hideLoading();a=f('<div id="fancybox-loading"><div></div></div>').click(b.cancel).appendTo("body");p.bind("keydown.loading",function(a){27===(a.which||a.keyCode)&&(a.preventDefault(),b.cancel())});b.defaults.fixed||(d=b.getViewport(),a.css({position:"absolute",top:0.5*d.h+d.y,left:0.5*d.w+d.x}));b.trigger("onLoading")},getViewport:function(){var a=b.current&&
26583b.current.locked||!1,d={x:q.scrollLeft(),y:q.scrollTop()};a&&a.length?(d.w=a[0].clientWidth,d.h=a[0].clientHeight):(d.w=t&&s.innerWidth?s.innerWidth:q.width(),d.h=t&&s.innerHeight?s.innerHeight:q.height());return d},unbindEvents:function(){b.wrap&&u(b.wrap)&&b.wrap.unbind(".fb");p.unbind(".fb");q.unbind(".fb")},bindEvents:function(){var a=b.current,d;a&&(q.bind("orientationchange.fb"+(t?"":" resize.fb")+(a.autoCenter&&!a.locked?" scroll.fb":""),b.update),(d=a.keys)&&p.bind("keydown.fb",function(e){var c=
26584e.which||e.keyCode,l=e.target||e.srcElement;if(27===c&&b.coming)return!1;e.ctrlKey||e.altKey||e.shiftKey||e.metaKey||l&&(l.type||f(l).is("[contenteditable]"))||f.each(d,function(d,l){if(1<a.group.length&&l[c]!==w)return b[d](l[c]),e.preventDefault(),!1;if(-1<f.inArray(c,l))return b[d](),e.preventDefault(),!1})}),f.fn.mousewheel&&a.mouseWheel&&b.wrap.bind("mousewheel.fb",function(d,c,l,g){for(var h=f(d.target||null),k=!1;h.length&&!(k||h.is(".fancybox-skin")||h.is(".fancybox-wrap"));)k=h[0]&&!(h[0].style.overflow&&
26585"hidden"===h[0].style.overflow)&&(h[0].clientWidth&&h[0].scrollWidth>h[0].clientWidth||h[0].clientHeight&&h[0].scrollHeight>h[0].clientHeight),h=f(h).parent();0!==c&&!k&&1<b.group.length&&!a.canShrink&&(0<g||0<l?b.prev(0<g?"down":"left"):(0>g||0>l)&&b.next(0>g?"up":"right"),d.preventDefault())}))},trigger:function(a,d){var e,c=d||b.coming||b.current;if(c){f.isFunction(c[a])&&(e=c[a].apply(c,Array.prototype.slice.call(arguments,1)));if(!1===e)return!1;c.helpers&&f.each(c.helpers,function(d,e){if(e&&
26586b.helpers[d]&&f.isFunction(b.helpers[d][a]))b.helpers[d][a](f.extend(!0,{},b.helpers[d].defaults,e),c)})}p.trigger(a)},isImage:function(a){return r(a)&&a.match(/(^data:image\/.*,)|(\.(jp(e|g|eg)|gif|png|bmp|webp|svg)((\?|#).*)?$)/i)},isSWF:function(a){return r(a)&&a.match(/\.(swf)((\?|#).*)?$/i)},_start:function(a){var d={},e,c;a=m(a);e=b.group[a]||null;if(!e)return!1;d=f.extend(!0,{},b.opts,e);e=d.margin;c=d.padding;"number"===f.type(e)&&(d.margin=[e,e,e,e]);"number"===f.type(c)&&(d.padding=[c,c,
26587c,c]);d.modal&&f.extend(!0,d,{closeBtn:!1,closeClick:!1,nextClick:!1,arrows:!1,mouseWheel:!1,keys:null,helpers:{overlay:{closeClick:!1}}});d.autoSize&&(d.autoWidth=d.autoHeight=!0);"auto"===d.width&&(d.autoWidth=!0);"auto"===d.height&&(d.autoHeight=!0);d.group=b.group;d.index=a;b.coming=d;if(!1===b.trigger("beforeLoad"))b.coming=null;else{c=d.type;e=d.href;if(!c)return b.coming=null,b.current&&b.router&&"jumpto"!==b.router?(b.current.index=a,b[b.router](b.direction)):!1;b.isActive=!0;if("image"===
26588c||"swf"===c)d.autoHeight=d.autoWidth=!1,d.scrolling="visible";"image"===c&&(d.aspectRatio=!0);"iframe"===c&&t&&(d.scrolling="scroll");d.wrap=f(d.tpl.wrap).addClass("fancybox-"+(t?"mobile":"desktop")+" fancybox-type-"+c+" fancybox-tmp "+d.wrapCSS).appendTo(d.parent||"body");f.extend(d,{skin:f(".fancybox-skin",d.wrap),outer:f(".fancybox-outer",d.wrap),inner:f(".fancybox-inner",d.wrap)});f.each(["Top","Right","Bottom","Left"],function(a,b){d.skin.css("padding"+b,x(d.padding[a]))});b.trigger("onReady");
26589if("inline"===c||"html"===c){if(!d.content||!d.content.length)return b._error("content")}else if(!e)return b._error("href");"image"===c?b._loadImage():"ajax"===c?b._loadAjax():"iframe"===c?b._loadIframe():b._afterLoad()}},_error:function(a){f.extend(b.coming,{type:"html",autoWidth:!0,autoHeight:!0,minWidth:0,minHeight:0,scrolling:"no",hasError:a,content:b.coming.tpl.error});b._afterLoad()},_loadImage:function(){var a=b.imgPreload=new Image;a.onload=function(){this.onload=this.onerror=null;b.coming.width=
26590this.width/b.opts.pixelRatio;b.coming.height=this.height/b.opts.pixelRatio;b._afterLoad()};a.onerror=function(){this.onload=this.onerror=null;b._error("image")};a.src=b.coming.href;!0!==a.complete&&b.showLoading()},_loadAjax:function(){var a=b.coming;b.showLoading();b.ajaxLoad=f.ajax(f.extend({},a.ajax,{url:a.href,error:function(a,e){b.coming&&"abort"!==e?b._error("ajax",a):b.hideLoading()},success:function(d,e){"success"===e&&(a.content=d,b._afterLoad())}}))},_loadIframe:function(){var a=b.coming,
26591d=f(a.tpl.iframe.replace(/\{rnd\}/g,(new Date).getTime())).attr("scrolling",t?"auto":a.iframe.scrolling).attr("src",a.href);f(a.wrap).bind("onReset",function(){try{f(this).find("iframe").hide().attr("src","//about:blank").end().empty()}catch(a){}});a.iframe.preload&&(b.showLoading(),d.one("load",function(){f(this).data("ready",1);t||f(this).bind("load.fb",b.update);f(this).parents(".fancybox-wrap").width("100%").removeClass("fancybox-tmp").show();b._afterLoad()}));a.content=d.appendTo(a.inner);a.iframe.preload||
26592b._afterLoad()},_preloadImages:function(){var a=b.group,d=b.current,e=a.length,c=d.preload?Math.min(d.preload,e-1):0,f,g;for(g=1;g<=c;g+=1)f=a[(d.index+g)%e],"image"===f.type&&f.href&&((new Image).src=f.href)},_afterLoad:function(){var a=b.coming,d=b.current,e,c,l,g,h;b.hideLoading();if(a&&!1!==b.isActive)if(!1===b.trigger("afterLoad",a,d))a.wrap.stop(!0).trigger("onReset").remove(),b.coming=null;else{d&&(b.trigger("beforeChange",d),d.wrap.stop(!0).removeClass("fancybox-opened").find(".fancybox-item, .fancybox-nav").remove());
26593b.unbindEvents();e=a.content;c=a.type;l=a.scrolling;f.extend(b,{wrap:a.wrap,skin:a.skin,outer:a.outer,inner:a.inner,current:a,previous:d});g=a.href;switch(c){case "inline":case "ajax":case "html":a.selector?e=f("<div>").html(e).find(a.selector):u(e)&&(e.data("fancybox-placeholder")||e.data("fancybox-placeholder",f('<div class="fancybox-placeholder"></div>').insertAfter(e).hide()),e=e.show().detach(),a.wrap.bind("onReset",function(){f(this).find(e).length&&e.hide().replaceAll(e.data("fancybox-placeholder")).data("fancybox-placeholder",
26594!1)}));break;case "image":e=a.tpl.image.replace(/\{href\}/g,g);break;case "swf":e='<object id="fancybox-swf" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="100%" height="100%"><param name="movie" value="'+g+'"></param>',h="",f.each(a.swf,function(a,b){e+='<param name="'+a+'" value="'+b+'"></param>';h+=" "+a+'="'+b+'"'}),e+='<embed src="'+g+'" type="application/x-shockwave-flash" width="100%" height="100%"'+h+"></embed></object>"}u(e)&&e.parent().is(a.inner)||a.inner.append(e);b.trigger("beforeShow");
26595a.inner.css("overflow","yes"===l?"scroll":"no"===l?"hidden":l);b._setDimension();b.reposition();b.isOpen=!1;b.coming=null;b.bindEvents();if(!b.isOpened)f(".fancybox-wrap").not(a.wrap).stop(!0).trigger("onReset").remove();else if(d.prevMethod)b.transitions[d.prevMethod]();b.transitions[b.isOpened?a.nextMethod:a.openMethod]();b._preloadImages()}},_setDimension:function(){var a=b.getViewport(),d=0,e=!1,c=!1,e=b.wrap,l=b.skin,g=b.inner,h=b.current,c=h.width,k=h.height,n=h.minWidth,v=h.minHeight,p=h.maxWidth,
26596q=h.maxHeight,t=h.scrolling,r=h.scrollOutside?h.scrollbarWidth:0,y=h.margin,z=m(y[1]+y[3]),s=m(y[0]+y[2]),w,A,u,D,B,G,C,E,I;e.add(l).add(g).width("auto").height("auto").removeClass("fancybox-tmp");y=m(l.outerWidth(!0)-l.width());w=m(l.outerHeight(!0)-l.height());A=z+y;u=s+w;D=F(c)?(a.w-A)*m(c)/100:c;B=F(k)?(a.h-u)*m(k)/100:k;if("iframe"===h.type){if(I=h.content,h.autoHeight&&1===I.data("ready"))try{I[0].contentWindow.document.location&&(g.width(D).height(9999),G=I.contents().find("body"),r&&G.css("overflow-x",
26597"hidden"),B=G.outerHeight(!0))}catch(H){}}else if(h.autoWidth||h.autoHeight)g.addClass("fancybox-tmp"),h.autoWidth||g.width(D),h.autoHeight||g.height(B),h.autoWidth&&(D=g.width()),h.autoHeight&&(B=g.height()),g.removeClass("fancybox-tmp");c=m(D);k=m(B);E=D/B;n=m(F(n)?m(n,"w")-A:n);p=m(F(p)?m(p,"w")-A:p);v=m(F(v)?m(v,"h")-u:v);q=m(F(q)?m(q,"h")-u:q);G=p;C=q;h.fitToView&&(p=Math.min(a.w-A,p),q=Math.min(a.h-u,q));A=a.w-z;s=a.h-s;h.aspectRatio?(c>p&&(c=p,k=m(c/E)),k>q&&(k=q,c=m(k*E)),c<n&&(c=n,k=m(c/
26598E)),k<v&&(k=v,c=m(k*E))):(c=Math.max(n,Math.min(c,p)),h.autoHeight&&"iframe"!==h.type&&(g.width(c),k=g.height()),k=Math.max(v,Math.min(k,q)));if(h.fitToView)if(g.width(c).height(k),e.width(c+y),a=e.width(),z=e.height(),h.aspectRatio)for(;(a>A||z>s)&&c>n&&k>v&&!(19<d++);)k=Math.max(v,Math.min(q,k-10)),c=m(k*E),c<n&&(c=n,k=m(c/E)),c>p&&(c=p,k=m(c/E)),g.width(c).height(k),e.width(c+y),a=e.width(),z=e.height();else c=Math.max(n,Math.min(c,c-(a-A))),k=Math.max(v,Math.min(k,k-(z-s)));r&&"auto"===t&&k<B&&
26599c+y+r<A&&(c+=r);g.width(c).height(k);e.width(c+y);a=e.width();z=e.height();e=(a>A||z>s)&&c>n&&k>v;c=h.aspectRatio?c<G&&k<C&&c<D&&k<B:(c<G||k<C)&&(c<D||k<B);f.extend(h,{dim:{width:x(a),height:x(z)},origWidth:D,origHeight:B,canShrink:e,canExpand:c,wPadding:y,hPadding:w,wrapSpace:z-l.outerHeight(!0),skinSpace:l.height()-k});!I&&h.autoHeight&&k>v&&k<q&&!c&&g.height("auto")},_getPosition:function(a){var d=b.current,e=b.getViewport(),c=d.margin,f=b.wrap.width()+c[1]+c[3],g=b.wrap.height()+c[0]+c[2],c={position:"absolute",
26600top:c[0],left:c[3]};d.autoCenter&&d.fixed&&!a&&g<=e.h&&f<=e.w?c.position="fixed":d.locked||(c.top+=e.y,c.left+=e.x);c.top=x(Math.max(c.top,c.top+(e.h-g)*d.topRatio));c.left=x(Math.max(c.left,c.left+(e.w-f)*d.leftRatio));return c},_afterZoomIn:function(){var a=b.current;a&&((b.isOpen=b.isOpened=!0,b.wrap.css("overflow","visible").addClass("fancybox-opened"),b.update(),(a.closeClick||a.nextClick&&1<b.group.length)&&b.inner.css("cursor","pointer").bind("click.fb",function(d){f(d.target).is("a")||f(d.target).parent().is("a")||
26601(d.preventDefault(),b[a.closeClick?"close":"next"]())}),a.closeBtn&&f(a.tpl.closeBtn).appendTo(b.skin).bind("click.fb",function(a){a.preventDefault();b.close()}),a.arrows&&1<b.group.length&&((a.loop||0<a.index)&&f(a.tpl.prev).appendTo(b.outer).bind("click.fb",b.prev),(a.loop||a.index<b.group.length-1)&&f(a.tpl.next).appendTo(b.outer).bind("click.fb",b.next)),b.trigger("afterShow"),a.loop||a.index!==a.group.length-1)?b.opts.autoPlay&&!b.player.isActive&&(b.opts.autoPlay=!1,b.play(!0)):b.play(!1))},
26602_afterZoomOut:function(a){a=a||b.current;f(".fancybox-wrap").trigger("onReset").remove();f.extend(b,{group:{},opts:{},router:!1,current:null,isActive:!1,isOpened:!1,isOpen:!1,isClosing:!1,wrap:null,skin:null,outer:null,inner:null});b.trigger("afterClose",a)}});b.transitions={getOrigPosition:function(){var a=b.current,d=a.element,e=a.orig,c={},f=50,g=50,h=a.hPadding,k=a.wPadding,n=b.getViewport();!e&&a.isDom&&d.is(":visible")&&(e=d.find("img:first"),e.length||(e=d));u(e)?(c=e.offset(),e.is("img")&&
26603(f=e.outerWidth(),g=e.outerHeight())):(c.top=n.y+(n.h-g)*a.topRatio,c.left=n.x+(n.w-f)*a.leftRatio);if("fixed"===b.wrap.css("position")||a.locked)c.top-=n.y,c.left-=n.x;return c={top:x(c.top-h*a.topRatio),left:x(c.left-k*a.leftRatio),width:x(f+k),height:x(g+h)}},step:function(a,d){var e,c,f=d.prop;c=b.current;var g=c.wrapSpace,h=c.skinSpace;if("width"===f||"height"===f)e=d.end===d.start?1:(a-d.start)/(d.end-d.start),b.isClosing&&(e=1-e),c="width"===f?c.wPadding:c.hPadding,c=a-c,b.skin[f](m("width"===
26604f?c:c-g*e)),b.inner[f](m("width"===f?c:c-g*e-h*e))},zoomIn:function(){var a=b.current,d=a.pos,e=a.openEffect,c="elastic"===e,l=f.extend({opacity:1},d);delete l.position;c?(d=this.getOrigPosition(),a.openOpacity&&(d.opacity=0.1)):"fade"===e&&(d.opacity=0.1);b.wrap.css(d).animate(l,{duration:"none"===e?0:a.openSpeed,easing:a.openEasing,step:c?this.step:null,complete:b._afterZoomIn})},zoomOut:function(){var a=b.current,d=a.closeEffect,e="elastic"===d,c={opacity:0.1};e&&(c=this.getOrigPosition(),a.closeOpacity&&
26605(c.opacity=0.1));b.wrap.animate(c,{duration:"none"===d?0:a.closeSpeed,easing:a.closeEasing,step:e?this.step:null,complete:b._afterZoomOut})},changeIn:function(){var a=b.current,d=a.nextEffect,e=a.pos,c={opacity:1},f=b.direction,g;e.opacity=0.1;"elastic"===d&&(g="down"===f||"up"===f?"top":"left","down"===f||"right"===f?(e[g]=x(m(e[g])-200),c[g]="+=200px"):(e[g]=x(m(e[g])+200),c[g]="-=200px"));"none"===d?b._afterZoomIn():b.wrap.css(e).animate(c,{duration:a.nextSpeed,easing:a.nextEasing,complete:b._afterZoomIn})},
26606changeOut:function(){var a=b.previous,d=a.prevEffect,e={opacity:0.1},c=b.direction;"elastic"===d&&(e["down"===c||"up"===c?"top":"left"]=("up"===c||"left"===c?"-":"+")+"=200px");a.wrap.animate(e,{duration:"none"===d?0:a.prevSpeed,easing:a.prevEasing,complete:function(){f(this).trigger("onReset").remove()}})}};b.helpers.overlay={defaults:{closeClick:!0,speedOut:200,showEarly:!0,css:{},locked:!t,fixed:!0},overlay:null,fixed:!1,el:f("html"),create:function(a){var d;a=f.extend({},this.defaults,a);this.overlay&&
26607this.close();d=b.coming?b.coming.parent:a.parent;this.overlay=f('<div class="fancybox-overlay"></div>').appendTo(d&&d.lenth?d:"body");this.fixed=!1;a.fixed&&b.defaults.fixed&&(this.overlay.addClass("fancybox-overlay-fixed"),this.fixed=!0)},open:function(a){var d=this;a=f.extend({},this.defaults,a);this.overlay?this.overlay.unbind(".overlay").width("auto").height("auto"):this.create(a);this.fixed||(q.bind("resize.overlay",f.proxy(this.update,this)),this.update());a.closeClick&&this.overlay.bind("click.overlay",
26608function(a){if(f(a.target).hasClass("fancybox-overlay"))return b.isActive?b.close():d.close(),!1});this.overlay.css(a.css).show()},close:function(){q.unbind("resize.overlay");this.el.hasClass("fancybox-lock")&&(f(".fancybox-margin").removeClass("fancybox-margin"),this.el.removeClass("fancybox-lock"),q.scrollTop(this.scrollV).scrollLeft(this.scrollH));f(".fancybox-overlay").remove().hide();f.extend(this,{overlay:null,fixed:!1})},update:function(){var a="100%",b;this.overlay.width(a).height("100%");
26609J?(b=Math.max(H.documentElement.offsetWidth,H.body.offsetWidth),p.width()>b&&(a=p.width())):p.width()>q.width()&&(a=p.width());this.overlay.width(a).height(p.height())},onReady:function(a,b){var e=this.overlay;f(".fancybox-overlay").stop(!0,!0);e||this.create(a);a.locked&&this.fixed&&b.fixed&&(b.locked=this.overlay.append(b.wrap),b.fixed=!1);!0===a.showEarly&&this.beforeShow.apply(this,arguments)},beforeShow:function(a,b){b.locked&&!this.el.hasClass("fancybox-lock")&&(!1!==this.fixPosition&&f("*").filter(function(){return"fixed"===
26610f(this).css("position")&&!f(this).hasClass("fancybox-overlay")&&!f(this).hasClass("fancybox-wrap")}).addClass("fancybox-margin"),this.el.addClass("fancybox-margin"),this.scrollV=q.scrollTop(),this.scrollH=q.scrollLeft(),this.el.addClass("fancybox-lock"),q.scrollTop(this.scrollV).scrollLeft(this.scrollH));this.open(a)},onUpdate:function(){this.fixed||this.update()},afterClose:function(a){this.overlay&&!b.coming&&this.overlay.fadeOut(a.speedOut,f.proxy(this.close,this))}};b.helpers.title={defaults:{type:"float",
26611position:"bottom"},beforeShow:function(a){var d=b.current,e=d.title,c=a.type;f.isFunction(e)&&(e=e.call(d.element,d));if(r(e)&&""!==f.trim(e)){d=f('<div class="fancybox-title fancybox-title-'+c+'-wrap">'+e+"</div>");switch(c){case "inside":c=b.skin;break;case "outside":c=b.wrap;break;case "over":c=b.inner;break;default:c=b.skin,d.appendTo("body"),J&&d.width(d.width()),d.wrapInner('<span class="child"></span>'),b.current.margin[2]+=Math.abs(m(d.css("margin-bottom")))}d["top"===a.position?"prependTo":
26612"appendTo"](c)}}};f.fn.fancybox=function(a){var d,e=f(this),c=this.selector||"",l=function(g){var h=f(this).blur(),k=d,l,m;g.ctrlKey||g.altKey||g.shiftKey||g.metaKey||h.is(".fancybox-wrap")||(l=a.groupAttr||"data-fancybox-group",m=h.attr(l),m||(l="rel",m=h.get(0)[l]),m&&""!==m&&"nofollow"!==m&&(h=c.length?f(c):e,h=h.filter("["+l+'="'+m+'"]'),k=h.index(this)),a.index=k,!1!==b.open(h,a)&&g.preventDefault())};a=a||{};d=a.index||0;c&&!1!==a.live?p.undelegate(c,"click.fb-start").delegate(c+":not('.fancybox-item, .fancybox-nav')",
26613"click.fb-start",l):e.unbind("click.fb-start").bind("click.fb-start",l);this.filter("[data-fancybox-start=1]").trigger("click");return this};p.ready(function(){var a,d;f.scrollbarWidth===w&&(f.scrollbarWidth=function(){var a=f('<div style="width:50px;height:50px;overflow:auto"><div/></div>').appendTo("body"),b=a.children(),b=b.innerWidth()-b.height(99).innerWidth();a.remove();return b});f.support.fixedPosition===w&&(f.support.fixedPosition=function(){var a=f('<div style="position:fixed;top:20px;"></div>').appendTo("body"),
26614b=20===a[0].offsetTop||15===a[0].offsetTop;a.remove();return b}());f.extend(b.defaults,{scrollbarWidth:f.scrollbarWidth(),fixed:f.support.fixedPosition,parent:f("body")});a=f(s).width();K.addClass("fancybox-lock-test");d=f(s).width();K.removeClass("fancybox-lock-test");f("<style type='text/css'>.fancybox-margin{margin-right:"+(d-a)+"px;}</style>").appendTo("head")})})(window,document,jQuery);
vendor: 7,728 bytes, lines 26614-26919
26614
26615/*
26616 * qTip2 - Pretty powerful tooltips - v3.0.2
26617 * http://qtip2.com
26618 *
26619 * Copyright (c) 2015 
26620 * Released under the MIT licenses
26621 * http://jquery.org/license
26622 *
26623 * Date: Tue Dec 8 2015 07:16 GMT+0000
26624 * Plugins: tips modal viewport svg imagemap ie6
26625 * Styles: core basic css3
26626 */
26627/*global window: false, jQuery: false, console: false, define: false */
26628
26629/* Cache window, document, undefined */
26630(function( window, document, undefined ) {
26631
26632// Uses AMD or browser globals to create a jQuery plugin.
26633(function( factory ) {
26634	"use strict";
26635	if(typeof define === 'function' && define.amd) {
26636		define(['jquery'], factory);
26637	}
26638	else if(jQuery && !jQuery.fn.qtip) {
26639		factory(jQuery);
26640	}
26641}
26642(function($) {
26643	"use strict"; // Enable ECMAScript "strict" operation for this function. See more: http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/
26644;// Munge the primitives - Paul Irish tip
26645var TRUE = true,
26646FALSE = false,
26647NULL = null,
26648
26649// Common variables
26650X = 'x', Y = 'y',
26651WIDTH = 'width',
26652HEIGHT = 'height',
26653
26654// Positioning sides
26655TOP = 'top',
26656LEFT = 'left',
26657BOTTOM = 'bottom',
26658RIGHT = 'right',
26659CENTER = 'center',
26660
26661// Position adjustment types
26662FLIP = 'flip',
26663FLIPINVERT = 'flipinvert',
26664SHIFT = 'shift',
26665
26666// Shortcut vars
26667QTIP, PROTOTYPE, CORNER, CHECKS,
26668PLUGINS = {},
26669NAMESPACE = 'qtip',
26670ATTR_HAS = 'data-hasqtip',
26671ATTR_ID = 'data-qtip-id',
26672WIDGET = ['ui-widget', 'ui-tooltip'],
26673SELECTOR = '.'+NAMESPACE,
26674INACTIVE_EVENTS = 'click dblclick mousedown mouseup mousemove mouseleave mouseenter'.split(' '),
26675
26676CLASS_FIXED = NAMESPACE+'-fixed',
26677CLASS_DEFAULT = NAMESPACE + '-default',
26678CLASS_FOCUS = NAMESPACE + '-focus',
26679CLASS_HOVER = NAMESPACE + '-hover',
26680CLASS_DISABLED = NAMESPACE+'-disabled',
26681
26682replaceSuffix = '_replacedByqTip',
26683oldtitle = 'oldtitle',
26684trackingBound,
26685
26686// Browser detection
26687BROWSER = {
26688	/*
26689	 * IE version detection
26690	 *
26691	 * Adapted from: http://ajaxian.com/archives/attack-of-the-ie-conditional-comment
26692	 * Credit to James Padolsey for the original implemntation!
26693	 */
26694	ie: (function() {
26695		/* eslint-disable no-empty */
26696		var v, i;
26697		for (
26698			v = 4, i = document.createElement('div');
26699			(i.innerHTML = '<!--[if gt IE ' + v + ']><i></i><![endif]-->') && i.getElementsByTagName('i')[0];
26700			v+=1
26701		) {}
26702		return v > 4 ? v : NaN;
26703		/* eslint-enable no-empty */
26704	})(),
26705
26706	/*
26707	 * iOS version detection
26708	 */
26709	iOS: parseFloat(
26710		('' + (/CPU.*OS ([0-9_]{1,5})|(CPU like).*AppleWebKit.*Mobile/i.exec(navigator.userAgent) || [0,''])[1])
26711		.replace('undefined', '3_2').replace('_', '.').replace('_', '')
26712	) || FALSE
26713};
26714;function QTip(target, options, id, attr) {
26715	// Elements and ID
26716	this.id = id;
26717	this.target = target;
26718	this.tooltip = NULL;
26719	this.elements = { target: target };
26720
26721	// Internal constructs
26722	this._id = NAMESPACE + '-' + id;
26723	this.timers = { img: {} };
26724	this.options = options;
26725	this.plugins = {};
26726
26727	// Cache object
26728	this.cache = {
26729		event: {},
26730		target: $(),
26731		disabled: FALSE,
26732		attr: attr,
26733		onTooltip: FALSE,
26734		lastClass: ''
26735	};
26736
26737	// Set the initial flags
26738	this.rendered = this.destroyed = this.disabled = this.waiting =
26739		this.hiddenDuringWait = this.positioning = this.triggering = FALSE;
26740}
26741PROTOTYPE = QTip.prototype;
26742
26743PROTOTYPE._when = function(deferreds) {
26744	return $.when.apply($, deferreds);
26745};
26746
26747PROTOTYPE.render = function(show) {
26748	if(this.rendered || this.destroyed) { return this; } // If tooltip has already been rendered, exit
26749
26750	var self = this,
26751		options = this.options,
26752		cache = this.cache,
26753		elements = this.elements,
26754		text = options.content.text,
26755		title = options.content.title,
26756		button = options.content.button,
26757		posOptions = options.position,
26758		deferreds = [];
26759
26760	// Add ARIA attributes to target
26761	$.attr(this.target[0], 'aria-describedby', this._id);
26762
26763	// Create public position object that tracks current position corners
26764	cache.posClass = this._createPosClass(
26765		(this.position = { my: posOptions.my, at: posOptions.at }).my
26766	);
26767
26768	// Create tooltip element
26769	this.tooltip = elements.tooltip = $('<div/>', {
26770		'id': this._id,
26771		'class': [ NAMESPACE, CLASS_DEFAULT, options.style.classes, cache.posClass ].join(' '),
26772		'width': options.style.width || '',
26773		'height': options.style.height || '',
26774		'tracking': posOptions.target === 'mouse' && posOptions.adjust.mouse,
26775
26776		/* ARIA specific attributes */
26777		'role': 'alert',
26778		'aria-live': 'polite',
26779		'aria-atomic': FALSE,
26780		'aria-describedby': this._id + '-content',
26781		'aria-hidden': TRUE
26782	})
26783	.toggleClass(CLASS_DISABLED, this.disabled)
26784	.attr(ATTR_ID, this.id)
26785	.data(NAMESPACE, this)
26786	.appendTo(posOptions.container)
26787	.append(
26788		// Create content element
26789		elements.content = $('<div />', {
26790			'class': NAMESPACE + '-content',
26791			'id': this._id + '-content',
26792			'aria-atomic': TRUE
26793		})
26794	);
26795
26796	// Set rendered flag and prevent redundant reposition calls for now
26797	this.rendered = -1;
26798	this.positioning = TRUE;
26799
26800	// Create title...
26801	if(title) {
26802		this._createTitle();
26803
26804		// Update title only if its not a callback (called in toggle if so)
26805		if(!$.isFunction(title)) {
26806			deferreds.push( this._updateTitle(title, FALSE) );
26807		}
26808	}
26809
26810	// Create button
26811	if(button) { this._createButton(); }
26812
26813	// Set proper rendered flag and update content if not a callback function (called in toggle)
26814	if(!$.isFunction(text)) {
26815		deferreds.push( this._updateContent(text, FALSE) );
26816	}
26817	this.rendered = TRUE;
26818
26819	// Setup widget classes
26820	this._setWidget();
26821
26822	// Initialize 'render' plugins
26823	$.each(PLUGINS, function(name) {
26824		var instance;
26825		if(this.initialize === 'render' && (instance = this(self))) {
26826			self.plugins[name] = instance;
26827		}
26828	});
26829
26830	// Unassign initial events and assign proper events
26831	this._unassignEvents();
26832	this._assignEvents();
26833
26834	// When deferreds have completed
26835	this._when(deferreds).then(function() {
26836		// tooltiprender event
26837		self._trigger('render');
26838
26839		// Reset flags
26840		self.positioning = FALSE;
26841
26842		// Show tooltip if not hidden during wait period
26843		if(!self.hiddenDuringWait && (options.show.ready || show)) {
26844			self.toggle(TRUE, cache.event, FALSE);
26845		}
26846		self.hiddenDuringWait = FALSE;
26847	});
26848
26849	// Expose API
26850	QTIP.api[this.id] = this;
26851
26852	return this;
26853};
26854
26855PROTOTYPE.destroy = function(immediate) {
26856	// Set flag the signify destroy is taking place to plugins
26857	// and ensure it only gets destroyed once!
26858	if(this.destroyed) { return this.target; }
26859
26860	function process() {
26861		if(this.destroyed) { return; }
26862		this.destroyed = TRUE;
26863
26864		var target = this.target,
26865			title = target.attr(oldtitle),
26866			timer;
26867
26868		// Destroy tooltip if rendered
26869		if(this.rendered) {
26870			this.tooltip.stop(1,0).find('*').remove().end().remove();
26871		}
26872
26873		// Destroy all plugins
26874		$.each(this.plugins, function() {
26875			this.destroy && this.destroy();
26876		});
26877
26878		// Clear timers
26879		for (timer in this.timers) {
26880			if (this.timers.hasOwnProperty(timer)) {
26881				clearTimeout(this.timers[timer]);
26882			}
26883		}
26884
26885		// Remove api object and ARIA attributes
26886		target.removeData(NAMESPACE)
26887			.removeAttr(ATTR_ID)
26888			.removeAttr(ATTR_HAS)
26889			.removeAttr('aria-describedby');
26890
26891		// Reset old title attribute if removed
26892		if(this.options.suppress && title) {
26893			target.attr('title', title).removeAttr(oldtitle);
26894		}
26895
26896		// Remove qTip events associated with this API
26897		this._unassignEvents();
26898
26899		// Remove ID from used id objects, and delete object references
26900		// for better garbage collection and leak protection
26901		this.options = this.elements = this.cache = this.timers =
26902			this.plugins = this.mouse = NULL;
26903
26904		// Delete epoxsed API object
26905		delete QTIP.api[this.id];
26906	}
26907
26908	// If an immediate destroy is needed
26909	if((immediate !== TRUE || this.triggering === 'hide') && this.rendered) {
26910		this.tooltip.one('tooltiphidden', $.proxy(process, this));
26911		!this.triggering && this.hide();
26912	}
26913
26914	// If we're not in the process of hiding... process
26915	else { process.call(this); }
26916
26917	return this.target;
26918};
26919;
26919function invalidOpt(a) {
26920	return a === NULL || $.type(a) !== 'object';
26921}
26922
26923function invalidContent(c) {
26924	return !($.isFunction(c) || c && c.attr) || c.length || $.type(c) === 'object' && (c.jquery || c.then
vendor: 13,218 bytes, lines 26924-27396
26924);
26925}
26926
26927// Option object sanitizer
26928function sanitizeOptions(opts) {
26929	var content, text, ajax, once;
26930
26931	if(invalidOpt(opts)) { return FALSE; }
26932
26933	if(invalidOpt(opts.metadata)) {
26934		opts.metadata = { type: opts.metadata };
26935	}
26936
26937	if('content' in opts) {
26938		content = opts.content;
26939
26940		if(invalidOpt(content) || content.jquery || content.done) {
26941			text = invalidContent(content) ? FALSE : content;
26942			content = opts.content = {
26943				text: text
26944			};
26945		}
26946		else { text = content.text; }
26947
26948		// DEPRECATED - Old content.ajax plugin functionality
26949		// Converts it into the proper Deferred syntax
26950		if('ajax' in content) {
26951			ajax = content.ajax;
26952			once = ajax && ajax.once !== FALSE;
26953			delete content.ajax;
26954
26955			content.text = function(event, api) {
26956				var loading = text || $(this).attr(api.options.content.attr) || 'Loading...',
26957
26958				deferred = $.ajax(
26959					$.extend({}, ajax, { context: api })
26960				)
26961				.then(ajax.success, NULL, ajax.error)
26962				.then(function(newContent) {
26963					if(newContent && once) { api.set('content.text', newContent); }
26964					return newContent;
26965				},
26966				function(xhr, status, error) {
26967					if(api.destroyed || xhr.status === 0) { return; }
26968					api.set('content.text', status + ': ' + error);
26969				});
26970
26971				return !once ? (api.set('content.text', loading), deferred) : loading;
26972			};
26973		}
26974
26975		if('title' in content) {
26976			if($.isPlainObject(content.title)) {
26977				content.button = content.title.button;
26978				content.title = content.title.text;
26979			}
26980
26981			if(invalidContent(content.title || FALSE)) {
26982				content.title = FALSE;
26983			}
26984		}
26985	}
26986
26987	if('position' in opts && invalidOpt(opts.position)) {
26988		opts.position = { my: opts.position, at: opts.position };
26989	}
26990
26991	if('show' in opts && invalidOpt(opts.show)) {
26992		opts.show = opts.show.jquery ? { target: opts.show } :
26993			opts.show === TRUE ? { ready: TRUE } : { event: opts.show };
26994	}
26995
26996	if('hide' in opts && invalidOpt(opts.hide)) {
26997		opts.hide = opts.hide.jquery ? { target: opts.hide } : { event: opts.hide };
26998	}
26999
27000	if('style' in opts && invalidOpt(opts.style)) {
27001		opts.style = { classes: opts.style };
27002	}
27003
27004	// Sanitize plugin options
27005	$.each(PLUGINS, function() {
27006		this.sanitize && this.sanitize(opts);
27007	});
27008
27009	return opts;
27010}
27011
27012// Setup builtin .set() option checks
27013CHECKS = PROTOTYPE.checks = {
27014	builtin: {
27015		// Core checks
27016		'^id$': function(obj, o, v, prev) {
27017			var id = v === TRUE ? QTIP.nextid : v,
27018				newId = NAMESPACE + '-' + id;
27019
27020			if(id !== FALSE && id.length > 0 && !$('#'+newId).length) {
27021				this._id = newId;
27022
27023				if(this.rendered) {
27024					this.tooltip[0].id = this._id;
27025					this.elements.content[0].id = this._id + '-content';
27026					this.elements.title[0].id = this._id + '-title';
27027				}
27028			}
27029			else { obj[o] = prev; }
27030		},
27031		'^prerender': function(obj, o, v) {
27032			v && !this.rendered && this.render(this.options.show.ready);
27033		},
27034
27035		// Content checks
27036		'^content.text$': function(obj, o, v) {
27037			this._updateContent(v);
27038		},
27039		'^content.attr$': function(obj, o, v, prev) {
27040			if(this.options.content.text === this.target.attr(prev)) {
27041				this._updateContent( this.target.attr(v) );
27042			}
27043		},
27044		'^content.title$': function(obj, o, v) {
27045			// Remove title if content is null
27046			if(!v) { return this._removeTitle(); }
27047
27048			// If title isn't already created, create it now and update
27049			v && !this.elements.title && this._createTitle();
27050			this._updateTitle(v);
27051		},
27052		'^content.button$': function(obj, o, v) {
27053			this._updateButton(v);
27054		},
27055		'^content.title.(text|button)$': function(obj, o, v) {
27056			this.set('content.'+o, v); // Backwards title.text/button compat
27057		},
27058
27059		// Position checks
27060		'^position.(my|at)$': function(obj, o, v){
27061			if('string' === typeof v) {
27062				this.position[o] = obj[o] = new CORNER(v, o === 'at');
27063			}
27064		},
27065		'^position.container$': function(obj, o, v){
27066			this.rendered && this.tooltip.appendTo(v);
27067		},
27068
27069		// Show checks
27070		'^show.ready$': function(obj, o, v) {
27071			v && (!this.rendered && this.render(TRUE) || this.toggle(TRUE));
27072		},
27073
27074		// Style checks
27075		'^style.classes$': function(obj, o, v, p) {
27076			this.rendered && this.tooltip.removeClass(p).addClass(v);
27077		},
27078		'^style.(width|height)': function(obj, o, v) {
27079			this.rendered && this.tooltip.css(o, v);
27080		},
27081		'^style.widget|content.title': function() {
27082			this.rendered && this._setWidget();
27083		},
27084		'^style.def': function(obj, o, v) {
27085			this.rendered && this.tooltip.toggleClass(CLASS_DEFAULT, !!v);
27086		},
27087
27088		// Events check
27089		'^events.(render|show|move|hide|focus|blur)$': function(obj, o, v) {
27090			this.rendered && this.tooltip[($.isFunction(v) ? '' : 'un') + 'bind']('tooltip'+o, v);
27091		},
27092
27093		// Properties which require event reassignment
27094		'^(show|hide|position).(event|target|fixed|inactive|leave|distance|viewport|adjust)': function() {
27095			if(!this.rendered) { return; }
27096
27097			// Set tracking flag
27098			var posOptions = this.options.position;
27099			this.tooltip.attr('tracking', posOptions.target === 'mouse' && posOptions.adjust.mouse);
27100
27101			// Reassign events
27102			this._unassignEvents();
27103			this._assignEvents();
27104		}
27105	}
27106};
27107
27108// Dot notation converter
27109function convertNotation(options, notation) {
27110	var i = 0, obj, option = options,
27111
27112	// Split notation into array
27113	levels = notation.split('.');
27114
27115	// Loop through
27116	while(option = option[ levels[i++] ]) {
27117		if(i < levels.length) { obj = option; }
27118	}
27119
27120	return [obj || options, levels.pop()];
27121}
27122
27123PROTOTYPE.get = function(notation) {
27124	if(this.destroyed) { return this; }
27125
27126	var o = convertNotation(this.options, notation.toLowerCase()),
27127		result = o[0][ o[1] ];
27128
27129	return result.precedance ? result.string() : result;
27130};
27131
27132function setCallback(notation, args) {
27133	var category, rule, match;
27134
27135	for(category in this.checks) {
27136		if (!this.checks.hasOwnProperty(category)) { continue; }
27137
27138		for(rule in this.checks[category]) {
27139			if (!this.checks[category].hasOwnProperty(rule)) { continue; }
27140
27141			if(match = (new RegExp(rule, 'i')).exec(notation)) {
27142				args.push(match);
27143
27144				if(category === 'builtin' || this.plugins[category]) {
27145					this.checks[category][rule].apply(
27146						this.plugins[category] || this, args
27147					);
27148				}
27149			}
27150		}
27151	}
27152}
27153
27154var rmove = /^position\.(my|at|adjust|target|container|viewport)|style|content|show\.ready/i,
27155	rrender = /^prerender|show\.ready/i;
27156
27157PROTOTYPE.set = function(option, value) {
27158	if(this.destroyed) { return this; }
27159
27160	var rendered = this.rendered,
27161		reposition = FALSE,
27162		options = this.options,
27163		name;
27164
27165	// Convert singular option/value pair into object form
27166	if('string' === typeof option) {
27167		name = option; option = {}; option[name] = value;
27168	}
27169	else { option = $.extend({}, option); }
27170
27171	// Set all of the defined options to their new values
27172	$.each(option, function(notation, val) {
27173		if(rendered && rrender.test(notation)) {
27174			delete option[notation]; return;
27175		}
27176
27177		// Set new obj value
27178		var obj = convertNotation(options, notation.toLowerCase()), previous;
27179		previous = obj[0][ obj[1] ];
27180		obj[0][ obj[1] ] = val && val.nodeType ? $(val) : val;
27181
27182		// Also check if we need to reposition
27183		reposition = rmove.test(notation) || reposition;
27184
27185		// Set the new params for the callback
27186		option[notation] = [obj[0], obj[1], val, previous];
27187	});
27188
27189	// Re-sanitize options
27190	sanitizeOptions(options);
27191
27192	/*
27193	 * Execute any valid callbacks for the set options
27194	 * Also set positioning flag so we don't get loads of redundant repositioning calls.
27195	 */
27196	this.positioning = TRUE;
27197	$.each(option, $.proxy(setCallback, this));
27198	this.positioning = FALSE;
27199
27200	// Update position if needed
27201	if(this.rendered && this.tooltip[0].offsetWidth > 0 && reposition) {
27202		this.reposition( options.position.target === 'mouse' ? NULL : this.cache.event );
27203	}
27204
27205	return this;
27206};
27207;PROTOTYPE._update = function(content, element) {
27208	var self = this,
27209		cache = this.cache;
27210
27211	// Make sure tooltip is rendered and content is defined. If not return
27212	if(!this.rendered || !content) { return FALSE; }
27213
27214	// Use function to parse content
27215	if($.isFunction(content)) {
27216		content = content.call(this.elements.target, cache.event, this) || '';
27217	}
27218
27219	// Handle deferred content
27220	if($.isFunction(content.then)) {
27221		cache.waiting = TRUE;
27222		return content.then(function(c) {
27223			cache.waiting = FALSE;
27224			return self._update(c, element);
27225		}, NULL, function(e) {
27226			return self._update(e, element);
27227		});
27228	}
27229
27230	// If content is null... return false
27231	if(content === FALSE || !content && content !== '') { return FALSE; }
27232
27233	// Append new content if its a DOM array and show it if hidden
27234	if(content.jquery && content.length > 0) {
27235		element.empty().append(
27236			content.css({ display: 'block', visibility: 'visible' })
27237		);
27238	}
27239
27240	// Content is a regular string, insert the new content
27241	else { element.html(content); }
27242
27243	// Wait for content to be loaded, and reposition
27244	return this._waitForContent(element).then(function(images) {
27245		if(self.rendered && self.tooltip[0].offsetWidth > 0) {
27246			self.reposition(cache.event, !images.length);
27247		}
27248	});
27249};
27250
27251PROTOTYPE._waitForContent = function(element) {
27252	var cache = this.cache;
27253
27254	// Set flag
27255	cache.waiting = TRUE;
27256
27257	// If imagesLoaded is included, ensure images have loaded and return promise
27258	return ( $.fn.imagesLoaded ? element.imagesLoaded() : new $.Deferred().resolve([]) )
27259		.done(function() { cache.waiting = FALSE; })
27260		.promise();
27261};
27262
27263PROTOTYPE._updateContent = function(content, reposition) {
27264	this._update(content, this.elements.content, reposition);
27265};
27266
27267PROTOTYPE._updateTitle = function(content, reposition) {
27268	if(this._update(content, this.elements.title, reposition) === FALSE) {
27269		this._removeTitle(FALSE);
27270	}
27271};
27272
27273PROTOTYPE._createTitle = function()
27274{
27275	var elements = this.elements,
27276		id = this._id+'-title';
27277
27278	// Destroy previous title element, if present
27279	if(elements.titlebar) { this._removeTitle(); }
27280
27281	// Create title bar and title elements
27282	elements.titlebar = $('<div />', {
27283		'class': NAMESPACE + '-titlebar ' + (this.options.style.widget ? createWidgetClass('header') : '')
27284	})
27285	.append(
27286		elements.title = $('<div />', {
27287			'id': id,
27288			'class': NAMESPACE + '-title',
27289			'aria-atomic': TRUE
27290		})
27291	)
27292	.insertBefore(elements.content)
27293
27294	// Button-specific events
27295	.delegate('.qtip-close', 'mousedown keydown mouseup keyup mouseout', function(event) {
27296		$(this).toggleClass('ui-state-active ui-state-focus', event.type.substr(-4) === 'down');
27297	})
27298	.delegate('.qtip-close', 'mouseover mouseout', function(event){
27299		$(this).toggleClass('ui-state-hover', event.type === 'mouseover');
27300	});
27301
27302	// Create button if enabled
27303	if(this.options.content.button) { this._createButton(); }
27304};
27305
27306PROTOTYPE._removeTitle = function(reposition)
27307{
27308	var elements = this.elements;
27309
27310	if(elements.title) {
27311		elements.titlebar.remove();
27312		elements.titlebar = elements.title = elements.button = NULL;
27313
27314		// Reposition if enabled
27315		if(reposition !== FALSE) { this.reposition(); }
27316	}
27317};
27318;PROTOTYPE._createPosClass = function(my) {
27319	return NAMESPACE + '-pos-' + (my || this.options.position.my).abbrev();
27320};
27321
27322PROTOTYPE.reposition = function(event, effect) {
27323	if(!this.rendered || this.positioning || this.destroyed) { return this; }
27324
27325	// Set positioning flag
27326	this.positioning = TRUE;
27327
27328	var cache = this.cache,
27329		tooltip = this.tooltip,
27330		posOptions = this.options.position,
27331		target = posOptions.target,
27332		my = posOptions.my,
27333		at = posOptions.at,
27334		viewport = posOptions.viewport,
27335		container = posOptions.container,
27336		adjust = posOptions.adjust,
27337		method = adjust.method.split(' '),
27338		tooltipWidth = tooltip.outerWidth(FALSE),
27339		tooltipHeight = tooltip.outerHeight(FALSE),
27340		targetWidth = 0,
27341		targetHeight = 0,
27342		type = tooltip.css('position'),
27343		position = { left: 0, top: 0 },
27344		visible = tooltip[0].offsetWidth > 0,
27345		isScroll = event && event.type === 'scroll',
27346		win = $(window),
27347		doc = container[0].ownerDocument,
27348		mouse = this.mouse,
27349		pluginCalculations, offset, adjusted, newClass;
27350
27351	// Check if absolute position was passed
27352	if($.isArray(target) && target.length === 2) {
27353		// Force left top and set position
27354		at = { x: LEFT, y: TOP };
27355		position = { left: target[0], top: target[1] };
27356	}
27357
27358	// Check if mouse was the target
27359	else if(target === 'mouse') {
27360		// Force left top to allow flipping
27361		at = { x: LEFT, y: TOP };
27362
27363		// Use the mouse origin that caused the show event, if distance hiding is enabled
27364		if((!adjust.mouse || this.options.hide.distance) && cache.origin && cache.origin.pageX) {
27365			event =  cache.origin;
27366		}
27367
27368		// Use cached event for resize/scroll events
27369		else if(!event || event && (event.type === 'resize' || event.type === 'scroll')) {
27370			event = cache.event;
27371		}
27372
27373		// Otherwise, use the cached mouse coordinates if available
27374		else if(mouse && mouse.pageX) {
27375			event = mouse;
27376		}
27377
27378		// Calculate body and container offset and take them into account below
27379		if(type !== 'static') { position = container.offset(); }
27380		if(doc.body.offsetWidth !== (window.innerWidth || doc.documentElement.clientWidth)) {
27381			offset = $(document.body).offset();
27382		}
27383
27384		// Use event coordinates for position
27385		position = {
27386			left: event.pageX - position.left + (offset && offset.left || 0),
27387			top: event.pageY - position.top + (offset && offset.top || 0)
27388		};
27389
27390		// Scroll events are a pain, some browsers
27391		if(adjust.mouse && isScroll && mouse) {
27392			position.left -= (mouse.scrollX || 0) - win.scrollLeft();
27393			position.top -= (mouse.scrollY || 0) - win.scrollTop();
27394		}
27395	}
27396
vendor: 8,382 bytes, lines 27397-27645
27397	// Target wasn't mouse or absolute...
27398	else {
27399		// Check if event targetting is being used
27400		if(target === 'event') {
27401			if(event && event.target && event.type !== 'scroll' && event.type !== 'resize') {
27402				cache.target = $(event.target);
27403			}
27404			else if(!event.target) {
27405				cache.target = this.elements.target;
27406			}
27407		}
27408		else if(target !== 'event'){
27409			cache.target = $(target.jquery ? target : this.elements.target);
27410		}
27411		target = cache.target;
27412
27413		// Parse the target into a jQuery object and make sure there's an element present
27414		target = $(target).eq(0);
27415		if(target.length === 0) { return this; }
27416
27417		// Check if window or document is the target
27418		else if(target[0] === document || target[0] === window) {
27419			targetWidth = BROWSER.iOS ? window.innerWidth : target.width();
27420			targetHeight = BROWSER.iOS ? window.innerHeight : target.height();
27421
27422			if(target[0] === window) {
27423				position = {
27424					top: (viewport || target).scrollTop(),
27425					left: (viewport || target).scrollLeft()
27426				};
27427			}
27428		}
27429
27430		// Check if the target is an <AREA> element
27431		else if(PLUGINS.imagemap && target.is('area')) {
27432			pluginCalculations = PLUGINS.imagemap(this, target, at, PLUGINS.viewport ? method : FALSE);
27433		}
27434
27435		// Check if the target is an SVG element
27436		else if(PLUGINS.svg && target && target[0].ownerSVGElement) {
27437			pluginCalculations = PLUGINS.svg(this, target, at, PLUGINS.viewport ? method : FALSE);
27438		}
27439
27440		// Otherwise use regular jQuery methods
27441		else {
27442			targetWidth = target.outerWidth(FALSE);
27443			targetHeight = target.outerHeight(FALSE);
27444			position = target.offset();
27445		}
27446
27447		// Parse returned plugin values into proper variables
27448		if(pluginCalculations) {
27449			targetWidth = pluginCalculations.width;
27450			targetHeight = pluginCalculations.height;
27451			offset = pluginCalculations.offset;
27452			position = pluginCalculations.position;
27453		}
27454
27455		// Adjust position to take into account offset parents
27456		position = this.reposition.offset(target, position, container);
27457
27458		// Adjust for position.fixed tooltips (and also iOS scroll bug in v3.2-4.0 & v4.3-4.3.2)
27459		if(BROWSER.iOS > 3.1 && BROWSER.iOS < 4.1 ||
27460			BROWSER.iOS >= 4.3 && BROWSER.iOS < 4.33 ||
27461			!BROWSER.iOS && type === 'fixed'
27462		){
27463			position.left -= win.scrollLeft();
27464			position.top -= win.scrollTop();
27465		}
27466
27467		// Adjust position relative to target
27468		if(!pluginCalculations || pluginCalculations && pluginCalculations.adjustable !== FALSE) {
27469			position.left += at.x === RIGHT ? targetWidth : at.x === CENTER ? targetWidth / 2 : 0;
27470			position.top += at.y === BOTTOM ? targetHeight : at.y === CENTER ? targetHeight / 2 : 0;
27471		}
27472	}
27473
27474	// Adjust position relative to tooltip
27475	position.left += adjust.x + (my.x === RIGHT ? -tooltipWidth : my.x === CENTER ? -tooltipWidth / 2 : 0);
27476	position.top += adjust.y + (my.y === BOTTOM ? -tooltipHeight : my.y === CENTER ? -tooltipHeight / 2 : 0);
27477
27478	// Use viewport adjustment plugin if enabled
27479	if(PLUGINS.viewport) {
27480		adjusted = position.adjusted = PLUGINS.viewport(
27481			this, position, posOptions, targetWidth, targetHeight, tooltipWidth, tooltipHeight
27482		);
27483
27484		// Apply offsets supplied by positioning plugin (if used)
27485		if(offset && adjusted.left) { position.left += offset.left; }
27486		if(offset && adjusted.top) {  position.top += offset.top; }
27487
27488		// Apply any new 'my' position
27489		if(adjusted.my) { this.position.my = adjusted.my; }
27490	}
27491
27492	// Viewport adjustment is disabled, set values to zero
27493	else { position.adjusted = { left: 0, top: 0 }; }
27494
27495	// Set tooltip position class if it's changed
27496	if(cache.posClass !== (newClass = this._createPosClass(this.position.my))) {
27497		cache.posClass = newClass;
27498		tooltip.removeClass(cache.posClass).addClass(newClass);
27499	}
27500
27501	// tooltipmove event
27502	if(!this._trigger('move', [position, viewport.elem || viewport], event)) { return this; }
27503	delete position.adjusted;
27504
27505	// If effect is disabled, target it mouse, no animation is defined or positioning gives NaN out, set CSS directly
27506	if(effect === FALSE || !visible || isNaN(position.left) || isNaN(position.top) || target === 'mouse' || !$.isFunction(posOptions.effect)) {
27507		tooltip.css(position);
27508	}
27509
27510	// Use custom function if provided
27511	else if($.isFunction(posOptions.effect)) {
27512		posOptions.effect.call(tooltip, this, $.extend({}, position));
27513		tooltip.queue(function(next) {
27514			// Reset attributes to avoid cross-browser rendering bugs
27515			$(this).css({ opacity: '', height: '' });
27516			if(BROWSER.ie) { this.style.removeAttribute('filter'); }
27517
27518			next();
27519		});
27520	}
27521
27522	// Set positioning flag
27523	this.positioning = FALSE;
27524
27525	return this;
27526};
27527
27528// Custom (more correct for qTip!) offset calculator
27529PROTOTYPE.reposition.offset = function(elem, pos, container) {
27530	if(!container[0]) { return pos; }
27531
27532	var ownerDocument = $(elem[0].ownerDocument),
27533		quirks = !!BROWSER.ie && document.compatMode !== 'CSS1Compat',
27534		parent = container[0],
27535		scrolled, position, parentOffset, overflow;
27536
27537	function scroll(e, i) {
27538		pos.left += i * e.scrollLeft();
27539		pos.top += i * e.scrollTop();
27540	}
27541
27542	// Compensate for non-static containers offset
27543	do {
27544		if((position = $.css(parent, 'position')) !== 'static') {
27545			if(position === 'fixed') {
27546				parentOffset = parent.getBoundingClientRect();
27547				scroll(ownerDocument, -1);
27548			}
27549			else {
27550				parentOffset = $(parent).position();
27551				parentOffset.left += parseFloat($.css(parent, 'borderLeftWidth')) || 0;
27552				parentOffset.top += parseFloat($.css(parent, 'borderTopWidth')) || 0;
27553			}
27554
27555			pos.left -= parentOffset.left + (parseFloat($.css(parent, 'marginLeft')) || 0);
27556			pos.top -= parentOffset.top + (parseFloat($.css(parent, 'marginTop')) || 0);
27557
27558			// If this is the first parent element with an overflow of "scroll" or "auto", store it
27559			if(!scrolled && (overflow = $.css(parent, 'overflow')) !== 'hidden' && overflow !== 'visible') { scrolled = $(parent); }
27560		}
27561	}
27562	while(parent = parent.offsetParent);
27563
27564	// Compensate for containers scroll if it also has an offsetParent (or in IE quirks mode)
27565	if(scrolled && (scrolled[0] !== ownerDocument[0] || quirks)) {
27566		scroll(scrolled, 1);
27567	}
27568
27569	return pos;
27570};
27571
27572// Corner class
27573var C = (CORNER = PROTOTYPE.reposition.Corner = function(corner, forceY) {
27574	corner = ('' + corner).replace(/([A-Z])/, ' $1').replace(/middle/gi, CENTER).toLowerCase();
27575	this.x = (corner.match(/left|right/i) || corner.match(/center/) || ['inherit'])[0].toLowerCase();
27576	this.y = (corner.match(/top|bottom|center/i) || ['inherit'])[0].toLowerCase();
27577	this.forceY = !!forceY;
27578
27579	var f = corner.charAt(0);
27580	this.precedance = f === 't' || f === 'b' ? Y : X;
27581}).prototype;
27582
27583C.invert = function(z, center) {
27584	this[z] = this[z] === LEFT ? RIGHT : this[z] === RIGHT ? LEFT : center || this[z];
27585};
27586
27587C.string = function(join) {
27588	var x = this.x, y = this.y;
27589
27590	var result = x !== y ?
27591		x === 'center' || y !== 'center' && (this.precedance === Y || this.forceY) ? 
27592			[y,x] : 
27593			[x,y] :
27594		[x];
27595
27596	return join !== false ? result.join(' ') : result;
27597};
27598
27599C.abbrev = function() {
27600	var result = this.string(false);
27601	return result[0].charAt(0) + (result[1] && result[1].charAt(0) || '');
27602};
27603
27604C.clone = function() {
27605	return new CORNER( this.string(), this.forceY );
27606};
27607
27608;
27609PROTOTYPE.toggle = function(state, event) {
27610	var cache = this.cache,
27611		options = this.options,
27612		tooltip = this.tooltip;
27613
27614	// Try to prevent flickering when tooltip overlaps show element
27615	if(event) {
27616		if((/over|enter/).test(event.type) && cache.event && (/out|leave/).test(cache.event.type) &&
27617			options.show.target.add(event.target).length === options.show.target.length &&
27618			tooltip.has(event.relatedTarget).length) {
27619			return this;
27620		}
27621
27622		// Cache event
27623		cache.event = $.event.fix(event);
27624	}
27625
27626	// If we're currently waiting and we've just hidden... stop it
27627	this.waiting && !state && (this.hiddenDuringWait = TRUE);
27628
27629	// Render the tooltip if showing and it isn't already
27630	if(!this.rendered) { return state ? this.render(1) : this; }
27631	else if(this.destroyed || this.disabled) { return this; }
27632
27633	var type = state ? 'show' : 'hide',
27634		opts = this.options[type],
27635		posOptions = this.options.position,
27636		contentOptions = this.options.content,
27637		width = this.tooltip.css('width'),
27638		visible = this.tooltip.is(':visible'),
27639		animate = state || opts.target.length === 1,
27640		sameTarget = !event || opts.target.length < 2 || cache.target[0] === event.target,
27641		identicalState, allow, after;
27642
27643	// Detect state if valid one isn't provided
27644	if((typeof state).search('boolean|number')) { state = !visible; }
27645
vendor: 23,703 bytes, lines 27646-28389
27646	// Check if the tooltip is in an identical state to the new would-be state
27647	identicalState = !tooltip.is(':animated') && visible === state && sameTarget;
27648
27649	// Fire tooltip(show/hide) event and check if destroyed
27650	allow = !identicalState ? !!this._trigger(type, [90]) : NULL;
27651
27652	// Check to make sure the tooltip wasn't destroyed in the callback
27653	if(this.destroyed) { return this; }
27654
27655	// If the user didn't stop the method prematurely and we're showing the tooltip, focus it
27656	if(allow !== FALSE && state) { this.focus(event); }
27657
27658	// If the state hasn't changed or the user stopped it, return early
27659	if(!allow || identicalState) { return this; }
27660
27661	// Set ARIA hidden attribute
27662	$.attr(tooltip[0], 'aria-hidden', !!!state);
27663
27664	// Execute state specific properties
27665	if(state) {
27666		// Store show origin coordinates
27667		this.mouse && (cache.origin = $.event.fix(this.mouse));
27668
27669		// Update tooltip content & title if it's a dynamic function
27670		if($.isFunction(contentOptions.text)) { this._updateContent(contentOptions.text, FALSE); }
27671		if($.isFunction(contentOptions.title)) { this._updateTitle(contentOptions.title, FALSE); }
27672
27673		// Cache mousemove events for positioning purposes (if not already tracking)
27674		if(!trackingBound && posOptions.target === 'mouse' && posOptions.adjust.mouse) {
27675			$(document).bind('mousemove.'+NAMESPACE, this._storeMouse);
27676			trackingBound = TRUE;
27677		}
27678
27679		// Update the tooltip position (set width first to prevent viewport/max-width issues)
27680		if(!width) { tooltip.css('width', tooltip.outerWidth(FALSE)); }
27681		this.reposition(event, arguments[2]);
27682		if(!width) { tooltip.css('width', ''); }
27683
27684		// Hide other tooltips if tooltip is solo
27685		if(!!opts.solo) {
27686			(typeof opts.solo === 'string' ? $(opts.solo) : $(SELECTOR, opts.solo))
27687				.not(tooltip).not(opts.target).qtip('hide', new $.Event('tooltipsolo'));
27688		}
27689	}
27690	else {
27691		// Clear show timer if we're hiding
27692		clearTimeout(this.timers.show);
27693
27694		// Remove cached origin on hide
27695		delete cache.origin;
27696
27697		// Remove mouse tracking event if not needed (all tracking qTips are hidden)
27698		if(trackingBound && !$(SELECTOR+'[tracking="true"]:visible', opts.solo).not(tooltip).length) {
27699			$(document).unbind('mousemove.'+NAMESPACE);
27700			trackingBound = FALSE;
27701		}
27702
27703		// Blur the tooltip
27704		this.blur(event);
27705	}
27706
27707	// Define post-animation, state specific properties
27708	after = $.proxy(function() {
27709		if(state) {
27710			// Prevent antialias from disappearing in IE by removing filter
27711			if(BROWSER.ie) { tooltip[0].style.removeAttribute('filter'); }
27712
27713			// Remove overflow setting to prevent tip bugs
27714			tooltip.css('overflow', '');
27715
27716			// Autofocus elements if enabled
27717			if('string' === typeof opts.autofocus) {
27718				$(this.options.show.autofocus, tooltip).focus();
27719			}
27720
27721			// If set, hide tooltip when inactive for delay period
27722			this.options.show.target.trigger('qtip-'+this.id+'-inactive');
27723		}
27724		else {
27725			// Reset CSS states
27726			tooltip.css({
27727				display: '',
27728				visibility: '',
27729				opacity: '',
27730				left: '',
27731				top: ''
27732			});
27733		}
27734
27735		// tooltipvisible/tooltiphidden events
27736		this._trigger(state ? 'visible' : 'hidden');
27737	}, this);
27738
27739	// If no effect type is supplied, use a simple toggle
27740	if(opts.effect === FALSE || animate === FALSE) {
27741		tooltip[ type ]();
27742		after();
27743	}
27744
27745	// Use custom function if provided
27746	else if($.isFunction(opts.effect)) {
27747		tooltip.stop(1, 1);
27748		opts.effect.call(tooltip, this);
27749		tooltip.queue('fx', function(n) {
27750			after(); n();
27751		});
27752	}
27753
27754	// Use basic fade function by default
27755	else { tooltip.fadeTo(90, state ? 1 : 0, after); }
27756
27757	// If inactive hide method is set, active it
27758	if(state) { opts.target.trigger('qtip-'+this.id+'-inactive'); }
27759
27760	return this;
27761};
27762
27763PROTOTYPE.show = function(event) { return this.toggle(TRUE, event); };
27764
27765PROTOTYPE.hide = function(event) { return this.toggle(FALSE, event); };
27766;PROTOTYPE.focus = function(event) {
27767	if(!this.rendered || this.destroyed) { return this; }
27768
27769	var qtips = $(SELECTOR),
27770		tooltip = this.tooltip,
27771		curIndex = parseInt(tooltip[0].style.zIndex, 10),
27772		newIndex = QTIP.zindex + qtips.length;
27773
27774	// Only update the z-index if it has changed and tooltip is not already focused
27775	if(!tooltip.hasClass(CLASS_FOCUS)) {
27776		// tooltipfocus event
27777		if(this._trigger('focus', [newIndex], event)) {
27778			// Only update z-index's if they've changed
27779			if(curIndex !== newIndex) {
27780				// Reduce our z-index's and keep them properly ordered
27781				qtips.each(function() {
27782					if(this.style.zIndex > curIndex) {
27783						this.style.zIndex = this.style.zIndex - 1;
27784					}
27785				});
27786
27787				// Fire blur event for focused tooltip
27788				qtips.filter('.' + CLASS_FOCUS).qtip('blur', event);
27789			}
27790
27791			// Set the new z-index
27792			tooltip.addClass(CLASS_FOCUS)[0].style.zIndex = newIndex;
27793		}
27794	}
27795
27796	return this;
27797};
27798
27799PROTOTYPE.blur = function(event) {
27800	if(!this.rendered || this.destroyed) { return this; }
27801
27802	// Set focused status to FALSE
27803	this.tooltip.removeClass(CLASS_FOCUS);
27804
27805	// tooltipblur event
27806	this._trigger('blur', [ this.tooltip.css('zIndex') ], event);
27807
27808	return this;
27809};
27810;PROTOTYPE.disable = function(state) {
27811	if(this.destroyed) { return this; }
27812
27813	// If 'toggle' is passed, toggle the current state
27814	if(state === 'toggle') {
27815		state = !(this.rendered ? this.tooltip.hasClass(CLASS_DISABLED) : this.disabled);
27816	}
27817
27818	// Disable if no state passed
27819	else if('boolean' !== typeof state) {
27820		state = TRUE;
27821	}
27822
27823	if(this.rendered) {
27824		this.tooltip.toggleClass(CLASS_DISABLED, state)
27825			.attr('aria-disabled', state);
27826	}
27827
27828	this.disabled = !!state;
27829
27830	return this;
27831};
27832
27833PROTOTYPE.enable = function() { return this.disable(FALSE); };
27834;PROTOTYPE._createButton = function()
27835{
27836	var self = this,
27837		elements = this.elements,
27838		tooltip = elements.tooltip,
27839		button = this.options.content.button,
27840		isString = typeof button === 'string',
27841		close = isString ? button : 'Close tooltip';
27842
27843	if(elements.button) { elements.button.remove(); }
27844
27845	// Use custom button if one was supplied by user, else use default
27846	if(button.jquery) {
27847		elements.button = button;
27848	}
27849	else {
27850		elements.button = $('<a />', {
27851			'class': 'qtip-close ' + (this.options.style.widget ? '' : NAMESPACE+'-icon'),
27852			'title': close,
27853			'aria-label': close
27854		})
27855		.prepend(
27856			$('<span />', {
27857				'class': 'ui-icon ui-icon-close',
27858				'html': '&times;'
27859			})
27860		);
27861	}
27862
27863	// Create button and setup attributes
27864	elements.button.appendTo(elements.titlebar || tooltip)
27865		.attr('role', 'button')
27866		.click(function(event) {
27867			if(!tooltip.hasClass(CLASS_DISABLED)) { self.hide(event); }
27868			return FALSE;
27869		});
27870};
27871
27872PROTOTYPE._updateButton = function(button)
27873{
27874	// Make sure tooltip is rendered and if not, return
27875	if(!this.rendered) { return FALSE; }
27876
27877	var elem = this.elements.button;
27878	if(button) { this._createButton(); }
27879	else { elem.remove(); }
27880};
27881;// Widget class creator
27882function createWidgetClass(cls) {
27883	return WIDGET.concat('').join(cls ? '-'+cls+' ' : ' ');
27884}
27885
27886// Widget class setter method
27887PROTOTYPE._setWidget = function()
27888{
27889	var on = this.options.style.widget,
27890		elements = this.elements,
27891		tooltip = elements.tooltip,
27892		disabled = tooltip.hasClass(CLASS_DISABLED);
27893
27894	tooltip.removeClass(CLASS_DISABLED);
27895	CLASS_DISABLED = on ? 'ui-state-disabled' : 'qtip-disabled';
27896	tooltip.toggleClass(CLASS_DISABLED, disabled);
27897
27898	tooltip.toggleClass('ui-helper-reset '+createWidgetClass(), on).toggleClass(CLASS_DEFAULT, this.options.style.def && !on);
27899
27900	if(elements.content) {
27901		elements.content.toggleClass( createWidgetClass('content'), on);
27902	}
27903	if(elements.titlebar) {
27904		elements.titlebar.toggleClass( createWidgetClass('header'), on);
27905	}
27906	if(elements.button) {
27907		elements.button.toggleClass(NAMESPACE+'-icon', !on);
27908	}
27909};
27910;function delay(callback, duration) {
27911	// If tooltip has displayed, start hide timer
27912	if(duration > 0) {
27913		return setTimeout(
27914			$.proxy(callback, this), duration
27915		);
27916	}
27917	else{ callback.call(this); }
27918}
27919
27920function showMethod(event) {
27921	if(this.tooltip.hasClass(CLASS_DISABLED)) { return; }
27922
27923	// Clear hide timers
27924	clearTimeout(this.timers.show);
27925	clearTimeout(this.timers.hide);
27926
27927	// Start show timer
27928	this.timers.show = delay.call(this,
27929		function() { this.toggle(TRUE, event); },
27930		this.options.show.delay
27931	);
27932}
27933
27934function hideMethod(event) {
27935	if(this.tooltip.hasClass(CLASS_DISABLED) || this.destroyed) { return; }
27936
27937	// Check if new target was actually the tooltip element
27938	var relatedTarget = $(event.relatedTarget),
27939		ontoTooltip = relatedTarget.closest(SELECTOR)[0] === this.tooltip[0],
27940		ontoTarget = relatedTarget[0] === this.options.show.target[0];
27941
27942	// Clear timers and stop animation queue
27943	clearTimeout(this.timers.show);
27944	clearTimeout(this.timers.hide);
27945
27946	// Prevent hiding if tooltip is fixed and event target is the tooltip.
27947	// Or if mouse positioning is enabled and cursor momentarily overlaps
27948	if(this !== relatedTarget[0] &&
27949		(this.options.position.target === 'mouse' && ontoTooltip) ||
27950		this.options.hide.fixed && (
27951			(/mouse(out|leave|move)/).test(event.type) && (ontoTooltip || ontoTarget))
27952		)
27953	{
27954		/* eslint-disable no-empty */
27955		try {
27956			event.preventDefault();
27957			event.stopImmediatePropagation();
27958		} catch(e) {}
27959		/* eslint-enable no-empty */
27960
27961		return;
27962	}
27963
27964	// If tooltip has displayed, start hide timer
27965	this.timers.hide = delay.call(this,
27966		function() { this.toggle(FALSE, event); },
27967		this.options.hide.delay,
27968		this
27969	);
27970}
27971
27972function inactiveMethod(event) {
27973	if(this.tooltip.hasClass(CLASS_DISABLED) || !this.options.hide.inactive) { return; }
27974
27975	// Clear timer
27976	clearTimeout(this.timers.inactive);
27977
27978	this.timers.inactive = delay.call(this,
27979		function(){ this.hide(event); },
27980		this.options.hide.inactive
27981	);
27982}
27983
27984function repositionMethod(event) {
27985	if(this.rendered && this.tooltip[0].offsetWidth > 0) { this.reposition(event); }
27986}
27987
27988// Store mouse coordinates
27989PROTOTYPE._storeMouse = function(event) {
27990	(this.mouse = $.event.fix(event)).type = 'mousemove';
27991	return this;
27992};
27993
27994// Bind events
27995PROTOTYPE._bind = function(targets, events, method, suffix, context) {
27996	if(!targets || !method || !events.length) { return; }
27997	var ns = '.' + this._id + (suffix ? '-'+suffix : '');
27998	$(targets).bind(
27999		(events.split ? events : events.join(ns + ' ')) + ns,
28000		$.proxy(method, context || this)
28001	);
28002	return this;
28003};
28004PROTOTYPE._unbind = function(targets, suffix) {
28005	targets && $(targets).unbind('.' + this._id + (suffix ? '-'+suffix : ''));
28006	return this;
28007};
28008
28009// Global delegation helper
28010function delegate(selector, events, method) {
28011	$(document.body).delegate(selector,
28012		(events.split ? events : events.join('.'+NAMESPACE + ' ')) + '.'+NAMESPACE,
28013		function() {
28014			var api = QTIP.api[ $.attr(this, ATTR_ID) ];
28015			api && !api.disabled && method.apply(api, arguments);
28016		}
28017	);
28018}
28019// Event trigger
28020PROTOTYPE._trigger = function(type, args, event) {
28021	var callback = new $.Event('tooltip'+type);
28022	callback.originalEvent = event && $.extend({}, event) || this.cache.event || NULL;
28023
28024	this.triggering = type;
28025	this.tooltip.trigger(callback, [this].concat(args || []));
28026	this.triggering = FALSE;
28027
28028	return !callback.isDefaultPrevented();
28029};
28030
28031PROTOTYPE._bindEvents = function(showEvents, hideEvents, showTargets, hideTargets, showCallback, hideCallback) {
28032	// Get tasrgets that lye within both
28033	var similarTargets = showTargets.filter( hideTargets ).add( hideTargets.filter(showTargets) ),
28034		toggleEvents = [];
28035
28036	// If hide and show targets are the same...
28037	if(similarTargets.length) {
28038
28039		// Filter identical show/hide events
28040		$.each(hideEvents, function(i, type) {
28041			var showIndex = $.inArray(type, showEvents);
28042
28043			// Both events are identical, remove from both hide and show events
28044			// and append to toggleEvents
28045			showIndex > -1 && toggleEvents.push( showEvents.splice( showIndex, 1 )[0] );
28046		});
28047
28048		// Toggle events are special case of identical show/hide events, which happen in sequence
28049		if(toggleEvents.length) {
28050			// Bind toggle events to the similar targets
28051			this._bind(similarTargets, toggleEvents, function(event) {
28052				var state = this.rendered ? this.tooltip[0].offsetWidth > 0 : false;
28053				(state ? hideCallback : showCallback).call(this, event);
28054			});
28055
28056			// Remove the similar targets from the regular show/hide bindings
28057			showTargets = showTargets.not(similarTargets);
28058			hideTargets = hideTargets.not(similarTargets);
28059		}
28060	}
28061
28062	// Apply show/hide/toggle events
28063	this._bind(showTargets, showEvents, showCallback);
28064	this._bind(hideTargets, hideEvents, hideCallback);
28065};
28066
28067PROTOTYPE._assignInitialEvents = function(event) {
28068	var options = this.options,
28069		showTarget = options.show.target,
28070		hideTarget = options.hide.target,
28071		showEvents = options.show.event ? $.trim('' + options.show.event).split(' ') : [],
28072		hideEvents = options.hide.event ? $.trim('' + options.hide.event).split(' ') : [];
28073
28074	// Catch remove/removeqtip events on target element to destroy redundant tooltips
28075	this._bind(this.elements.target, ['remove', 'removeqtip'], function() {
28076		this.destroy(true);
28077	}, 'destroy');
28078
28079	/*
28080	 * Make sure hoverIntent functions properly by using mouseleave as a hide event if
28081	 * mouseenter/mouseout is used for show.event, even if it isn't in the users options.
28082	 */
28083	if(/mouse(over|enter)/i.test(options.show.event) && !/mouse(out|leave)/i.test(options.hide.event)) {
28084		hideEvents.push('mouseleave');
28085	}
28086
28087	/*
28088	 * Also make sure initial mouse targetting works correctly by caching mousemove coords
28089	 * on show targets before the tooltip has rendered. Also set onTarget when triggered to
28090	 * keep mouse tracking working.
28091	 */
28092	this._bind(showTarget, 'mousemove', function(moveEvent) {
28093		this._storeMouse(moveEvent);
28094		this.cache.onTarget = TRUE;
28095	});
28096
28097	// Define hoverIntent function
28098	function hoverIntent(hoverEvent) {
28099		// Only continue if tooltip isn't disabled
28100		if(this.disabled || this.destroyed) { return FALSE; }
28101
28102		// Cache the event data
28103		this.cache.event = hoverEvent && $.event.fix(hoverEvent);
28104		this.cache.target = hoverEvent && $(hoverEvent.target);
28105
28106		// Start the event sequence
28107		clearTimeout(this.timers.show);
28108		this.timers.show = delay.call(this,
28109			function() { this.render(typeof hoverEvent === 'object' || options.show.ready); },
28110			options.prerender ? 0 : options.show.delay
28111		);
28112	}
28113
28114	// Filter and bind events
28115	this._bindEvents(showEvents, hideEvents, showTarget, hideTarget, hoverIntent, function() {
28116		if(!this.timers) { return FALSE; }
28117		clearTimeout(this.timers.show);
28118	});
28119
28120	// Prerendering is enabled, create tooltip now
28121	if(options.show.ready || options.prerender) { hoverIntent.call(this, event); }
28122};
28123
28124// Event assignment method
28125PROTOTYPE._assignEvents = function() {
28126	var self = this,
28127		options = this.options,
28128		posOptions = options.position,
28129
28130		tooltip = this.tooltip,
28131		showTarget = options.show.target,
28132		hideTarget = options.hide.target,
28133		containerTarget = posOptions.container,
28134		viewportTarget = posOptions.viewport,
28135		documentTarget = $(document),
28136		windowTarget = $(window),
28137
28138		showEvents = options.show.event ? $.trim('' + options.show.event).split(' ') : [],
28139		hideEvents = options.hide.event ? $.trim('' + options.hide.event).split(' ') : [];
28140
28141
28142	// Assign passed event callbacks
28143	$.each(options.events, function(name, callback) {
28144		self._bind(tooltip, name === 'toggle' ? ['tooltipshow','tooltiphide'] : ['tooltip'+name], callback, null, tooltip);
28145	});
28146
28147	// Hide tooltips when leaving current window/frame (but not select/option elements)
28148	if(/mouse(out|leave)/i.test(options.hide.event) && options.hide.leave === 'window') {
28149		this._bind(documentTarget, ['mouseout', 'blur'], function(event) {
28150			if(!/select|option/.test(event.target.nodeName) && !event.relatedTarget) {
28151				this.hide(event);
28152			}
28153		});
28154	}
28155
28156	// Enable hide.fixed by adding appropriate class
28157	if(options.hide.fixed) {
28158		hideTarget = hideTarget.add( tooltip.addClass(CLASS_FIXED) );
28159	}
28160
28161	/*
28162	 * Make sure hoverIntent functions properly by using mouseleave to clear show timer if
28163	 * mouseenter/mouseout is used for show.event, even if it isn't in the users options.
28164	 */
28165	else if(/mouse(over|enter)/i.test(options.show.event)) {
28166		this._bind(hideTarget, 'mouseleave', function() {
28167			clearTimeout(this.timers.show);
28168		});
28169	}
28170
28171	// Hide tooltip on document mousedown if unfocus events are enabled
28172	if(('' + options.hide.event).indexOf('unfocus') > -1) {
28173		this._bind(containerTarget.closest('html'), ['mousedown', 'touchstart'], function(event) {
28174			var elem = $(event.target),
28175				enabled = this.rendered && !this.tooltip.hasClass(CLASS_DISABLED) && this.tooltip[0].offsetWidth > 0,
28176				isAncestor = elem.parents(SELECTOR).filter(this.tooltip[0]).length > 0;
28177
28178			if(elem[0] !== this.target[0] && elem[0] !== this.tooltip[0] && !isAncestor &&
28179				!this.target.has(elem[0]).length && enabled
28180			) {
28181				this.hide(event);
28182			}
28183		});
28184	}
28185
28186	// Check if the tooltip hides when inactive
28187	if('number' === typeof options.hide.inactive) {
28188		// Bind inactive method to show target(s) as a custom event
28189		this._bind(showTarget, 'qtip-'+this.id+'-inactive', inactiveMethod, 'inactive');
28190
28191		// Define events which reset the 'inactive' event handler
28192		this._bind(hideTarget.add(tooltip), QTIP.inactiveEvents, inactiveMethod);
28193	}
28194
28195	// Filter and bind events
28196	this._bindEvents(showEvents, hideEvents, showTarget, hideTarget, showMethod, hideMethod);
28197
28198	// Mouse movement bindings
28199	this._bind(showTarget.add(tooltip), 'mousemove', function(event) {
28200		// Check if the tooltip hides when mouse is moved a certain distance
28201		if('number' === typeof options.hide.distance) {
28202			var origin = this.cache.origin || {},
28203				limit = this.options.hide.distance,
28204				abs = Math.abs;
28205
28206			// Check if the movement has gone beyond the limit, and hide it if so
28207			if(abs(event.pageX - origin.pageX) >= limit || abs(event.pageY - origin.pageY) >= limit) {
28208				this.hide(event);
28209			}
28210		}
28211
28212		// Cache mousemove coords on show targets
28213		this._storeMouse(event);
28214	});
28215
28216	// Mouse positioning events
28217	if(posOptions.target === 'mouse') {
28218		// If mouse adjustment is on...
28219		if(posOptions.adjust.mouse) {
28220			// Apply a mouseleave event so we don't get problems with overlapping
28221			if(options.hide.event) {
28222				// Track if we're on the target or not
28223				this._bind(showTarget, ['mouseenter', 'mouseleave'], function(event) {
28224					if(!this.cache) {return FALSE; }
28225					this.cache.onTarget = event.type === 'mouseenter';
28226				});
28227			}
28228
28229			// Update tooltip position on mousemove
28230			this._bind(documentTarget, 'mousemove', function(event) {
28231				// Update the tooltip position only if the tooltip is visible and adjustment is enabled
28232				if(this.rendered && this.cache.onTarget && !this.tooltip.hasClass(CLASS_DISABLED) && this.tooltip[0].offsetWidth > 0) {
28233					this.reposition(event);
28234				}
28235			});
28236		}
28237	}
28238
28239	// Adjust positions of the tooltip on window resize if enabled
28240	if(posOptions.adjust.resize || viewportTarget.length) {
28241		this._bind( $.event.special.resize ? viewportTarget : windowTarget, 'resize', repositionMethod );
28242	}
28243
28244	// Adjust tooltip position on scroll of the window or viewport element if present
28245	if(posOptions.adjust.scroll) {
28246		this._bind( windowTarget.add(posOptions.container), 'scroll', repositionMethod );
28247	}
28248};
28249
28250// Un-assignment method
28251PROTOTYPE._unassignEvents = function() {
28252	var options = this.options,
28253		showTargets = options.show.target,
28254		hideTargets = options.hide.target,
28255		targets = $.grep([
28256			this.elements.target[0],
28257			this.rendered && this.tooltip[0],
28258			options.position.container[0],
28259			options.position.viewport[0],
28260			options.position.container.closest('html')[0], // unfocus
28261			window,
28262			document
28263		], function(i) {
28264			return typeof i === 'object';
28265		});
28266
28267	// Add show and hide targets if they're valid
28268	if(showTargets && showTargets.toArray) {
28269		targets = targets.concat(showTargets.toArray());
28270	}
28271	if(hideTargets && hideTargets.toArray) {
28272		targets = targets.concat(hideTargets.toArray());
28273	}
28274
28275	// Unbind the events
28276	this._unbind(targets)
28277		._unbind(targets, 'destroy')
28278		._unbind(targets, 'inactive');
28279};
28280
28281// Apply common event handlers using delegate (avoids excessive .bind calls!)
28282$(function() {
28283	delegate(SELECTOR, ['mouseenter', 'mouseleave'], function(event) {
28284		var state = event.type === 'mouseenter',
28285			tooltip = $(event.currentTarget),
28286			target = $(event.relatedTarget || event.target),
28287			options = this.options;
28288
28289		// On mouseenter...
28290		if(state) {
28291			// Focus the tooltip on mouseenter (z-index stacking)
28292			this.focus(event);
28293
28294			// Clear hide timer on tooltip hover to prevent it from closing
28295			tooltip.hasClass(CLASS_FIXED) && !tooltip.hasClass(CLASS_DISABLED) && clearTimeout(this.timers.hide);
28296		}
28297
28298		// On mouseleave...
28299		else {
28300			// When mouse tracking is enabled, hide when we leave the tooltip and not onto the show target (if a hide event is set)
28301			if(options.position.target === 'mouse' && options.position.adjust.mouse &&
28302				options.hide.event && options.show.target && !target.closest(options.show.target[0]).length) {
28303				this.hide(event);
28304			}
28305		}
28306
28307		// Add hover class
28308		tooltip.toggleClass(CLASS_HOVER, state);
28309	});
28310
28311	// Define events which reset the 'inactive' event handler
28312	delegate('['+ATTR_ID+']', INACTIVE_EVENTS, inactiveMethod);
28313});
28314;// Initialization method
28315function init(elem, id, opts) {
28316	var obj, posOptions, attr, config, title,
28317
28318	// Setup element references
28319	docBody = $(document.body),
28320
28321	// Use document body instead of document element if needed
28322	newTarget = elem[0] === document ? docBody : elem,
28323
28324	// Grab metadata from element if plugin is present
28325	metadata = elem.metadata ? elem.metadata(opts.metadata) : NULL,
28326
28327	// If metadata type if HTML5, grab 'name' from the object instead, or use the regular data object otherwise
28328	metadata5 = opts.metadata.type === 'html5' && metadata ? metadata[opts.metadata.name] : NULL,
28329
28330	// Grab data from metadata.name (or data-qtipopts as fallback) using .data() method,
28331	html5 = elem.data(opts.metadata.name || 'qtipopts');
28332
28333	// If we don't get an object returned attempt to parse it manualyl without parseJSON
28334	/* eslint-disable no-empty */
28335	try { html5 = typeof html5 === 'string' ? $.parseJSON(html5) : html5; }
28336	catch(e) {}
28337	/* eslint-enable no-empty */
28338
28339	// Merge in and sanitize metadata
28340	config = $.extend(TRUE, {}, QTIP.defaults, opts,
28341		typeof html5 === 'object' ? sanitizeOptions(html5) : NULL,
28342		sanitizeOptions(metadata5 || metadata));
28343
28344	// Re-grab our positioning options now we've merged our metadata and set id to passed value
28345	posOptions = config.position;
28346	config.id = id;
28347
28348	// Setup missing content if none is detected
28349	if('boolean' === typeof config.content.text) {
28350		attr = elem.attr(config.content.attr);
28351
28352		// Grab from supplied attribute if available
28353		if(config.content.attr !== FALSE && attr) { config.content.text = attr; }
28354
28355		// No valid content was found, abort render
28356		else { return FALSE; }
28357	}
28358
28359	// Setup target options
28360	if(!posOptions.container.length) { posOptions.container = docBody; }
28361	if(posOptions.target === FALSE) { posOptions.target = newTarget; }
28362	if(config.show.target === FALSE) { config.show.target = newTarget; }
28363	if(config.show.solo === TRUE) { config.show.solo = posOptions.container.closest('body'); }
28364	if(config.hide.target === FALSE) { config.hide.target = newTarget; }
28365	if(config.position.viewport === TRUE) { config.position.viewport = posOptions.container; }
28366
28367	// Ensure we only use a single container
28368	posOptions.container = posOptions.container.eq(0);
28369
28370	// Convert position corner values into x and y strings
28371	posOptions.at = new CORNER(posOptions.at, TRUE);
28372	posOptions.my = new CORNER(posOptions.my);
28373
28374	// Destroy previous tooltip if overwrite is enabled, or skip element if not
28375	if(elem.data(NAMESPACE)) {
28376		if(config.overwrite) {
28377			elem.qtip('destroy', true);
28378		}
28379		else if(config.overwrite === FALSE) {
28380			return FALSE;
28381		}
28382	}
28383
28384	// Add has-qtip attribute
28385	elem.attr(ATTR_HAS, id);
28386
28387	// Remove title attribute and store it if present
28388	if(config.suppress && (title = elem.attr('title'))) {
28389		// Final attr call fixes event delegatio
vendor: 4,438 bytes, lines 28389-28545
28389m and IE default tooltip showing problem
28390		elem.removeAttr('title').attr(oldtitle, title).attr('title', '');
28391	}
28392
28393	// Initialize the tooltip and add API reference
28394	obj = new QTip(elem, config, id, !!attr);
28395	elem.data(NAMESPACE, obj);
28396
28397	return obj;
28398}
28399
28400// jQuery $.fn extension method
28401QTIP = $.fn.qtip = function(options, notation, newValue)
28402{
28403	var command = ('' + options).toLowerCase(), // Parse command
28404		returned = NULL,
28405		args = $.makeArray(arguments).slice(1),
28406		event = args[args.length - 1],
28407		opts = this[0] ? $.data(this[0], NAMESPACE) : NULL;
28408
28409	// Check for API request
28410	if(!arguments.length && opts || command === 'api') {
28411		return opts;
28412	}
28413
28414	// Execute API command if present
28415	else if('string' === typeof options) {
28416		this.each(function() {
28417			var api = $.data(this, NAMESPACE);
28418			if(!api) { return TRUE; }
28419
28420			// Cache the event if possible
28421			if(event && event.timeStamp) { api.cache.event = event; }
28422
28423			// Check for specific API commands
28424			if(notation && (command === 'option' || command === 'options')) {
28425				if(newValue !== undefined || $.isPlainObject(notation)) {
28426					api.set(notation, newValue);
28427				}
28428				else {
28429					returned = api.get(notation);
28430					return FALSE;
28431				}
28432			}
28433
28434			// Execute API command
28435			else if(api[command]) {
28436				api[command].apply(api, args);
28437			}
28438		});
28439
28440		return returned !== NULL ? returned : this;
28441	}
28442
28443	// No API commands. validate provided options and setup qTips
28444	else if('object' === typeof options || !arguments.length) {
28445		// Sanitize options first
28446		opts = sanitizeOptions($.extend(TRUE, {}, options));
28447
28448		return this.each(function(i) {
28449			var api, id;
28450
28451			// Find next available ID, or use custom ID if provided
28452			id = $.isArray(opts.id) ? opts.id[i] : opts.id;
28453			id = !id || id === FALSE || id.length < 1 || QTIP.api[id] ? QTIP.nextid++ : id;
28454
28455			// Initialize the qTip and re-grab newly sanitized options
28456			api = init($(this), id, opts);
28457			if(api === FALSE) { return TRUE; }
28458			else { QTIP.api[id] = api; }
28459
28460			// Initialize plugins
28461			$.each(PLUGINS, function() {
28462				if(this.initialize === 'initialize') { this(api); }
28463			});
28464
28465			// Assign initial pre-render events
28466			api._assignInitialEvents(event);
28467		});
28468	}
28469};
28470
28471// Expose class
28472$.qtip = QTip;
28473
28474// Populated in render method
28475QTIP.api = {};
28476;$.each({
28477	/* Allow other plugins to successfully retrieve the title of an element with a qTip applied */
28478	attr: function(attr, val) {
28479		if(this.length) {
28480			var self = this[0],
28481				title = 'title',
28482				api = $.data(self, 'qtip');
28483
28484			if(attr === title && api && api.options && 'object' === typeof api && 'object' === typeof api.options && api.options.suppress) {
28485				if(arguments.length < 2) {
28486					return $.attr(self, oldtitle);
28487				}
28488
28489				// If qTip is rendered and title was originally used as content, update it
28490				if(api && api.options.content.attr === title && api.cache.attr) {
28491					api.set('content.text', val);
28492				}
28493
28494				// Use the regular attr method to set, then cache the result
28495				return this.attr(oldtitle, val);
28496			}
28497		}
28498
28499		return $.fn['attr'+replaceSuffix].apply(this, arguments);
28500	},
28501
28502	/* Allow clone to correctly retrieve cached title attributes */
28503	clone: function(keepData) {
28504		// Clone our element using the real clone method
28505		var elems = $.fn['clone'+replaceSuffix].apply(this, arguments);
28506
28507		// Grab all elements with an oldtitle set, and change it to regular title attribute, if keepData is false
28508		if(!keepData) {
28509			elems.filter('['+oldtitle+']').attr('title', function() {
28510				return $.attr(this, oldtitle);
28511			})
28512			.removeAttr(oldtitle);
28513		}
28514
28515		return elems;
28516	}
28517}, function(name, func) {
28518	if(!func || $.fn[name+replaceSuffix]) { return TRUE; }
28519
28520	var old = $.fn[name+replaceSuffix] = $.fn[name];
28521	$.fn[name] = function() {
28522		return func.apply(this, arguments) || old.apply(this, arguments);
28523	};
28524});
28525
28526/* Fire off 'removeqtip' handler in $.cleanData if jQuery UI not present (it already does similar).
28527 * This snippet is taken directly from jQuery UI source code found here:
28528 *     http://code.jquery.com/ui/jquery-ui-git.js
28529 */
28530if(!$.ui) {
28531	$['cleanData'+replaceSuffix] = $.cleanData;
28532	$.cleanData = function( elems ) {
28533		for(var i = 0, elem; (elem = $( elems[i] )).length; i++) {
28534			if(elem.attr(ATTR_HAS)) {
28535				/* eslint-disable no-empty */
28536				try { elem.triggerHandler('removeqtip'); }
28537				catch( e ) {}
28538				/* eslint-enable no-empty */
28539			}
28540		}
28541		$['cleanData'+replaceSuffix].apply(this, arguments);
28542	};
28543}
28544;// qTip version
28545QTIP.version = '3.0.2
vendor: 45,032 bytes, lines 28545-30099
28545';
28546
28547// Base ID for all qTips
28548QTIP.nextid = 0;
28549
28550// Inactive events array
28551QTIP.inactiveEvents = INACTIVE_EVENTS;
28552
28553// Base z-index for all qTips
28554QTIP.zindex = 15000;
28555
28556// Define configuration defaults
28557QTIP.defaults = {
28558	prerender: FALSE,
28559	id: FALSE,
28560	overwrite: TRUE,
28561	suppress: TRUE,
28562	content: {
28563		text: TRUE,
28564		attr: 'title',
28565		title: FALSE,
28566		button: FALSE
28567	},
28568	position: {
28569		my: 'top left',
28570		at: 'bottom right',
28571		target: FALSE,
28572		container: FALSE,
28573		viewport: FALSE,
28574		adjust: {
28575			x: 0, y: 0,
28576			mouse: TRUE,
28577			scroll: TRUE,
28578			resize: TRUE,
28579			method: 'flipinvert flipinvert'
28580		},
28581		effect: function(api, pos) {
28582			$(this).animate(pos, {
28583				duration: 200,
28584				queue: FALSE
28585			});
28586		}
28587	},
28588	show: {
28589		target: FALSE,
28590		event: 'mouseenter',
28591		effect: TRUE,
28592		delay: 90,
28593		solo: FALSE,
28594		ready: FALSE,
28595		autofocus: FALSE
28596	},
28597	hide: {
28598		target: FALSE,
28599		event: 'mouseleave',
28600		effect: TRUE,
28601		delay: 0,
28602		fixed: FALSE,
28603		inactive: FALSE,
28604		leave: 'window',
28605		distance: FALSE
28606	},
28607	style: {
28608		classes: '',
28609		widget: FALSE,
28610		width: FALSE,
28611		height: FALSE,
28612		def: TRUE
28613	},
28614	events: {
28615		render: NULL,
28616		move: NULL,
28617		show: NULL,
28618		hide: NULL,
28619		toggle: NULL,
28620		visible: NULL,
28621		hidden: NULL,
28622		focus: NULL,
28623		blur: NULL
28624	}
28625};
28626;var TIP,
28627createVML,
28628SCALE,
28629PIXEL_RATIO,
28630BACKING_STORE_RATIO,
28631
28632// Common CSS strings
28633MARGIN = 'margin',
28634BORDER = 'border',
28635COLOR = 'color',
28636BG_COLOR = 'background-color',
28637TRANSPARENT = 'transparent',
28638IMPORTANT = ' !important',
28639
28640// Check if the browser supports <canvas/> elements
28641HASCANVAS = !!document.createElement('canvas').getContext,
28642
28643// Invalid colour values used in parseColours()
28644INVALID = /rgba?\(0, 0, 0(, 0)?\)|transparent|#123456/i;
28645
28646// Camel-case method, taken from jQuery source
28647// http://code.jquery.com/jquery-1.8.0.js
28648function camel(s) { return s.charAt(0).toUpperCase() + s.slice(1); }
28649
28650/*
28651 * Modified from Modernizr's testPropsAll()
28652 * http://modernizr.com/downloads/modernizr-latest.js
28653 */
28654var cssProps = {}, cssPrefixes = ['Webkit', 'O', 'Moz', 'ms'];
28655function vendorCss(elem, prop) {
28656	var ucProp = prop.charAt(0).toUpperCase() + prop.slice(1),
28657		props = (prop + ' ' + cssPrefixes.join(ucProp + ' ') + ucProp).split(' '),
28658		cur, val, i = 0;
28659
28660	// If the property has already been mapped...
28661	if(cssProps[prop]) { return elem.css(cssProps[prop]); }
28662
28663	while(cur = props[i++]) {
28664		if((val = elem.css(cur)) !== undefined) {
28665			cssProps[prop] = cur;
28666			return val;
28667		}
28668	}
28669}
28670
28671// Parse a given elements CSS property into an int
28672function intCss(elem, prop) {
28673	return Math.ceil(parseFloat(vendorCss(elem, prop)));
28674}
28675
28676
28677// VML creation (for IE only)
28678if(!HASCANVAS) {
28679	createVML = function(tag, props, style) {
28680		return '<qtipvml:'+tag+' xmlns="urn:schemas-microsoft.com:vml" class="qtip-vml" '+(props||'')+
28681			' style="behavior: url(#default#VML); '+(style||'')+ '" />';
28682	};
28683}
28684
28685// Canvas only definitions
28686else {
28687	PIXEL_RATIO = window.devicePixelRatio || 1;
28688	BACKING_STORE_RATIO = (function() {
28689		var context = document.createElement('canvas').getContext('2d');
28690		return context.backingStorePixelRatio || context.webkitBackingStorePixelRatio || context.mozBackingStorePixelRatio ||
28691				context.msBackingStorePixelRatio || context.oBackingStorePixelRatio || 1;
28692	})();
28693	SCALE = PIXEL_RATIO / BACKING_STORE_RATIO;
28694}
28695
28696
28697function Tip(qtip, options) {
28698	this._ns = 'tip';
28699	this.options = options;
28700	this.offset = options.offset;
28701	this.size = [ options.width, options.height ];
28702
28703	// Initialize
28704	this.qtip = qtip;
28705	this.init(qtip);
28706}
28707
28708$.extend(Tip.prototype, {
28709	init: function(qtip) {
28710		var context, tip;
28711
28712		// Create tip element and prepend to the tooltip
28713		tip = this.element = qtip.elements.tip = $('<div />', { 'class': NAMESPACE+'-tip' }).prependTo(qtip.tooltip);
28714
28715		// Create tip drawing element(s)
28716		if(HASCANVAS) {
28717			// save() as soon as we create the canvas element so FF2 doesn't bork on our first restore()!
28718			context = $('<canvas />').appendTo(this.element)[0].getContext('2d');
28719
28720			// Setup constant parameters
28721			context.lineJoin = 'miter';
28722			context.miterLimit = 100000;
28723			context.save();
28724		}
28725		else {
28726			context = createVML('shape', 'coordorigin="0,0"', 'position:absolute;');
28727			this.element.html(context + context);
28728
28729			// Prevent mousing down on the tip since it causes problems with .live() handling in IE due to VML
28730			qtip._bind( $('*', tip).add(tip), ['click', 'mousedown'], function(event) { event.stopPropagation(); }, this._ns);
28731		}
28732
28733		// Bind update events
28734		qtip._bind(qtip.tooltip, 'tooltipmove', this.reposition, this._ns, this);
28735
28736		// Create it
28737		this.create();
28738	},
28739
28740	_swapDimensions: function() {
28741		this.size[0] = this.options.height;
28742		this.size[1] = this.options.width;
28743	},
28744	_resetDimensions: function() {
28745		this.size[0] = this.options.width;
28746		this.size[1] = this.options.height;
28747	},
28748
28749	_useTitle: function(corner) {
28750		var titlebar = this.qtip.elements.titlebar;
28751		return titlebar && (
28752			corner.y === TOP || corner.y === CENTER && this.element.position().top + this.size[1] / 2 + this.options.offset < titlebar.outerHeight(TRUE)
28753		);
28754	},
28755
28756	_parseCorner: function(corner) {
28757		var my = this.qtip.options.position.my;
28758
28759		// Detect corner and mimic properties
28760		if(corner === FALSE || my === FALSE) {
28761			corner = FALSE;
28762		}
28763		else if(corner === TRUE) {
28764			corner = new CORNER( my.string() );
28765		}
28766		else if(!corner.string) {
28767			corner = new CORNER(corner);
28768			corner.fixed = TRUE;
28769		}
28770
28771		return corner;
28772	},
28773
28774	_parseWidth: function(corner, side, use) {
28775		var elements = this.qtip.elements,
28776			prop = BORDER + camel(side) + 'Width';
28777
28778		return (use ? intCss(use, prop) : 
28779			intCss(elements.content, prop) ||
28780			intCss(this._useTitle(corner) && elements.titlebar || elements.content, prop) ||
28781			intCss(elements.tooltip, prop)
28782		) || 0;
28783	},
28784
28785	_parseRadius: function(corner) {
28786		var elements = this.qtip.elements,
28787			prop = BORDER + camel(corner.y) + camel(corner.x) + 'Radius';
28788
28789		return BROWSER.ie < 9 ? 0 :
28790			intCss(this._useTitle(corner) && elements.titlebar || elements.content, prop) ||
28791			intCss(elements.tooltip, prop) || 0;
28792	},
28793
28794	_invalidColour: function(elem, prop, compare) {
28795		var val = elem.css(prop);
28796		return !val || compare && val === elem.css(compare) || INVALID.test(val) ? FALSE : val;
28797	},
28798
28799	_parseColours: function(corner) {
28800		var elements = this.qtip.elements,
28801			tip = this.element.css('cssText', ''),
28802			borderSide = BORDER + camel(corner[ corner.precedance ]) + camel(COLOR),
28803			colorElem = this._useTitle(corner) && elements.titlebar || elements.content,
28804			css = this._invalidColour, color = [];
28805
28806		// Attempt to detect the background colour from various elements, left-to-right precedance
28807		color[0] = css(tip, BG_COLOR) || css(colorElem, BG_COLOR) || css(elements.content, BG_COLOR) ||
28808			css(elements.tooltip, BG_COLOR) || tip.css(BG_COLOR);
28809
28810		// Attempt to detect the correct border side colour from various elements, left-to-right precedance
28811		color[1] = css(tip, borderSide, COLOR) || css(colorElem, borderSide, COLOR) ||
28812			css(elements.content, borderSide, COLOR) || css(elements.tooltip, borderSide, COLOR) || elements.tooltip.css(borderSide);
28813
28814		// Reset background and border colours
28815		$('*', tip).add(tip).css('cssText', BG_COLOR+':'+TRANSPARENT+IMPORTANT+';'+BORDER+':0'+IMPORTANT+';');
28816
28817		return color;
28818	},
28819
28820	_calculateSize: function(corner) {
28821		var y = corner.precedance === Y,
28822			width = this.options.width,
28823			height = this.options.height,
28824			isCenter = corner.abbrev() === 'c',
28825			base = (y ? width: height) * (isCenter ? 0.5 : 1),
28826			pow = Math.pow,
28827			round = Math.round,
28828			bigHyp, ratio, result,
28829
28830		smallHyp = Math.sqrt( pow(base, 2) + pow(height, 2) ),
28831		hyp = [
28832			this.border / base * smallHyp,
28833			this.border / height * smallHyp
28834		];
28835
28836		hyp[2] = Math.sqrt( pow(hyp[0], 2) - pow(this.border, 2) );
28837		hyp[3] = Math.sqrt( pow(hyp[1], 2) - pow(this.border, 2) );
28838
28839		bigHyp = smallHyp + hyp[2] + hyp[3] + (isCenter ? 0 : hyp[0]);
28840		ratio = bigHyp / smallHyp;
28841
28842		result = [ round(ratio * width), round(ratio * height) ];
28843		return y ? result : result.reverse();
28844	},
28845
28846	// Tip coordinates calculator
28847	_calculateTip: function(corner, size, scale) {
28848		scale = scale || 1;
28849		size = size || this.size;
28850
28851		var width = size[0] * scale,
28852			height = size[1] * scale,
28853			width2 = Math.ceil(width / 2), height2 = Math.ceil(height / 2),
28854
28855		// Define tip coordinates in terms of height and width values
28856		tips = {
28857			br:	[0,0,		width,height,	width,0],
28858			bl:	[0,0,		width,0,		0,height],
28859			tr:	[0,height,	width,0,		width,height],
28860			tl:	[0,0,		0,height,		width,height],
28861			tc:	[0,height,	width2,0,		width,height],
28862			bc:	[0,0,		width,0,		width2,height],
28863			rc:	[0,0,		width,height2,	0,height],
28864			lc:	[width,0,	width,height,	0,height2]
28865		};
28866
28867		// Set common side shapes
28868		tips.lt = tips.br; tips.rt = tips.bl;
28869		tips.lb = tips.tr; tips.rb = tips.tl;
28870
28871		return tips[ corner.abbrev() ];
28872	},
28873
28874	// Tip coordinates drawer (canvas)
28875	_drawCoords: function(context, coords) {
28876		context.beginPath();
28877		context.moveTo(coords[0], coords[1]);
28878		context.lineTo(coords[2], coords[3]);
28879		context.lineTo(coords[4], coords[5]);
28880		context.closePath();
28881	},
28882
28883	create: function() {
28884		// Determine tip corner
28885		var c = this.corner = (HASCANVAS || BROWSER.ie) && this._parseCorner(this.options.corner);
28886
28887		// If we have a tip corner...
28888		this.enabled = !!this.corner && this.corner.abbrev() !== 'c';
28889		if(this.enabled) {
28890			// Cache it
28891			this.qtip.cache.corner = c.clone();
28892
28893			// Create it
28894			this.update();
28895		}
28896
28897		// Toggle tip element
28898		this.element.toggle(this.enabled);
28899
28900		return this.corner;
28901	},
28902
28903	update: function(corner, position) {
28904		if(!this.enabled) { return this; }
28905
28906		var elements = this.qtip.elements,
28907			tip = this.element,
28908			inner = tip.children(),
28909			options = this.options,
28910			curSize = this.size,
28911			mimic = options.mimic,
28912			round = Math.round,
28913			color, precedance, context,
28914			coords, bigCoords, translate, newSize, border;
28915
28916		// Re-determine tip if not already set
28917		if(!corner) { corner = this.qtip.cache.corner || this.corner; }
28918
28919		// Use corner property if we detect an invalid mimic value
28920		if(mimic === FALSE) { mimic = corner; }
28921
28922		// Otherwise inherit mimic properties from the corner object as necessary
28923		else {
28924			mimic = new CORNER(mimic);
28925			mimic.precedance = corner.precedance;
28926
28927			if(mimic.x === 'inherit') { mimic.x = corner.x; }
28928			else if(mimic.y === 'inherit') { mimic.y = corner.y; }
28929			else if(mimic.x === mimic.y) {
28930				mimic[ corner.precedance ] = corner[ corner.precedance ];
28931			}
28932		}
28933		precedance = mimic.precedance;
28934
28935		// Ensure the tip width.height are relative to the tip position
28936		if(corner.precedance === X) { this._swapDimensions(); }
28937		else { this._resetDimensions(); }
28938
28939		// Update our colours
28940		color = this.color = this._parseColours(corner);
28941
28942		// Detect border width, taking into account colours
28943		if(color[1] !== TRANSPARENT) {
28944			// Grab border width
28945			border = this.border = this._parseWidth(corner, corner[corner.precedance]);
28946
28947			// If border width isn't zero, use border color as fill if it's not invalid (1.0 style tips)
28948			if(options.border && border < 1 && !INVALID.test(color[1])) { color[0] = color[1]; }
28949
28950			// Set border width (use detected border width if options.border is true)
28951			this.border = border = options.border !== TRUE ? options.border : border;
28952		}
28953
28954		// Border colour was invalid, set border to zero
28955		else { this.border = border = 0; }
28956
28957		// Determine tip size
28958		newSize = this.size = this._calculateSize(corner);
28959		tip.css({
28960			width: newSize[0],
28961			height: newSize[1],
28962			lineHeight: newSize[1]+'px'
28963		});
28964
28965		// Calculate tip translation
28966		if(corner.precedance === Y) {
28967			translate = [
28968				round(mimic.x === LEFT ? border : mimic.x === RIGHT ? newSize[0] - curSize[0] - border : (newSize[0] - curSize[0]) / 2),
28969				round(mimic.y === TOP ? newSize[1] - curSize[1] : 0)
28970			];
28971		}
28972		else {
28973			translate = [
28974				round(mimic.x === LEFT ? newSize[0] - curSize[0] : 0),
28975				round(mimic.y === TOP ? border : mimic.y === BOTTOM ? newSize[1] - curSize[1] - border : (newSize[1] - curSize[1]) / 2)
28976			];
28977		}
28978
28979		// Canvas drawing implementation
28980		if(HASCANVAS) {
28981			// Grab canvas context and clear/save it
28982			context = inner[0].getContext('2d');
28983			context.restore(); context.save();
28984			context.clearRect(0,0,6000,6000);
28985
28986			// Calculate coordinates
28987			coords = this._calculateTip(mimic, curSize, SCALE);
28988			bigCoords = this._calculateTip(mimic, this.size, SCALE);
28989
28990			// Set the canvas size using calculated size
28991			inner.attr(WIDTH, newSize[0] * SCALE).attr(HEIGHT, newSize[1] * SCALE);
28992			inner.css(WIDTH, newSize[0]).css(HEIGHT, newSize[1]);
28993
28994			// Draw the outer-stroke tip
28995			this._drawCoords(context, bigCoords);
28996			context.fillStyle = color[1];
28997			context.fill();
28998
28999			// Draw the actual tip
29000			context.translate(translate[0] * SCALE, translate[1] * SCALE);
29001			this._drawCoords(context, coords);
29002			context.fillStyle = color[0];
29003			context.fill();
29004		}
29005
29006		// VML (IE Proprietary implementation)
29007		else {
29008			// Calculate coordinates
29009			coords = this._calculateTip(mimic);
29010
29011			// Setup coordinates string
29012			coords = 'm' + coords[0] + ',' + coords[1] + ' l' + coords[2] +
29013				',' + coords[3] + ' ' + coords[4] + ',' + coords[5] + ' xe';
29014
29015			// Setup VML-specific offset for pixel-perfection
29016			translate[2] = border && /^(r|b)/i.test(corner.string()) ?
29017				BROWSER.ie === 8 ? 2 : 1 : 0;
29018
29019			// Set initial CSS
29020			inner.css({
29021				coordsize: newSize[0]+border + ' ' + newSize[1]+border,
29022				antialias: ''+(mimic.string().indexOf(CENTER) > -1),
29023				left: translate[0] - translate[2] * Number(precedance === X),
29024				top: translate[1] - translate[2] * Number(precedance === Y),
29025				width: newSize[0] + border,
29026				height: newSize[1] + border
29027			})
29028			.each(function(i) {
29029				var $this = $(this);
29030
29031				// Set shape specific attributes
29032				$this[ $this.prop ? 'prop' : 'attr' ]({
29033					coordsize: newSize[0]+border + ' ' + newSize[1]+border,
29034					path: coords,
29035					fillcolor: color[0],
29036					filled: !!i,
29037					stroked: !i
29038				})
29039				.toggle(!!(border || i));
29040
29041				// Check if border is enabled and add stroke element
29042				!i && $this.html( createVML(
29043					'stroke', 'weight="'+border*2+'px" color="'+color[1]+'" miterlimit="1000" joinstyle="miter"'
29044				) );
29045			});
29046		}
29047
29048		// Opera bug #357 - Incorrect tip position
29049		// https://github.com/Craga89/qTip2/issues/367
29050		window.opera && setTimeout(function() {
29051			elements.tip.css({
29052				display: 'inline-block',
29053				visibility: 'visible'
29054			});
29055		}, 1);
29056
29057		// Position if needed
29058		if(position !== FALSE) { this.calculate(corner, newSize); }
29059	},
29060
29061	calculate: function(corner, size) {
29062		if(!this.enabled) { return FALSE; }
29063
29064		var self = this,
29065			elements = this.qtip.elements,
29066			tip = this.element,
29067			userOffset = this.options.offset,
29068			position = {},
29069			precedance, corners;
29070
29071		// Inherit corner if not provided
29072		corner = corner || this.corner;
29073		precedance = corner.precedance;
29074
29075		// Determine which tip dimension to use for adjustment
29076		size = size || this._calculateSize(corner);
29077
29078		// Setup corners and offset array
29079		corners = [ corner.x, corner.y ];
29080		if(precedance === X) { corners.reverse(); }
29081
29082		// Calculate tip position
29083		$.each(corners, function(i, side) {
29084			var b, bc, br;
29085
29086			if(side === CENTER) {
29087				b = precedance === Y ? LEFT : TOP;
29088				position[ b ] = '50%';
29089				position[MARGIN+'-' + b] = -Math.round(size[ precedance === Y ? 0 : 1 ] / 2) + userOffset;
29090			}
29091			else {
29092				b = self._parseWidth(corner, side, elements.tooltip);
29093				bc = self._parseWidth(corner, side, elements.content);
29094				br = self._parseRadius(corner);
29095
29096				position[ side ] = Math.max(-self.border, i ? bc : userOffset + (br > b ? br : -b));
29097			}
29098		});
29099
29100		// Adjust for tip size
29101		position[ corner[precedance] ] -= size[ precedance === X ? 0 : 1 ];
29102
29103		// Set and return new position
29104		tip.css({ margin: '', top: '', bottom: '', left: '', right: '' }).css(position);
29105		return position;
29106	},
29107
29108	reposition: function(event, api, pos) {
29109		if(!this.enabled) { return; }
29110
29111		var cache = api.cache,
29112			newCorner = this.corner.clone(),
29113			adjust = pos.adjusted,
29114			method = api.options.position.adjust.method.split(' '),
29115			horizontal = method[0],
29116			vertical = method[1] || method[0],
29117			shift = { left: FALSE, top: FALSE, x: 0, y: 0 },
29118			offset, css = {}, props;
29119
29120		function shiftflip(direction, precedance, popposite, side, opposite) {
29121			// Horizontal - Shift or flip method
29122			if(direction === SHIFT && newCorner.precedance === precedance && adjust[side] && newCorner[popposite] !== CENTER) {
29123				newCorner.precedance = newCorner.precedance === X ? Y : X;
29124			}
29125			else if(direction !== SHIFT && adjust[side]){
29126				newCorner[precedance] = newCorner[precedance] === CENTER ?
29127					adjust[side] > 0 ? side : opposite :
29128					newCorner[precedance] === side ? opposite : side;
29129			}
29130		}
29131
29132		function shiftonly(xy, side, opposite) {
29133			if(newCorner[xy] === CENTER) {
29134				css[MARGIN+'-'+side] = shift[xy] = offset[MARGIN+'-'+side] - adjust[side];
29135			}
29136			else {
29137				props = offset[opposite] !== undefined ?
29138					[ adjust[side], -offset[side] ] : [ -adjust[side], offset[side] ];
29139
29140				if( (shift[xy] = Math.max(props[0], props[1])) > props[0] ) {
29141					pos[side] -= adjust[side];
29142					shift[side] = FALSE;
29143				}
29144
29145				css[ offset[opposite] !== undefined ? opposite : side ] = shift[xy];
29146			}
29147		}
29148
29149		// If our tip position isn't fixed e.g. doesn't adjust with viewport...
29150		if(this.corner.fixed !== TRUE) {
29151			// Perform shift/flip adjustments
29152			shiftflip(horizontal, X, Y, LEFT, RIGHT);
29153			shiftflip(vertical, Y, X, TOP, BOTTOM);
29154
29155			// Update and redraw the tip if needed (check cached details of last drawn tip)
29156			if(newCorner.string() !== cache.corner.string() || cache.cornerTop !== adjust.top || cache.cornerLeft !== adjust.left) {
29157				this.update(newCorner, FALSE);
29158			}
29159		}
29160
29161		// Setup tip offset properties
29162		offset = this.calculate(newCorner);
29163
29164		// Readjust offset object to make it left/top
29165		if(offset.right !== undefined) { offset.left = -offset.right; }
29166		if(offset.bottom !== undefined) { offset.top = -offset.bottom; }
29167		offset.user = this.offset;
29168
29169		// Perform shift adjustments
29170		shift.left = horizontal === SHIFT && !!adjust.left;
29171		if(shift.left) {
29172			shiftonly(X, LEFT, RIGHT);
29173		}
29174		shift.top = vertical === SHIFT && !!adjust.top;
29175		if(shift.top) {
29176			shiftonly(Y, TOP, BOTTOM);
29177		}
29178
29179		/*
29180		* If the tip is adjusted in both dimensions, or in a
29181		* direction that would cause it to be anywhere but the
29182		* outer border, hide it!
29183		*/
29184		this.element.css(css).toggle(
29185			!(shift.x && shift.y || newCorner.x === CENTER && shift.y || newCorner.y === CENTER && shift.x)
29186		);
29187
29188		// Adjust position to accomodate tip dimensions
29189		pos.left -= offset.left.charAt ? offset.user :
29190			horizontal !== SHIFT || shift.top || !shift.left && !shift.top ? offset.left + this.border : 0;
29191		pos.top -= offset.top.charAt ? offset.user :
29192			vertical !== SHIFT || shift.left || !shift.left && !shift.top ? offset.top + this.border : 0;
29193
29194		// Cache details
29195		cache.cornerLeft = adjust.left; cache.cornerTop = adjust.top;
29196		cache.corner = newCorner.clone();
29197	},
29198
29199	destroy: function() {
29200		// Unbind events
29201		this.qtip._unbind(this.qtip.tooltip, this._ns);
29202
29203		// Remove the tip element(s)
29204		if(this.qtip.elements.tip) {
29205			this.qtip.elements.tip.find('*')
29206				.remove().end().remove();
29207		}
29208	}
29209});
29210
29211TIP = PLUGINS.tip = function(api) {
29212	return new Tip(api, api.options.style.tip);
29213};
29214
29215// Initialize tip on render
29216TIP.initialize = 'render';
29217
29218// Setup plugin sanitization options
29219TIP.sanitize = function(options) {
29220	if(options.style && 'tip' in options.style) {
29221		var opts = options.style.tip;
29222		if(typeof opts !== 'object') { opts = options.style.tip = { corner: opts }; }
29223		if(!(/string|boolean/i).test(typeof opts.corner)) { opts.corner = TRUE; }
29224	}
29225};
29226
29227// Add new option checks for the plugin
29228CHECKS.tip = {
29229	'^position.my|style.tip.(corner|mimic|border)$': function() {
29230		// Make sure a tip can be drawn
29231		this.create();
29232
29233		// Reposition the tooltip
29234		this.qtip.reposition();
29235	},
29236	'^style.tip.(height|width)$': function(obj) {
29237		// Re-set dimensions and redraw the tip
29238		this.size = [ obj.width, obj.height ];
29239		this.update();
29240
29241		// Reposition the tooltip
29242		this.qtip.reposition();
29243	},
29244	'^content.title|style.(classes|widget)$': function() {
29245		this.update();
29246	}
29247};
29248
29249// Extend original qTip defaults
29250$.extend(TRUE, QTIP.defaults, {
29251	style: {
29252		tip: {
29253			corner: TRUE,
29254			mimic: FALSE,
29255			width: 6,
29256			height: 6,
29257			border: TRUE,
29258			offset: 0
29259		}
29260	}
29261});
29262;var MODAL, OVERLAY,
29263	MODALCLASS = 'qtip-modal',
29264	MODALSELECTOR = '.'+MODALCLASS;
29265
29266OVERLAY = function()
29267{
29268	var self = this,
29269		focusableElems = {},
29270		current,
29271		prevState,
29272		elem;
29273
29274	// Modified code from jQuery UI 1.10.0 source
29275	// http://code.jquery.com/ui/1.10.0/jquery-ui.js
29276	function focusable(element) {
29277		// Use the defined focusable checker when possible
29278		if($.expr[':'].focusable) { return $.expr[':'].focusable; }
29279
29280		var isTabIndexNotNaN = !isNaN($.attr(element, 'tabindex')),
29281			nodeName = element.nodeName && element.nodeName.toLowerCase(),
29282			map, mapName, img;
29283
29284		if('area' === nodeName) {
29285			map = element.parentNode;
29286			mapName = map.name;
29287			if(!element.href || !mapName || map.nodeName.toLowerCase() !== 'map') {
29288				return false;
29289			}
29290			img = $('img[usemap=#' + mapName + ']')[0];
29291			return !!img && img.is(':visible');
29292		}
29293
29294		return /input|select|textarea|button|object/.test( nodeName ) ?
29295			!element.disabled :
29296			'a' === nodeName ?
29297				element.href || isTabIndexNotNaN :
29298				isTabIndexNotNaN
29299		;
29300	}
29301
29302	// Focus inputs using cached focusable elements (see update())
29303	function focusInputs(blurElems) {
29304		// Blurring body element in IE causes window.open windows to unfocus!
29305		if(focusableElems.length < 1 && blurElems.length) { blurElems.not('body').blur(); }
29306
29307		// Focus the inputs
29308		else { focusableElems.first().focus(); }
29309	}
29310
29311	// Steal focus from elements outside tooltip
29312	function stealFocus(event) {
29313		if(!elem.is(':visible')) { return; }
29314
29315		var target = $(event.target),
29316			tooltip = current.tooltip,
29317			container = target.closest(SELECTOR),
29318			targetOnTop;
29319
29320		// Determine if input container target is above this
29321		targetOnTop = container.length < 1 ? FALSE :
29322			parseInt(container[0].style.zIndex, 10) > parseInt(tooltip[0].style.zIndex, 10);
29323
29324		// If we're showing a modal, but focus has landed on an input below
29325		// this modal, divert focus to the first visible input in this modal
29326		// or if we can't find one... the tooltip itself
29327		if(!targetOnTop && target.closest(SELECTOR)[0] !== tooltip[0]) {
29328			focusInputs(target);
29329		}
29330	}
29331
29332	$.extend(self, {
29333		init: function() {
29334			// Create document overlay
29335			elem = self.elem = $('<div />', {
29336				id: 'qtip-overlay',
29337				html: '<div></div>',
29338				mousedown: function() { return FALSE; }
29339			})
29340			.hide();
29341
29342			// Make sure we can't focus anything outside the tooltip
29343			$(document.body).bind('focusin'+MODALSELECTOR, stealFocus);
29344
29345			// Apply keyboard "Escape key" close handler
29346			$(document).bind('keydown'+MODALSELECTOR, function(event) {
29347				if(current && current.options.show.modal.escape && event.keyCode === 27) {
29348					current.hide(event);
29349				}
29350			});
29351
29352			// Apply click handler for blur option
29353			elem.bind('click'+MODALSELECTOR, function(event) {
29354				if(current && current.options.show.modal.blur) {
29355					current.hide(event);
29356				}
29357			});
29358
29359			return self;
29360		},
29361
29362		update: function(api) {
29363			// Update current API reference
29364			current = api;
29365
29366			// Update focusable elements if enabled
29367			if(api.options.show.modal.stealfocus !== FALSE) {
29368				focusableElems = api.tooltip.find('*').filter(function() {
29369					return focusable(this);
29370				});
29371			}
29372			else { focusableElems = []; }
29373		},
29374
29375		toggle: function(api, state, duration) {
29376			var tooltip = api.tooltip,
29377				options = api.options.show.modal,
29378				effect = options.effect,
29379				type = state ? 'show': 'hide',
29380				visible = elem.is(':visible'),
29381				visibleModals = $(MODALSELECTOR).filter(':visible:not(:animated)').not(tooltip);
29382
29383			// Set active tooltip API reference
29384			self.update(api);
29385
29386			// If the modal can steal the focus...
29387			// Blur the current item and focus anything in the modal we an
29388			if(state && options.stealfocus !== FALSE) {
29389				focusInputs( $(':focus') );
29390			}
29391
29392			// Toggle backdrop cursor style on show
29393			elem.toggleClass('blurs', options.blur);
29394
29395			// Append to body on show
29396			if(state) {
29397				elem.appendTo(document.body);
29398			}
29399
29400			// Prevent modal from conflicting with show.solo, and don't hide backdrop is other modals are visible
29401			if(elem.is(':animated') && visible === state && prevState !== FALSE || !state && visibleModals.length) {
29402				return self;
29403			}
29404
29405			// Stop all animations
29406			elem.stop(TRUE, FALSE);
29407
29408			// Use custom function if provided
29409			if($.isFunction(effect)) {
29410				effect.call(elem, state);
29411			}
29412
29413			// If no effect type is supplied, use a simple toggle
29414			else if(effect === FALSE) {
29415				elem[ type ]();
29416			}
29417
29418			// Use basic fade function
29419			else {
29420				elem.fadeTo( parseInt(duration, 10) || 90, state ? 1 : 0, function() {
29421					if(!state) { elem.hide(); }
29422				});
29423			}
29424
29425			// Reset position and detach from body on hide
29426			if(!state) {
29427				elem.queue(function(next) {
29428					elem.css({ left: '', top: '' });
29429					if(!$(MODALSELECTOR).length) { elem.detach(); }
29430					next();
29431				});
29432			}
29433
29434			// Cache the state
29435			prevState = state;
29436
29437			// If the tooltip is destroyed, set reference to null
29438			if(current.destroyed) { current = NULL; }
29439
29440			return self;
29441		}
29442	});
29443
29444	self.init();
29445};
29446OVERLAY = new OVERLAY();
29447
29448function Modal(api, options) {
29449	this.options = options;
29450	this._ns = '-modal';
29451
29452	this.qtip = api;
29453	this.init(api);
29454}
29455
29456$.extend(Modal.prototype, {
29457	init: function(qtip) {
29458		var tooltip = qtip.tooltip;
29459
29460		// If modal is disabled... return
29461		if(!this.options.on) { return this; }
29462
29463		// Set overlay reference
29464		qtip.elements.overlay = OVERLAY.elem;
29465
29466		// Add unique attribute so we can grab modal tooltips easily via a SELECTOR, and set z-index
29467		tooltip.addClass(MODALCLASS).css('z-index', QTIP.modal_zindex + $(MODALSELECTOR).length);
29468
29469		// Apply our show/hide/focus modal events
29470		qtip._bind(tooltip, ['tooltipshow', 'tooltiphide'], function(event, api, duration) {
29471			var oEvent = event.originalEvent;
29472
29473			// Make sure mouseout doesn't trigger a hide when showing the modal and mousing onto backdrop
29474			if(event.target === tooltip[0]) {
29475				if(oEvent && event.type === 'tooltiphide' && /mouse(leave|enter)/.test(oEvent.type) && $(oEvent.relatedTarget).closest(OVERLAY.elem[0]).length) {
29476					/* eslint-disable no-empty */
29477					try { event.preventDefault(); }
29478					catch(e) {}
29479					/* eslint-enable no-empty */
29480				}
29481				else if(!oEvent || oEvent && oEvent.type !== 'tooltipsolo') {
29482					this.toggle(event, event.type === 'tooltipshow', duration);
29483				}
29484			}
29485		}, this._ns, this);
29486
29487		// Adjust modal z-index on tooltip focus
29488		qtip._bind(tooltip, 'tooltipfocus', function(event, api) {
29489			// If focus was cancelled before it reached us, don't do anything
29490			if(event.isDefaultPrevented() || event.target !== tooltip[0]) { return; }
29491
29492			var qtips = $(MODALSELECTOR),
29493
29494			// Keep the modal's lower than other, regular qtips
29495			newIndex = QTIP.modal_zindex + qtips.length,
29496			curIndex = parseInt(tooltip[0].style.zIndex, 10);
29497
29498			// Set overlay z-index
29499			OVERLAY.elem[0].style.zIndex = newIndex - 1;
29500
29501			// Reduce modal z-index's and keep them properly ordered
29502			qtips.each(function() {
29503				if(this.style.zIndex > curIndex) {
29504					this.style.zIndex -= 1;
29505				}
29506			});
29507
29508			// Fire blur event for focused tooltip
29509			qtips.filter('.' + CLASS_FOCUS).qtip('blur', event.originalEvent);
29510
29511			// Set the new z-index
29512			tooltip.addClass(CLASS_FOCUS)[0].style.zIndex = newIndex;
29513
29514			// Set current
29515			OVERLAY.update(api);
29516
29517			// Prevent default handling
29518			/* eslint-disable no-empty */
29519			try { event.preventDefault(); }
29520			catch(e) {}
29521			/* eslint-enable no-empty */
29522		}, this._ns, this);
29523
29524		// Focus any other visible modals when this one hides
29525		qtip._bind(tooltip, 'tooltiphide', function(event) {
29526			if(event.target === tooltip[0]) {
29527				$(MODALSELECTOR).filter(':visible').not(tooltip).last().qtip('focus', event);
29528			}
29529		}, this._ns, this);
29530	},
29531
29532	toggle: function(event, state, duration) {
29533		// Make sure default event hasn't been prevented
29534		if(event && event.isDefaultPrevented()) { return this; }
29535
29536		// Toggle it
29537		OVERLAY.toggle(this.qtip, !!state, duration);
29538	},
29539
29540	destroy: function() {
29541		// Remove modal class
29542		this.qtip.tooltip.removeClass(MODALCLASS);
29543
29544		// Remove bound events
29545		this.qtip._unbind(this.qtip.tooltip, this._ns);
29546
29547		// Delete element reference
29548		OVERLAY.toggle(this.qtip, FALSE);
29549		delete this.qtip.elements.overlay;
29550	}
29551});
29552
29553
29554MODAL = PLUGINS.modal = function(api) {
29555	return new Modal(api, api.options.show.modal);
29556};
29557
29558// Setup sanitiztion rules
29559MODAL.sanitize = function(opts) {
29560	if(opts.show) {
29561		if(typeof opts.show.modal !== 'object') { opts.show.modal = { on: !!opts.show.modal }; }
29562		else if(typeof opts.show.modal.on === 'undefined') { opts.show.modal.on = TRUE; }
29563	}
29564};
29565
29566// Base z-index for all modal tooltips (use qTip core z-index as a base)
29567/* eslint-disable camelcase */
29568QTIP.modal_zindex = QTIP.zindex - 200;
29569/* eslint-enable camelcase */
29570
29571// Plugin needs to be initialized on render
29572MODAL.initialize = 'render';
29573
29574// Setup option set checks
29575CHECKS.modal = {
29576	'^show.modal.(on|blur)$': function() {
29577		// Initialise
29578		this.destroy();
29579		this.init();
29580
29581		// Show the modal if not visible already and tooltip is visible
29582		this.qtip.elems.overlay.toggle(
29583			this.qtip.tooltip[0].offsetWidth > 0
29584		);
29585	}
29586};
29587
29588// Extend original api defaults
29589$.extend(TRUE, QTIP.defaults, {
29590	show: {
29591		modal: {
29592			on: FALSE,
29593			effect: TRUE,
29594			blur: TRUE,
29595			stealfocus: TRUE,
29596			escape: TRUE
29597		}
29598	}
29599});
29600;PLUGINS.viewport = function(api, position, posOptions, targetWidth, targetHeight, elemWidth, elemHeight)
29601{
29602	var target = posOptions.target,
29603		tooltip = api.elements.tooltip,
29604		my = posOptions.my,
29605		at = posOptions.at,
29606		adjust = posOptions.adjust,
29607		method = adjust.method.split(' '),
29608		methodX = method[0],
29609		methodY = method[1] || method[0],
29610		viewport = posOptions.viewport,
29611		container = posOptions.container,
29612		adjusted = { left: 0, top: 0 },
29613		fixed, newMy, containerOffset, containerStatic,
29614		viewportWidth, viewportHeight, viewportScroll, viewportOffset;
29615
29616	// If viewport is not a jQuery element, or it's the window/document, or no adjustment method is used... return
29617	if(!viewport.jquery || target[0] === window || target[0] === document.body || adjust.method === 'none') {
29618		return adjusted;
29619	}
29620
29621	// Cach container details
29622	containerOffset = container.offset() || adjusted;
29623	containerStatic = container.css('position') === 'static';
29624
29625	// Cache our viewport details
29626	fixed = tooltip.css('position') === 'fixed';
29627	viewportWidth = viewport[0] === window ? viewport.width() : viewport.outerWidth(FALSE);
29628	viewportHeight = viewport[0] === window ? viewport.height() : viewport.outerHeight(FALSE);
29629	viewportScroll = { left: fixed ? 0 : viewport.scrollLeft(), top: fixed ? 0 : viewport.scrollTop() };
29630	viewportOffset = viewport.offset() || adjusted;
29631
29632	// Generic calculation method
29633	function calculate(side, otherSide, type, adjustment, side1, side2, lengthName, targetLength, elemLength) {
29634		var initialPos = position[side1],
29635			mySide = my[side],
29636			atSide = at[side],
29637			isShift = type === SHIFT,
29638			myLength = mySide === side1 ? elemLength : mySide === side2 ? -elemLength : -elemLength / 2,
29639			atLength = atSide === side1 ? targetLength : atSide === side2 ? -targetLength : -targetLength / 2,
29640			sideOffset = viewportScroll[side1] + viewportOffset[side1] - (containerStatic ? 0 : containerOffset[side1]),
29641			overflow1 = sideOffset - initialPos,
29642			overflow2 = initialPos + elemLength - (lengthName === WIDTH ? viewportWidth : viewportHeight) - sideOffset,
29643			offset = myLength - (my.precedance === side || mySide === my[otherSide] ? atLength : 0) - (atSide === CENTER ? targetLength / 2 : 0);
29644
29645		// shift
29646		if(isShift) {
29647			offset = (mySide === side1 ? 1 : -1) * myLength;
29648
29649			// Adjust position but keep it within viewport dimensions
29650			position[side1] += overflow1 > 0 ? overflow1 : overflow2 > 0 ? -overflow2 : 0;
29651			position[side1] = Math.max(
29652				-containerOffset[side1] + viewportOffset[side1],
29653				initialPos - offset,
29654				Math.min(
29655					Math.max(
29656						-containerOffset[side1] + viewportOffset[side1] + (lengthName === WIDTH ? viewportWidth : viewportHeight),
29657						initialPos + offset
29658					),
29659					position[side1],
29660
29661					// Make sure we don't adjust complete off the element when using 'center'
29662					mySide === 'center' ? initialPos - myLength : 1E9
29663				)
29664			);
29665
29666		}
29667
29668		// flip/flipinvert
29669		else {
29670			// Update adjustment amount depending on if using flipinvert or flip
29671			adjustment *= type === FLIPINVERT ? 2 : 0;
29672
29673			// Check for overflow on the left/top
29674			if(overflow1 > 0 && (mySide !== side1 || overflow2 > 0)) {
29675				position[side1] -= offset + adjustment;
29676				newMy.invert(side, side1);
29677			}
29678
29679			// Check for overflow on the bottom/right
29680			else if(overflow2 > 0 && (mySide !== side2 || overflow1 > 0)  ) {
29681				position[side1] -= (mySide === CENTER ? -offset : offset) + adjustment;
29682				newMy.invert(side, side2);
29683			}
29684
29685			// Make sure we haven't made things worse with the adjustment and reset if so
29686			if(position[side1] < viewportScroll[side1] && -position[side1] > overflow2) {
29687				position[side1] = initialPos; newMy = my.clone();
29688			}
29689		}
29690
29691		return position[side1] - initialPos;
29692	}
29693
29694	// Set newMy if using flip or flipinvert methods
29695	if(methodX !== 'shift' || methodY !== 'shift') { newMy = my.clone(); }
29696
29697	// Adjust position based onviewport and adjustment options
29698	adjusted = {
29699		left: methodX !== 'none' ? calculate( X, Y, methodX, adjust.x, LEFT, RIGHT, WIDTH, targetWidth, elemWidth ) : 0,
29700		top: methodY !== 'none' ? calculate( Y, X, methodY, adjust.y, TOP, BOTTOM, HEIGHT, targetHeight, elemHeight ) : 0,
29701		my: newMy
29702	};
29703
29704	return adjusted;
29705};
29706;PLUGINS.polys = {
29707	// POLY area coordinate calculator
29708	//	Special thanks to Ed Cradock for helping out with this.
29709	//	Uses a binary search algorithm to find suitable coordinates.
29710	polygon: function(baseCoords, corner) {
29711		var result = {
29712			width: 0, height: 0,
29713			position: {
29714				top: 1e10, right: 0,
29715				bottom: 0, left: 1e10
29716			},
29717			adjustable: FALSE
29718		},
29719		i = 0, next,
29720		coords = [],
29721		compareX = 1, compareY = 1,
29722		realX = 0, realY = 0,
29723		newWidth, newHeight;
29724
29725		// First pass, sanitize coords and determine outer edges
29726		i = baseCoords.length; 
29727		while(i--) {
29728			next = [ parseInt(baseCoords[--i], 10), parseInt(baseCoords[i+1], 10) ];
29729
29730			if(next[0] > result.position.right){ result.position.right = next[0]; }
29731			if(next[0] < result.position.left){ result.position.left = next[0]; }
29732			if(next[1] > result.position.bottom){ result.position.bottom = next[1]; }
29733			if(next[1] < result.position.top){ result.position.top = next[1]; }
29734
29735			coords.push(next);
29736		}
29737
29738		// Calculate height and width from outer edges
29739		newWidth = result.width = Math.abs(result.position.right - result.position.left);
29740		newHeight = result.height = Math.abs(result.position.bottom - result.position.top);
29741
29742		// If it's the center corner...
29743		if(corner.abbrev() === 'c') {
29744			result.position = {
29745				left: result.position.left + result.width / 2,
29746				top: result.position.top + result.height / 2
29747			};
29748		}
29749		else {
29750			// Second pass, use a binary search algorithm to locate most suitable coordinate
29751			while(newWidth > 0 && newHeight > 0 && compareX > 0 && compareY > 0)
29752			{
29753				newWidth = Math.floor(newWidth / 2);
29754				newHeight = Math.floor(newHeight / 2);
29755
29756				if(corner.x === LEFT){ compareX = newWidth; }
29757				else if(corner.x === RIGHT){ compareX = result.width - newWidth; }
29758				else{ compareX += Math.floor(newWidth / 2); }
29759
29760				if(corner.y === TOP){ compareY = newHeight; }
29761				else if(corner.y === BOTTOM){ compareY = result.height - newHeight; }
29762				else{ compareY += Math.floor(newHeight / 2); }
29763
29764				i = coords.length;
29765				while(i--)
29766				{
29767					if(coords.length < 2){ break; }
29768
29769					realX = coords[i][0] - result.position.left;
29770					realY = coords[i][1] - result.position.top;
29771
29772					if(
29773						corner.x === LEFT && realX >= compareX ||
29774						corner.x === RIGHT && realX <= compareX ||
29775						corner.x === CENTER && (realX < compareX || realX > result.width - compareX) ||
29776						corner.y === TOP && realY >= compareY ||
29777						corner.y === BOTTOM && realY <= compareY ||
29778						corner.y === CENTER && (realY < compareY || realY > result.height - compareY)) {
29779						coords.splice(i, 1);
29780					}
29781				}
29782			}
29783			result.position = { left: coords[0][0], top: coords[0][1] };
29784		}
29785
29786		return result;
29787	},
29788
29789	rect: function(ax, ay, bx, by) {
29790		return {
29791			width: Math.abs(bx - ax),
29792			height: Math.abs(by - ay),
29793			position: {
29794				left: Math.min(ax, bx),
29795				top: Math.min(ay, by)
29796			}
29797		};
29798	},
29799
29800	_angles: {
29801		tc: 3 / 2, tr: 7 / 4, tl: 5 / 4,
29802		bc: 1 / 2, br: 1 / 4, bl: 3 / 4,
29803		rc: 2, lc: 1, c: 0
29804	},
29805	ellipse: function(cx, cy, rx, ry, corner) {
29806		var c = PLUGINS.polys._angles[ corner.abbrev() ],
29807			rxc = c === 0 ? 0 : rx * Math.cos( c * Math.PI ),
29808			rys = ry * Math.sin( c * Math.PI );
29809
29810		return {
29811			width: rx * 2 - Math.abs(rxc),
29812			height: ry * 2 - Math.abs(rys),
29813			position: {
29814				left: cx + rxc,
29815				top: cy + rys
29816			},
29817			adjustable: FALSE
29818		};
29819	},
29820	circle: function(cx, cy, r, corner) {
29821		return PLUGINS.polys.ellipse(cx, cy, r, r, corner);
29822	}
29823};
29824;PLUGINS.svg = function(api, svg, corner)
29825{
29826	var elem = svg[0],
29827		root = $(elem.ownerSVGElement),
29828		ownerDocument = elem.ownerDocument,
29829		strokeWidth2 = (parseInt(svg.css('stroke-width'), 10) || 0) / 2,
29830		frameOffset, mtx, transformed,
29831		len, next, i, points,
29832		result, position;
29833
29834	// Ascend the parentNode chain until we find an element with getBBox()
29835	while(!elem.getBBox) { elem = elem.parentNode; }
29836	if(!elem.getBBox || !elem.parentNode) { return FALSE; }
29837
29838	// Determine which shape calculation to use
29839	switch(elem.nodeName) {
29840		case 'ellipse':
29841		case 'circle':
29842			result = PLUGINS.polys.ellipse(
29843				elem.cx.baseVal.value,
29844				elem.cy.baseVal.value,
29845				(elem.rx || elem.r).baseVal.value + strokeWidth2,
29846				(elem.ry || elem.r).baseVal.value + strokeWidth2,
29847				corner
29848			);
29849		break;
29850
29851		case 'line':
29852		case 'polygon':
29853		case 'polyline':
29854			// Determine points object (line has none, so mimic using array)
29855			points = elem.points || [
29856				{ x: elem.x1.baseVal.value, y: elem.y1.baseVal.value },
29857				{ x: elem.x2.baseVal.value, y: elem.y2.baseVal.value }
29858			];
29859
29860			for(result = [], i = -1, len = points.numberOfItems || points.length; ++i < len;) {
29861				next = points.getItem ? points.getItem(i) : points[i];
29862				result.push.apply(result, [next.x, next.y]);
29863			}
29864
29865			result = PLUGINS.polys.polygon(result, corner);
29866		break;
29867
29868		// Unknown shape or rectangle? Use bounding box
29869		default:
29870			result = elem.getBBox();
29871			result = {
29872				width: result.width,
29873				height: result.height,
29874				position: {
29875					left: result.x,
29876					top: result.y
29877				}
29878			};
29879		break;
29880	}
29881
29882	// Shortcut assignments
29883	position = result.position;
29884	root = root[0];
29885
29886	// Convert position into a pixel value
29887	if(root.createSVGPoint) {
29888		mtx = elem.getScreenCTM();
29889		points = root.createSVGPoint();
29890
29891		points.x = position.left;
29892		points.y = position.top;
29893		transformed = points.matrixTransform( mtx );
29894		position.left = transformed.x;
29895		position.top = transformed.y;
29896	}
29897
29898	// Check the element is not in a child document, and if so, adjust for frame elements offset
29899	if(ownerDocument !== document && api.position.target !== 'mouse') {
29900		frameOffset = $((ownerDocument.defaultView || ownerDocument.parentWindow).frameElement).offset();
29901		if(frameOffset) {
29902			position.left += frameOffset.left;
29903			position.top += frameOffset.top;
29904		}
29905	}
29906
29907	// Adjust by scroll offset of owner document
29908	ownerDocument = $(ownerDocument);
29909	position.left += ownerDocument.scrollLeft();
29910	position.top += ownerDocument.scrollTop();
29911
29912	return result;
29913};
29914;PLUGINS.imagemap = function(api, area, corner)
29915{
29916	if(!area.jquery) { area = $(area); }
29917
29918	var shape = (area.attr('shape') || 'rect').toLowerCase().replace('poly', 'polygon'),
29919		image = $('img[usemap="#'+area.parent('map').attr('name')+'"]'),
29920		coordsString = $.trim(area.attr('coords')),
29921		coordsArray = coordsString.replace(/,$/, '').split(','),
29922		imageOffset, coords, i, result, len;
29923
29924	// If we can't find the image using the map...
29925	if(!image.length) { return FALSE; }
29926
29927	// Pass coordinates string if polygon
29928	if(shape === 'polygon') {
29929		result = PLUGINS.polys.polygon(coordsArray, corner);
29930	}
29931
29932	// Otherwise parse the coordinates and pass them as arguments
29933	else if(PLUGINS.polys[shape]) {
29934		for(i = -1, len = coordsArray.length, coords = []; ++i < len;) {
29935			coords.push( parseInt(coordsArray[i], 10) );
29936		}
29937
29938		result = PLUGINS.polys[shape].apply(
29939			this, coords.concat(corner)
29940		);
29941	}
29942
29943	// If no shapre calculation method was found, return false
29944	else { return FALSE; }
29945
29946	// Make sure we account for padding and borders on the image
29947	imageOffset = image.offset();
29948	imageOffset.left += Math.ceil((image.outerWidth(FALSE) - image.width()) / 2);
29949	imageOffset.top += Math.ceil((image.outerHeight(FALSE) - image.height()) / 2);
29950
29951	// Add image position to offset coordinates
29952	result.position.left += imageOffset.left;
29953	result.position.top += imageOffset.top;
29954
29955	return result;
29956};
29957;var IE6,
29958
29959/*
29960 * BGIFrame adaption (http://plugins.jquery.com/project/bgiframe)
29961 * Special thanks to Brandon Aaron
29962 */
29963BGIFRAME = '<iframe class="qtip-bgiframe" frameborder="0" tabindex="-1" src="javascript:\'\';" ' +
29964	' style="display:block; position:absolute; z-index:-1; filter:alpha(opacity=0); ' +
29965		'-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";"></iframe>';
29966
29967function Ie6(api) {
29968	this._ns = 'ie6';
29969
29970	this.qtip = api;
29971	this.init(api);
29972}
29973
29974$.extend(Ie6.prototype, {
29975	_scroll : function() {
29976		var overlay = this.qtip.elements.overlay;
29977		overlay && (overlay[0].style.top = $(window).scrollTop() + 'px');
29978	},
29979
29980	init: function(qtip) {
29981		var tooltip = qtip.tooltip;
29982
29983		// Create the BGIFrame element if needed
29984		if($('select, object').length < 1) {
29985			this.bgiframe = qtip.elements.bgiframe = $(BGIFRAME).appendTo(tooltip);
29986
29987			// Update BGIFrame on tooltip move
29988			qtip._bind(tooltip, 'tooltipmove', this.adjustBGIFrame, this._ns, this);
29989		}
29990
29991		// redraw() container for width/height calculations
29992		this.redrawContainer = $('<div/>', { id: NAMESPACE+'-rcontainer' })
29993			.appendTo(document.body);
29994
29995		// Fixup modal plugin if present too
29996		if( qtip.elements.overlay && qtip.elements.overlay.addClass('qtipmodal-ie6fix') ) {
29997			qtip._bind(window, ['scroll', 'resize'], this._scroll, this._ns, this);
29998			qtip._bind(tooltip, ['tooltipshow'], this._scroll, this._ns, this);
29999		}
30000
30001		// Set dimensions
30002		this.redraw();
30003	},
30004
30005	adjustBGIFrame: function() {
30006		var tooltip = this.qtip.tooltip,
30007			dimensions = {
30008				height: tooltip.outerHeight(FALSE),
30009				width: tooltip.outerWidth(FALSE)
30010			},
30011			plugin = this.qtip.plugins.tip,
30012			tip = this.qtip.elements.tip,
30013			tipAdjust, offset;
30014
30015		// Adjust border offset
30016		offset = parseInt(tooltip.css('borderLeftWidth'), 10) || 0;
30017		offset = { left: -offset, top: -offset };
30018
30019		// Adjust for tips plugin
30020		if(plugin && tip) {
30021			tipAdjust = plugin.corner.precedance === 'x' ? [WIDTH, LEFT] : [HEIGHT, TOP];
30022			offset[ tipAdjust[1] ] -= tip[ tipAdjust[0] ]();
30023		}
30024
30025		// Update bgiframe
30026		this.bgiframe.css(offset).css(dimensions);
30027	},
30028
30029	// Max/min width simulator function
30030	redraw: function() {
30031		if(this.qtip.rendered < 1 || this.drawing) { return this; }
30032
30033		var tooltip = this.qtip.tooltip,
30034			style = this.qtip.options.style,
30035			container = this.qtip.options.position.container,
30036			perc, width, max, min;
30037
30038		// Set drawing flag
30039		this.qtip.drawing = 1;
30040
30041		// If tooltip has a set height/width, just set it... like a boss!
30042		if(style.height) { tooltip.css(HEIGHT, style.height); }
30043		if(style.width) { tooltip.css(WIDTH, style.width); }
30044
30045		// Simulate max/min width if not set width present...
30046		else {
30047			// Reset width and add fluid class
30048			tooltip.css(WIDTH, '').appendTo(this.redrawContainer);
30049
30050			// Grab our tooltip width (add 1 if odd so we don't get wrapping problems.. huzzah!)
30051			width = tooltip.width();
30052			if(width % 2 < 1) { width += 1; }
30053
30054			// Grab our max/min properties
30055			max = tooltip.css('maxWidth') || '';
30056			min = tooltip.css('minWidth') || '';
30057
30058			// Parse into proper pixel values
30059			perc = (max + min).indexOf('%') > -1 ? container.width() / 100 : 0;
30060			max = (max.indexOf('%') > -1 ? perc : 1 * parseInt(max, 10)) || width;
30061			min = (min.indexOf('%') > -1 ? perc : 1 * parseInt(min, 10)) || 0;
30062
30063			// Determine new dimension size based on max/min/current values
30064			width = max + min ? Math.min(Math.max(width, min), max) : width;
30065
30066			// Set the newly calculated width and remvoe fluid class
30067			tooltip.css(WIDTH, Math.round(width)).appendTo(container);
30068		}
30069
30070		// Set drawing flag
30071		this.drawing = 0;
30072
30073		return this;
30074	},
30075
30076	destroy: function() {
30077		// Remove iframe
30078		this.bgiframe && this.bgiframe.remove();
30079
30080		// Remove bound events
30081		this.qtip._unbind([window, this.qtip.tooltip], this._ns);
30082	}
30083});
30084
30085IE6 = PLUGINS.ie6 = function(api) {
30086	// Proceed only if the browser is IE6
30087	return BROWSER.ie === 6 ? new Ie6(api) : FALSE;
30088};
30089
30090IE6.initialize = 'render';
30091
30092CHECKS.ie6 = {
30093	'^content|style$': function() {
30094		this.redraw();
30095	}
30096};
30097;}));
30098}( window, document ));
30099
30100// Avoid `console` errors in browsers that lack a console.
30101(function () {
30102    var method;
30103    var noop = function () {
30104    };
30105    var methods = ['assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error', 'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log', 'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd', 'timeStamp', 'trace', 'warn'];
30106    var length = methods.length;
30107    var console = (window.console = window.console || {});
30108
30109    while (length--) {
30110        method = methods[length];
30111
30112        // Only stub undefined methods.
30113        if (!console[method]) {
30114            console[method] = noop;
30115        }
30116    }
30117}());
30118
30119// Place any jQuery/helper plugins in here.
30120function setCookie(cname, cvalue, exdays) {
30121    var d = new Date();
30122    d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
30123    var expires = "expires=" + d.toUTCString();
30124    document.cookie = cname + "=" + cvalue + "; " + expires;
30125    // $.post(Storage.getData('app_url'));
30126}
30127function getCookie(cname) {
30128    var name = cname + "=";
30129    var ca = document.cookie.split(';');
30130    for (var i = 0; i < ca.length; i++) {
30131        var c = ca[i];
30132        while (c.charAt(0) == ' ') {
30133            c = c.substring(1);
30134        }
30135        if (c.indexOf(name) != -1) {
30136            return c.substring(name.length, c.length);
30137        }
30138    }
30139    return "";
30140}
30141
30142if (window.history.pushState === undefined) {
30143    //adding fake support for fucked up browsers
30144    window.history.pushState = function (state, url, title) {
30145        document.location.href = url;
30146    }
30147}
30148
30149function updateUrl(title, url) {
30150    window.history.pushState(null, title, url);
30151    document.title = title;
30152}
30153
30154function updateLlb(data) {
30155    $('#loginLogout').text(data.loginLogout).attr('href', data.loginLogoutUrl);
30156}
30157
30158function stristr(haystack, needle, bool) {
30159    var pos = 0;
30160
30161    haystack += '';
30162    pos = haystack.toLowerCase()
30163        .indexOf((needle + '')
30164            .toLowerCase());
30165    if (pos == -1) {
30166        return false;
30167    } else {
30168        if (bool) {
30169            return haystack.substr(0, pos);
30170        } else {
30171            return haystack.slice(pos);
30172        }
30173    }
30174}
30175
30176function isReadyToBuy() {
30177    if (false == $('.ownerDetails .ok').hasClass('hidden') &&
30178        false == $('.adminDetails .ok').hasClass('hidden')
30179    ) {
30180        $('.success-btn-girl img').removeClass('hidden');
30181        $('.isReady .ok').removeClass('hidden').parent().find('.error').addClass('hidden');
30182        $('#domainCheckout').removeAttr('disabled');
30183        return true;
30184    } else {
30185        $('.isReady .error').removeClass('hidden').parent().find('.ok').addClass('hidden');
30186        $('#domainCheckout').attr('disabled', 'disabled');
30187        $('#creditCardDetails').addClass('hidden');
30188
30189        return false;
30190    }
30191}
30192
30193function nl2br(str, is_xhtml) {
30194    var breakTag = (is_xhtml || typeof is_xhtml === 'undefined') ? '<br />' : '<br>';
30195    return (str + '').replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1' + breakTag + '$2');
30196}
30197
30198function ctype_print(str) {
30199    var allowed = 'abcdefghijklmnopqrstuvwxyz0123456789*!@#$%^?:&*~=_.,<>{}"|-;`+()[]/\\\' ';
30200    allowed = allowed.split('');
30201
30202    str = str.replace(/\u200E/g, '');
30203    var chars = str.split('');
30204    var status = true;
30205
30206    for (var i = 0; i < chars.length; i++) {
30207        var singleChar = chars[i].toLowerCase();
30208        if (allowed.indexOf(singleChar) === -1) {
30209            status = false;
30210            break;
30211        }
30212    }
30213    return status;
30214}
30215
30216function enom_ctype_print(str) {
30217    var allowed = 'abcdefghijklmnopqrstuvwxyz0123456789*!@#$%^?:&*~=_.,<>{}"|-;`+()[]/\\\' ';
30218    allowed = allowed.split('');
30219
30220    str = str.replace(/\u200E/g, '');
30221    var chars = str.split('');
30222    var status = true;
30223
30224    for (var i = 0; i < chars.length; i++) {
30225        var singleChar = chars[i].toLowerCase();
30226        if (allowed.indexOf(singleChar) === -1) {
30227            status = false;
30228            break;
30229        }
30230    }
30231    return status;
30232}
30233
30234function ctype_print_heb(str) {
30235    var allowed = 'אבגדהוזחטיךכלםמןנסעףפץצקרשתabcdefghijklmnopqrstuvwxyz0123456789*!@#$%^?:&*~=_.,<>{}"|-;`+()[]/\\\' ';
30236    allowed = allowed.split('');
30237
30238    str = str.replace(/\u200E/g, '');
30239    var chars = str.split('');
30240    var status = true;
30241
30242    for (var i = 0; i < chars.length; i++) {
30243        var singleChar = chars[i].toLowerCase();
30244        if (allowed.indexOf(singleChar) === -1) {
30245            status = false;
30246            break;
30247        }
30248    }
30249    return status;
30250}
30251
30252function validatePerf(num) {
30253    if ('string' == typeof num && num.charAt(0) == '0') {
30254        num = num.slice(1, 5);
30255    }
30256    return num;
30257}
30258
30259jQuery.extend({
30260
30261    getQueryParameters: function (str) {
30262        return (str || document.location.search).replace(/(^\?)/, '').split("&").map(function (n) {
30263            return n = n.split("="), this[n[0]] = n[1], this
30264        }.bind({}))[0];
30265    }
30266
30267});
30268/**
30269 * This file is part of the "box.co.il" project.
30270 *
30271 * (c) Alex Buturlakin [email protected]
30272 */
30273
30274;(function($) {
30275  /**
30276   * Get Storage value by key.
30277   *
30278   * @param {String} key
30279   * @param {*}      [defaultValue]
30280   *
30281   * @return {*}
30282   */
30283  Storage.getData = function(key, defaultValue) {
30284    defaultValue = defaultValue || undefined;
30285
30286    if(typeof undefined == typeof this['data'] || !(key in this['data'])) {
30287      return defaultValue;
30288    }
30289
30290    return this['data'][key];
30291  };
30292
30293  /**
30294   * Check value by key in storage.
30295   * 
30296   * @param {String} key
30297   * @return {boolean}
30298   */
30299  Storage.hasData = function(key) {
30300    return !(typeof undefined == typeof this['data'] || !(key in this['data']));
30301  };
30302})(jQuery);
30303/**
30304 * This file is part of the "box.co.il" project.
30305 *
30306 * (c) Alex Buturlakin [email protected]
30307 */
30308;(function($) {
30309  
30310  /**
30311   * Translate message.
30312   * 
30313   * @param {String} message
30314   * @param {String} [locale]
30315   * 
30316   * @return {String}
30317   */
30318  $.translate = function(message, locale) {
30319    locale = locale || 'he';
30320
30321    if(typeof undefined === typeof Storage) {
30322      return message;
30323    }
30324    
30325    var localization = Storage.getData('localization', false);
30326
30327    if(false == localization || !(locale in localization) || !(message in localization[locale])) {
30328      return message;
30329    }
30330
30331    return localization[locale][message];
30332  }
30333})(jQuery);
30334/**
30335 * This file is part of the EXP project.
30336 * (c) Alex Buturlakin [email protected]
30337 * Date: 10.01.15
30338 * Time: 3:07
30339 */
30340
30341// Keep small extensions and helper functions here.
30342
30343;(function($) {
30344
30345  /**
30346   * Checking image for existing by url.
30347   *
30348   * @param url
30349   * @returns {boolean}
30350   */
30351  jQuery.imageExists =  function(url){
30352
30353    if(null == url || undefined == url){
30354      return false;
30355    }
30356
30357    var image = $('<img src="' + url + '" />');
30358    return image.prop('width') > 0;
30359  };
30360
30361  /**
30362   * Get url from background
30363   *
30364   * @returns {XML|string|jQuery}
30365   */
30366  jQuery.fn.parseUrlFromBackground = function (){
30367    var background = $(this).css('background-image');
30368
30369    if(undefined == background){
30370      return null;
30371    }
30372
30373    return background.replace('url("','').replace('")','');
30374  };
30375
30376  /**
30377   * Format function. Usage 'Hello, {0}!'.format('Alex'); Output 'Hello, Alex!'
30378   *
30379   * @returns String
30380   */
30381  String.prototype.format = function() {
30382    var s = this,
30383        i = arguments.length;
30384
30385    while (i--) {
30386      s = s.replace(new RegExp('\\{' + i + '\\}', 'gm'), arguments[i]);
30387    }
30388    return s;
30389  };
30390
30391  /**
30392   * Update property by path.
30393   * Have var hash = {a:{a: 'optionONE'}} n
30394   * Need to change 'optionOne' to 'optionTwo'.
30395   * Call updatePropertyByPath(hash, 'a.a', 'optionTwo');
30396   *
30397   * @returns {Object}
30398   */
30399  function updatePropertyByPath (object, path, value){
30400    var i, tmp;
30401    var parts = path.split('.');
30402
30403    for(i = 0; i < parts.length; i++) {
30404      tmp = object[parts[i]];
30405      if(value !== undefined && i == parts.length - 1) {
30406        tmp = object[parts[i]] = value;
30407      }
30408      else if(tmp === undefined) {
30409        tmp = object[parts[i]] = {};
30410      }
30411      object = tmp;
30412    }
30413    return object;
30414  }
30415
30416  /**
30417   *
30418   * @param uri
30419   * @param key
30420   * @param value
30421   * @return {*}
30422   */
30423  $.updateQueryStringParameter = function(uri, key, value) {
30424    var re = new RegExp("([?&])" + key + "=.*?(&|$)", "i");
30425    var separator = uri.indexOf('?') !== -1 ? "&" : "?";
30426    if (uri.match(re)) {
30427      return uri.replace(re, '$1' + key + "=" + value + '$2');
30428    }
30429    else {
30430      return uri + separator + key + "=" + value;
30431    }
30432  };
30433
30434  /**
30435   * Works like php ucfirst() function
30436   *
30437   * @param {string} str
30438   * @returns {string}
30439   */
30440  $.ucfirst = function(str) {
30441    var f = str.charAt(0).toUpperCase();
30442    return f + str.substr(1, str.length-1);
30443  };
30444
30445  /**
30446   *
30447   * @param {String} str
30448   * @param {String} [charlist]
30449   * @return {XML|void|*|string}
30450   */
30451  function rtrim(str, charlist) {
30452    charlist = !charlist ? ' \s\xA0' : charlist.replace(/([\[\]\(\)\.\?\/\*\{\}\+\$\^\:])/g, '\$1');
30453    var re = new RegExp('[' + charlist + ']+$', 'g');
30454    return str.replace(re, '');
30455  }
30456
30457  /**
30458   * Display twitter bootstrap alert.
30459   *
30460   * @param {String}  message
30461   * @param {String}  type
30462   * @param {int}     [delay] Delay in ms before alert will dismissed.
30463   * If delay is not defined, alert will not dismiss automatically.
30464   *
30465   * @param {String}  [insertMethod] possible values is 'prepend' and 'after'.
30466   * Default value is 'prepend'
30467   *
30468   * @param {String}  [customClass]
30469   * @param {boolean}  [showClose]
30470   */
30471  jQuery.fn.showAlert = function(message, type, delay, insertMethod, customClass, showClose) {
30472    showClose = typeof undefined == typeof showClose ? true : showClose;
30473
30474    var container   = $(this);
30475    var alertClass  = 'display-none alert alert-dismissible alert-{0}'.format(type);
30476    var closeButton = $('<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>');
30477
30478    insertMethod = insertMethod || 'prepend';
30479
30480    if(customClass) {
30481      alertClass += ' {0}'.format(customClass);
30482    }
30483
30484    if(0 == container.length) {
30485      return false;
30486    }
30487
30488    var alert = $('<div>', {
30489      'class': alertClass,
30490      'role': 'alert'
30491    });
30492
30493    var text = $('<span>', {
30494      'class': 'alert-message',
30495      'html':  message
30496    });
30497
30498    if(showClose) {
30499      alert.prepend(closeButton);
30500    }
30501
30502    alert.prepend(text);
30503
30504    var id = $(document).find('.alert').length;
30505    ++id;
30506    alert.attr('id', 'alert-{0}'.format(id));
30507
30508    // insert to
30509    switch (insertMethod) {
30510      case 'prepend': container.prepend(alert);
30511        break;
30512
30513      case 'append' : container.append(alert);
30514        break;
30515
30516      case 'before' : container.before(alert);
30517        break;
30518
30519      case 'after' :  alert.insertAfter(container);
30520        break;
30521
30522      default: alert.insertAfter(container);
30523    }
30524
30525    alert = $('#{0}'.format(alert.attr('id')));
30526
30527    alert.slideDown(600, function (){
30528      // close alerts automatically
30529      if(undefined !== delay && null != delay) {
30530        window.setTimeout(function() {
30531          alert.slideUp(600, function() {
30532            alert.alert('close');
30533          });
30534        }, delay);
30535      }
30536    });
30537
30538    return alert;
30539  };
30540
30541  /**
30542   * Add tooltip to element.
30543   *
30544   * @param {String} [title]
30545   * @param {String} [type]
30546   * @param {String} [effect]
30547   * @param {String} [position]
30548   */
30549  jQuery.fn.addTooltip = function (title, type, effect, position) {
30550
30551    var defaultType     = 'default';
30552    var defaultEffect   = 'fade';
30553    var defaultPosition = 'top';
30554    var defaultTitle    = 'ToolTip';
30555
30556    var template = '<div class="tooltip tooltip-{0} {1} {2} in"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>';
30557
30558    $.each($(this), function () {
30559
30560      var el = $(this);
30561
30562      if(!el.is(':visible')) {
30563        return true;
30564      }
30565
30566      var elementDataType     = el.data('tooltip-type');
30567      var elementDataEffect   = el.data('tooltip-effect');
30568      var elementDataPosition = el.data('tooltip-position');
30569      var elementDataTitle    = el.data('tooltip-title');
30570
30571      var currentType     = type     || (elementDataType     || defaultType);
30572      var currentEffect   = effect   || (elementDataEffect   || defaultEffect);
30573      var currentPosition = position || (elementDataPosition || defaultPosition);
30574      var currentTitle    = title    || (elementDataTitle    || defaultTitle);
30575
30576      el.siblings('.tooltip').remove();
30577
30578      el.tooltip('destroy').tooltip({
30579        template: template.format(currentType, currentEffect, currentPosition),
30580        title: currentTitle,
30581        html: true
30582      });
30583    });
30584
30585    return $(this);
30586  };
30587
30588  /**
30589   * Bind values to form elements.
30590   *
30591   * @param {Object} data
30592   * @param {String} selectorType
30593   * @param {String} [name]
30594   */
30595  jQuery.formBindElements = function(data, selectorType, name) {
30596    name = name || null;
30597    var selectorTpl = '';
30598
30599    switch (selectorType) {
30600      case 'class': selectorTpl = '.{0}';
30601        break;
30602      case 'id':    selectorTpl = '#{0}';
30603        break;
30604      case 'data':    selectorTpl = '[data-{1}="{0}"]';
30605        break;
30606      default :
30607        selectorTpl = false;
30608    }
30609
30610    $.each(data, function(id, val) {
30611      var elementSelector = selectorTpl ? selectorTpl.format(id, name) : id;
30612      var element = $(elementSelector);
30613
30614      if(element.length) {
30615        element.val(val);
30616      }
30617    });
30618  };
30619
30620  /**
30621   * Add loading state to button.
30622   *
30623   * @param {String} type Possible values are "loading" and "reset"
30624   * @returns {*|HTMLElement}
30625   */
30626  jQuery.fn.buttonLoading = function(type) {
30627    var button     = $(this);
30628    var isDisabled = 'reset' != type;
30629
30630    button.button(type);
30631    button.prop('disabled', isDisabled);
30632
30633    return button;
30634  };
30635
30636  /**
30637   * Pass twitter devices types ("xs", "xm", "md", "lg").
30638   * If device have passed type(s), return true, otherwise - false.
30639   *
30640   * @returns {boolean}
30641   */
30642  jQuery.checkDeviceType = function() {
30643    var args = arguments;
30644    var detected = false;
30645
30646    $.each(args, function() {
30647      if($('body').hasClass('screen-{0}'.format(this))) {
30648        detected = true;
30649        return false;
30650      }
30651    });
30652
30653    return detected;
30654  };
30655
30656  /**
30657   * Provide to scroll screen to element.
30658   *
30659   * @param {int}      [time] Animation time in ms. Default time is 500ms.
30660   * @param {int}      [offsetTop]
30661   * @param {function} [callback]
30662   *
30663   * @returns {*|HTMLElement}
30664   */
30665  jQuery.fn.scrollToElement = function(time, offsetTop, callback) {
30666    var el = $(this);
30667    time      = time || 500;
30668    offsetTop = offsetTop || 0;
30669    callback  = 'function' == typeof callback ? callback : function () {};
30670
30671    if(0 == el.length) {
30672      return el;
30673    }
30674
30675    $('html, body').animate({
30676      scrollTop: el.offset().top + offsetTop
30677    }, time, callback);
30678
30679    return el;
30680  };
30681
30682  /**
30683   * Merge jQuery object to one object.
30684   *
30685   * @param {Array} objects
30686   */
30687  jQuery.mergeJQueryObjects = function (objects) {
30688    return $($.map(objects, function(el){return el.get();}));
30689  };
30690
30691  /**
30692   * Filter elements by data name and value
30693   * Working with  jQuery.data(..) setter
30694   *
30695   * @param {String} prop
30696   * @param {String|Array} [val]
30697   * @returns {*}
30698   */
30699  $.fn.filterByData = function (prop, val) {
30700    var el = $(this);
30701
30702    if (typeof val === 'undefined') {
30703      return el.filter(function() {
30704        return 'undefined' !== typeof $(this).data(prop);
30705      });
30706    }
30707    // 15374
30708
30709    return el.filter(function() {
30710      return val instanceof Array ? -1 !== $.inArray($(this).data(prop), val) : val == $(this).data(prop);
30711    });
30712  };
30713
30714  /**
30715   * Remove classes by prefix
30716   *
30717   * @param {String} prefix
30718   * @returns {jQuery}
30719   */
30720  $.fn.removeClassPrefix = function(prefix) {
30721    this.each(function(i, el) {
30722      var classes = el.className.split(" ").filter(function(c) {
30723        return c.lastIndexOf(prefix, 0) !== 0;
30724      });
30725      el.className = $.trim(classes.join(" "));
30726    });
30727    return this;
30728  };
30729
30730  /**
30731   * Reset form data.
30732   *
30733   * @param {String[]} [exclude]
30734   */
30735  $.fn.resetForm = function(exclude) {
30736    exclude = exclude || [];
30737    var el  = $(this);
30738
30739    // reset text fields.
30740    var elements = el.find('input[type=text], input[type="email"], input[type="password"], textarea, select');
30741
30742    $.each(elements, function() {
30743      var element = $(this);
30744
30745      if(-1 !== $.inArray(element.attr('name'), exclude)) {
30746        return true;
30747      }
30748
30749      element.val('');
30750
30751      // select boxes
30752      if('select' == element.prop('tagName').toLowerCase()) {
30753        // un-select
30754        element.find('option:selected').prop('selected', false);
30755
30756        // select first
30757        element.find('option:first').prop('selected', true);
30758      }
30759    });
30760  };
30761
30762  /**
30763   * Lock form fields
30764   *
30765   * @param {Boolean} state
30766   * @param {String[]} [exclude]
30767   */
30768  $.fn.lockForm = function(state, exclude) {
30769    var el = $(this);
30770
30771    // lock form fields.
30772    var elements = el.find('input[type=text], input[type="email"], input[type="password"], textarea, select');
30773
30774    $.each(elements, function() {
30775      var element = $(this),
30776          tag     = element.prop('tagName').toLowerCase()
30777
30778      if(-1 !== $.inArray(element.attr('name'), exclude)) {
30779        return true;
30780      }
30781
30782      if('select' == tag) {
30783        var pe = state ? 'none' : 'auto';
30784
30785        element.css('pointer-events', pe);
30786
30787        return true;
30788      }
30789
30790      element.prop('readonly', state);
30791    });
30792  };
30793
30794  /**
30795   * Populate form elements with selected option.
30796   * // todo@alexbuturlakin: need merge this function with $.fn.populateDefaultData
30797   * @param {jQuery}  option
30798   * @param {String[]} exclude
30799   */
30800  $.fn.populateDefaultDataSelect = function(option, exclude) {
30801    exclude = exclude || [];
30802    var el       = $(this),
30803        elements = option.data('default-elements');
30804
30805    if(typeof elements === typeof undefined || false == elements) {
30806      return false;
30807    }
30808
30809    // reset form
30810    el.resetForm(exclude);
30811
30812    // update data
30813    var data = elements.split('||');
30814
30815    $.each(data, function() {
30816      var params = this.split('::');
30817
30818      // check that data has right format
30819      if(false == Array.isArray(params) || 0 == params.length) {
30820        return true;
30821      }
30822
30823      // check in excluded elements
30824      if(-1 !== $.inArray(params[0], exclude)) {
30825        return true;
30826      }
30827
30828      // get element
30829      var element = el.find('[name="{0}"]'.format(params[0]));
30830
30831      // no element found
30832      if(0 == element.length) {
30833        return true;
30834      }
30835
30836      var tag = element.prop('tagName').toLowerCase();
30837
30838      // if select or text input
30839      if(('select' == tag)) {
30840        element.val(params[1]);
30841
30842        return true;
30843      }
30844
30845      var type = element.attr('type');
30846
30847      // no type
30848      if(typeof type === typeof undefined) {
30849        element.val(params[1]);
30850
30851        return true;
30852      }
30853
30854      // if text input
30855      if('input' == tag && -1 !== $.inArray(type.toLowerCase(), ['text', 'email'])) {
30856        element.val(params[1]);
30857      }
30858
30859      // if radio
30860      if('input' == tag && 'radio' == type.toLowerCase()) {
30861        params[1] == element.val() ? element.prop('checked', true) : element.prop('checked', false);
30862      }
30863
30864      // trigger event
30865      element.trigger('default-data-populated', [params[1], 'select']);
30866    });
30867
30868    el.trigger('default-data-populated', [[], 'select']);
30869  };
30870
30871  /**
30872   * Populate form elements with default data.
30873   *
30874   * @param {Boolean}  populate
30875   * @param {String[]} exclude
30876   */
30877  $.fn.populateDefaultData = function(populate, exclude) {
30878    exclude = exclude || [];
30879    var el  = $(this);
30880
30881    // reset form
30882    if(false == populate) {
30883      el.resetForm(exclude);
30884
30885      return el;
30886    }
30887
30888    // or populate values
30889    el.find('[data-default]').each(function() {
30890      var element = $(this),
30891          data    = element.data('default'),
30892          tag     = element.prop('tagName').toLowerCase();
30893
30894      // check in excluded elements
30895      if(-1 !== $.inArray(element.attr('name'), exclude)) {
30896        return true;
30897      }
30898
30899      // if select or text input
30900      if(('select' == tag)) {
30901        element.val(data);
30902
30903        return true;
30904      }
30905
30906      var type = element.attr('type');
30907
30908      // no type
30909      if(typeof type === typeof undefined) {
30910        element.val(data);
30911
30912        return true;
30913      }
30914
30915      // if text input
30916      if('input' == tag && -1 !== $.inArray(type.toLowerCase(), ['text', 'email'])) {
30917        element.val(data);
30918      }
30919
30920      // if radio
30921      if('input' == tag && 'radio' == type.toLowerCase()) {
30922        data == element.val() ? element.prop('checked', true) : element.prop('checked', false);
30923      }
30924
30925      // ??
30926
30927      // trigger event
30928      element.trigger('default-data-populated', [data, 'checkbox']);
30929    });
30930
30931    el.trigger('default-data-populated', [[], 'checkbox']);
30932  };
30933
30934  /**
30935   * Get submit path for form.
30936   *
30937   * @return {String}
30938   */
30939  $.fn.getFormSubmitPath = function() {
30940    var form = $(this);
30941
30942    // if not a form or form not have action.
30943    if('form' != form.prop('tagName').toLowerCase() || typeof undefined == typeof form.attr('action')) {
30944      return document.URL;
30945    }
30946
30947    var url = form.attr('action');
30948
30949    url =  rtrim(url, '/');
30950    url += window.location.search;
30951
30952    return url;
30953  };
30954
30955  /**
30956   * Page reload
30957   *
30958   * @param {{}} [query]
30959   */
30960  $.pageReload = function(query) {
30961    var url = window.location.href;
30962
30963    if(undefined != query) {
30964      var queryArr = [];
30965      $.each(query, function(key, value) {
30966        queryArr.push('{0}={1}'.format(key, value));
30967      });
30968
30969      if(queryArr.length > 0) {
30970        var queryStr = queryArr.join('&'),
30971            sep      = url.indexOf('?') > -1 ? '&' : '?';
30972
30973        url += sep + queryStr;
30974      }
30975    }
30976
30977    window.location.href = url;
30978  };
30979
30980  /**
30981   * from here - http://stackoverflow.com/questions/1090948/change-url-parameters
30982   * @return {string}
30983   */
30984  $.updateUrlParam = function(url, param, paramVal) {
30985    var TheAnchor = null;
30986    var newAdditionalURL = "";
30987    var tempArray = url.split("?");
30988    var baseURL = tempArray[0];
30989    var additionalURL = tempArray[1];
30990    var temp = "";
30991
30992    if (additionalURL) {
30993      var tmpAnchor = additionalURL.split("#");
30994      var TheParams = tmpAnchor[0];
30995      TheAnchor = tmpAnchor[1];
30996      if(TheAnchor) {
30997        additionalURL = TheParams;
30998      }
30999
31000      tempArray = additionalURL.split("&");
31001
31002      for (var i=0; i<tempArray.length; i++) {
31003        if(tempArray[i].split('=')[0] != param) {
31004          newAdditionalURL += temp + tempArray[i];
31005          temp = "&";
31006        }
31007      }
31008    } else {
31009      var tmpAnchor = baseURL.split("#");
31010      var TheParams = tmpAnchor[0];
31011      TheAnchor     = tmpAnchor[1];
31012
31013      if(TheParams) {
31014        baseURL = TheParams;
31015      }
31016    }
31017
31018    if(TheAnchor) {
31019      paramVal += "#" + TheAnchor;
31020    }
31021
31022    var rows_txt = temp + "" + param + "=" + paramVal;
31023    return baseURL + "?" + newAdditionalURL + rows_txt;
31024  };
31025
31026  /**
31027   * From here - http://stackoverflow.com/a/1634841/1156253
31028   *
31029   * @param {String} url
31030   * @param {String} parameter
31031   */
31032  $.removeUrlParam = function(url, parameter) {
31033    //prefer to use l.search if you have a location/link object
31034    var urlparts = url.split('?');
31035    if (urlparts.length>=2) {
31036
31037      var prefix= encodeURIComponent(parameter)+'=';
31038      var pars= urlparts[1].split(/[&;]/g);
31039
31040      //reverse iteration as may be destructive
31041      for (var i= pars.length; i-- > 0;) {
31042        //idiom for string.startsWith
31043        if (pars[i].lastIndexOf(prefix, 0) !== -1) {
31044          pars.splice(i, 1);
31045        }
31046      }
31047
31048      url= urlparts[0] + (pars.length > 0 ? '?' + pars.join('&') : "");
31049      return url;
31050    } else {
31051      return url;
31052    }
31053  };
31054
31055  /**
31056   * Show simple ajax modal
31057   *
31058   * @param {string}   path
31059   * @param {function} callback
31060   * @param {{}}       params
31061   */
31062  $.showXHRModal = function(path, callback, params) {
31063    callback = callback || function() {};
31064    params   = params || {};
31065
31066    var options = {
31067      type:    'iframe',
31068      padding: 0
31069    };
31070
31071    options = $.merge(options, params);
31072
31073    $.get(path, function (response) {
31074      // user not loggined
31075      if (3 == response.status) {
31076        window.location = Storage.getData('app_url') + 'user/login';
31077
31078        return;
31079      }
31080
31081      // on error
31082      if(0 == response.status) {
31083        return;
31084      }
31085
31086      options.content   = response.html;
31087      options.afterShow = function() { callback.call(this, params, response) };
31088
31089      $.fancybox.open(options);
31090    });
31091  };
31092
31093  /**
31094   * Show error in modal window.
31095   *
31096   * @param {String} message
31097   */
31098  $.showError = function(message) {
31099    var html = '<div class="modal-error"><div class="modal-header"><h3>{0}</h3></div><div class="modal-body">{1}</div></div>';
31100
31101    $.fancybox.open({
31102      type:    'iframe',
31103      padding: 0,
31104      // autoSize: false,
31105      // width:   '400px',
31106      content: html.format($.translate('Error!'), message)
31107    });
31108  };
31109
31110  /**
31111   * Show success modal window
31112   *
31113   * @param {String}         title
31114   * @param {String}         text
31115   * @param {String|Boolean} [destination]
31116   * @param {Boolean}        [disableRedirect]
31117   */
31118  $.showSuccess = function (title, text, destination, disableRedirect) {
31119    disableRedirect = disableRedirect || false;
31120
31121    var html  = '<div class="modal-ok">',
31122        head  = '<div class="modal-header"><span class="UISectionTitleSummary UILabelIconValid">{0}</span></div>'.format(title),
31123        body  = '<div class="modal-body">{0}</div>'.format(text),
31124        foot  = '<div class="modal-footer"><button class="btn btn-primary close-window">{0}</button></div>'.format($.translate('Close'));
31125
31126    html = html + head + body + foot + '</div>';
31127
31128    var redirect = function() {
31129      if(disableRedirect) {
31130        return true;
31131      }
31132
31133      if(typeof undefined === typeof destination) {
31134        window.location.href = window.location.href;
31135      } else {
31136        window.location.href = destination;
31137      }
31138    };
31139
31140    $.fancybox.open({
31141      content: html,
31142      padding: 0,
31143      type: 'iframe',
31144      afterShow: function () {
31145        var btn = $('button.close-window');
31146        btn.click(function(){
31147          $.fancybox.close();
31148          redirect();
31149        });
31150      },
31151      afterClose: function () {
31152        redirect();
31153      }
31154    });
31155  };
31156})(jQuery);
31157
31158
31159
31160;(function($) {
31161    $(document).ready(function() {
31162
31163        var regVerifyForm = $("#domain-registrant-verification");
31164
31165        let regexName = /^[a-zA-Z\s]+$/;
31166        let regexCity = /^[a-zA-Z\s]+$/;
31167        let regexStreet = /^[A-Za-z0-9 .,-]+$/;
31168        let regexZip = /^\d{5,7}$/;
31169        let regexOrgID = /^5\d{8}$/;
31170        let regexOrgName = /^[a-zA-Z0-9.&\-"' ]+$/;
31171
31172        function validateInput(input, regex) {
31173            let value = $(input).val();
31174            if (!regex.test(value)) {
31175                $(input).addClass("input-error");
31176                return false;
31177            } else {
31178                $(input).removeClass("input-error");
31179                return true;
31180            }
31181        }
31182
31183        //name
31184        regVerifyForm.find('input[name="name"]').on("input", function () {
31185
31186            let value = $(this).val();
31187            if (!regexName.test(value)) {
31188                $(this).val(value.replace(/[^a-zA-Z\s]/g, '').substring(0, 150));
31189            }
31190            validateInput(this, regexName);
31191        });
31192
31193        //city
31194        regVerifyForm.find('input[name="address_city"]').on("input", function () {
31195
31196            let value = $(this).val();
31197            if (!regexCity.test(value)) {
31198                $(this).val(value.replace(/[^a-zA-Z\s]/g, '').substring(0, 150));
31199            }
31200            validateInput(this, regexCity);
31201        });
31202
31203        //street
31204        regVerifyForm.find('input[name="address_street"]').on("input", function () {
31205
31206            let value = $(this).val();
31207            if (!regexStreet.test(value)) {
31208                $(this).val(value.replace(/[^A-Za-z0-9 .,-]/g, '').substring(0, 150));
31209            }
31210            validateInput(this, regexStreet);
31211        });
31212
31213        //zip
31214        regVerifyForm.find('input[name="address_zip"]').on("input", function () {
31215            validateInput(this, regexZip);
31216        });
31217
31218        //organization_number
31219        regVerifyForm.find('input[name="organization_number"]').on("input", function () {
31220
31221            let value = $(this).val();
31222
31223            if (!regexOrgID.test(value)) {
31224                $(this).val(value.replace(/\D/g, '').replace(/^(\d{1})/, '5').substring(0, 9));
31225            }
31226            validateInput(this, regexOrgID);
31227        });
31228
31229        //organization_name
31230        regVerifyForm.find('input[name="organization_name"]').on("input", function () {
31231
31232            let value = $(this).val();
31233
31234            validateInput(this, regexOrgName);
31235        });
31236
31237        //phone
31238        regVerifyForm.find('input[name="phone_number"]').on("input", function () {
31239
31240            let value = $(this).val();
31241
31242            value.replace(/\D/g, '');
31243
31244            if (!isValidIsraeliPhone(value)) {
31245                $(this).addClass("input-error");
31246                $(this).val(value.replace(/\D/g, '').substring(0, 10));
31247            } else {
31248                $(this).removeClass("input-error");
31249            }
31250        });
31251
31252
31253        regVerifyForm.find(":input").on("invalid", function() {
31254            this.setCustomValidity(translations['this input is required field'] || key);
31255        }).on("input", function() {
31256            this.setCustomValidity(""); 
31257        });
31258
31259        regVerifyForm.on("submit", function (e) {
31260
31261            let valid = true;
31262
31263            $("#domain-registrant-verification-errors").empty();
31264
31265            if ($("#name").length) {
31266                valid &= validateInput("#name", regexName) ? true : (addErrorMessage("Name Is Invalid"), false);
31267            }
31268            valid &= validateInput("#address_city", regexCity) ? true : (addErrorMessage("City Is Invalid"), false);
31269            valid &= validateInput("#address_street", regexStreet) ? true : (addErrorMessage("Address Is Invalid"), false);
31270            valid &= validateInput("#address_zip", regexZip) ? true : (addErrorMessage("Zip is required"), false);
31271            if ($("#organization_number").length) {
31272                valid &= validateInput("#organization_number", regexOrgID) ? true : (addErrorMessage("Org ID Is Invalid"), false);
31273            }
31274            if ($("#organization_name").length) {
31275                valid &= validateInput("#organization_name", regexOrgName) ? true : (addErrorMessage("Org Name Is Invalid"), false);
31276            }
31277            valid &= isValidIsraeliPhone($("#phone_number").val()) ? true : (addErrorMessage("Phone Number Is Invalid"), false);
31278            valid &= validateVerificationForm()? true : (addErrorMessage("Please select at least one file for verification documents"), false);
31279            
31280
31281            if (!valid) {
31282                e.preventDefault();
31283            }
31284
31285        });
31286
31287        function addErrorMessage(key) {
31288            errMsgDiv = $('#domain-registrant-verification-errors');
31289            var message = translations[key] || key;
31290            errMsgDiv.append('<p>' + message + '</p>');
31291        }
31292
31293        function isValidIsraeliPhone(phone) {
31294
31295			if (phone.length !== 9 && phone.length !== 10) {
31296                $('#phone_number').addClass("input-error");
31297                return false;
31298            } 
31299
31300			var regex = /^((\+972|0)([2-9])[0-9]{7}|(\+972|0)(2|3|4|7|8|9)[0-9]{7}|(\+972|0)5[0-9]{8}|(\+972|0)7[0-9]{8})$/;
31301			if (phone.startsWith('07') && phone.length !== 10) {
31302                $('#phone_number').addClass("input-error");
31303				return false;
31304			}
31305			if (phone.startsWith('05') && phone.length !== 10) {
31306                $('#phone_number').addClass("input-error");
31307				return false;
31308			}
31309            $('#phone_number').removeClass("input-error");
31310			return regex.test(phone);
31311		}
31312
31313        let maxIdentityFiles = 5;
31314        let currentVisible = 1;
31315
31316        $('#addButton').click(function() {
31317            if (currentVisible < maxIdentityFiles) {
31318                currentVisible++;
31319                $('#identity' + currentVisible).show();
31320            }
31321        });
31322
31323        $('#removeButton').click(function() {
31324            if (currentVisible > 1) {
31325                $('#identity' + currentVisible).hide().val('');
31326                currentVisible--;
31327            }
31328        });
31329        
31330
31331    });
31332})(jQuery);
31333
31334
31335// document.addEventListener('DOMContentLoaded', () => {
31336//     const addButton = document.getElementById('addButton');
31337//     const removeButton = document.getElementById('removeButton');
31338//     const maxInputs = 5; // Total number of inputs
31339//     let visibleInputs = 1; // Start with only one input visible
31340
31341//     // Add button functionality
31342//     addButton.addEventListener('click', () => {
31343//         if (visibleInputs < maxInputs) {
31344//             visibleInputs++;
31345//             const nextInput = document.getElementById(`identity${visibleInputs}`);
31346//             if (nextInput) {
31347//                 nextInput.style.display = 'block';
31348//             }
31349//         }
31350//     });
31351
31352//     // Remove button functionality
31353//     removeButton.addEventListener('click', () => {
31354//         if (visibleInputs > 1) {
31355//             const currentInput = document.getElementById(`identity${visibleInputs}`);
31356//             if (currentInput) {
31357//                 currentInput.value = ''; // Clear the value
31358//                 currentInput.style.display = 'none';
31359//             }
31360//             visibleInputs--;
31361//         }
31362//     });
31363// });
31364/**
31365 * This file is part of the box.co.il project.
31366
31367 * (c) Alex Buturlakin [email protected]
31368 */
31369;(function($) {
31370
31371  // set custom messages for validation errors
31372  $.validatorMessages({
31373    valid_email:       $.translate('Only English letters (a-z), numbers, periods, @<br><span>Example: [email protected]</span>'),
31374    english:           $.translate('Only English letters (a-z)'),
31375    // company_name:      $.translate('Name Company Limited'),
31376    is_natural:        $.translate('Only digits (0-9)'),
31377    max_length:        $.translate('Up to {1} Characters'),
31378    length_one_or_two: $.translate('{1} characters'),
31379    password: [
31380      $.translate('At least 8 characters'),
31381      $.translate('At least one English letter (a-z)'),
31382      $.translate('Contain the number one (9-0)')
31383    ],
31384    one_word:  $.translate('First Name'),
31385    two_words: $.translate('Last Name'),
31386    street:    $.translate('Street is required with house num'),
31387    alpha_numeric_space_dot: $.translate('Only English letters (a-z), numbers (0-9)'),
31388    english_numeric:         $.translate('Only English letters (a-z), numbers (0-9)')
31389
31390  });
31391
31392  // forms validation rules
31393  window.validationRules = {};
31394
31395  var registerZipFieldRules = {
31396    rules: 'required|is_natural|length_one_or_two[7]|callback_valid_zip_code',
31397    messages: {
31398      required: false,
31399      callback_valid_zip_code: $.translate('Zip is invalid')
31400    },
31401    custom: {
31402      callback_valid_zip_code: function(field) {
31403        return !window.isInvalidZipCode(field.value);
31404      }
31405    }
31406  };
31407
31408  // #user-auth-register-company form
31409  window.validationRules.registerCompanyRules = {
31410    email: {
31411      rules: 'required|valid_email',
31412      messages: {
31413        required: false
31414      }
31415    },
31416    name: {
31417      rules: 'required|company_name|english_numeric|words_count_min[2]',
31418      messages: {
31419        required: false,
31420        words_count_min: false,
31421        company_name: false
31422      }
31423    },
31424    id: {
31425      rules: 'required|is_natural',
31426      messages: {
31427        required: false
31428      }
31429    },
31430    invoice: {
31431      rules: 'required|english_numeric',
31432      messages: {
31433        required: false
31434      }
31435    },
31436    tel1: {
31437      rules: 'required|is_natural',
31438      messages: {
31439        required: false
31440      }
31441    },
31442    tel3: {
31443      rules: 'required|is_natural',
31444      messages: {
31445        required: false
31446      }
31447    },
31448    tel4: {
31449      rules: 'required|is_natural',
31450      // disable validation if element is hidden
31451      depends: function(field) {
31452        var el = $(field.element);
31453
31454        return !el.closest('.form-control-inner').hasClass('hidden');
31455      },
31456      messages: {
31457        required: false
31458      }
31459    },
31460    street_name: {
31461      rules: 'required|english',
31462      messages: {
31463        required: false
31464      }
31465    },
31466    street_number: {
31467      rules: 'required|is_natural',
31468      messages: {
31469        required: false
31470      }
31471    },
31472    city: {
31473      rules: 'required|english',
31474      messages: {
31475        required: false
31476      }
31477    },
31478    zip: registerZipFieldRules,
31479    password: {
31480      rules: 'required|password',
31481      messages: {
31482        required: false
31483      }
31484    },
31485    password2: {
31486      rules: 'required|matches[password]',
31487      messages: {
31488        required: false,
31489        matches: $.translate('The passwords does not match')
31490      }
31491    },
31492    approve_terms: {
31493      rules: 'required',
31494      messages: {
31495        required: false
31496      }
31497    }
31498  };
31499
31500  // #user-auth-register-user form
31501  window.validationRules.registerUserRules = {
31502    email: {
31503      rules: 'required|valid_email',
31504      messages: {
31505        required: false
31506      }
31507    },
31508    name: {
31509      rules: 'required|one_word|two_words|english',
31510      messages: {
31511        required: false
31512      }
31513    },
31514    tel1: {
31515      rules: 'required|is_natural',
31516      messages: {
31517        required: false
31518      }
31519    },
31520    tel3: {
31521      rules: 'required|is_natural',
31522      messages: {
31523        required: false
31524      }
31525    },
31526    street_name: {
31527      rules: 'required|english',
31528      messages: {
31529        required: false
31530      }
31531    },
31532    street_number: {
31533      rules: 'required|is_natural',
31534      messages: {
31535        required: false
31536      }
31537    },
31538    city: {
31539      rules: 'required|english',
31540      messages: {
31541        required: false
31542      }
31543    },
31544    zip: registerZipFieldRules,
31545    password: {
31546      rules: 'required|password',
31547      messages: {
31548        required: false
31549      }
31550    },
31551    password2: {
31552      rules: 'required|matches[password]',
31553      messages: {
31554        required: false,
31555        matches: $.translate('The passwords does not match')
31556      }
31557    },
31558    approve_terms: {
31559      rules: 'required',
31560      messages: {
31561        required: false
31562      }
31563    },
31564    tel4: {
31565      rules: 'required|is_natural',
31566      // disable validation if element is hidden
31567      depends: function(field) {
31568        var el = $(field.element);
31569
31570        return !el.closest('.form-control-inner').hasClass('hidden');
31571      },
31572      messages: {
31573        required: false
31574      }
31575    }
31576  };
31577
31578  // Unified register form (private + company)
31579  window.validationRules.registerRules = {
31580    email: {
31581      rules: 'required|valid_email',
31582      messages: {
31583        required: false
31584      }
31585    },
31586    name: {
31587      rules: 'required|one_word|two_words|english',
31588      messages: {
31589        required: false
31590      }
31591    },
31592    id: {
31593      rules: 'required|is_natural',
31594      depends: function(field) {
31595        var form = $(field.element).closest('form');
31596        return form.find('[name="clientType"]:checked').val() === 'company';
31597      },
31598      messages: {
31599        required: false
31600      }
31601    },
31602    invoice: {
31603      rules: 'required|english_numeric',
31604      depends: function(field) {
31605        var form = $(field.element).closest('form');
31606        return form.find('[name="clientType"]:checked').val() === 'company';
31607      },
31608      messages: {
31609        required: false
31610      }
31611    },
31612    tel1: {
31613      rules: 'required|is_natural',
31614      messages: {
31615        required: false
31616      }
31617    },
31618    tel3: {
31619      rules: 'required|is_natural',
31620      messages: {
31621        required: false
31622      }
31623    },
31624    tel4: {
31625      rules: 'required|is_natural',
31626      depends: function(field) {
31627        var el = $(field.element);
31628        return !el.closest('.form-control-inner').hasClass('hidden');
31629      },
31630      messages: {
31631        required: false
31632      }
31633    },
31634    street_name: {
31635      rules: 'required|english',
31636      messages: {
31637        required: false
31638      }
31639    },
31640    street_number: {
31641      rules: 'required|is_natural',
31642      messages: {
31643        required: false
31644      }
31645    },
31646    city: {
31647      rules: 'required|english',
31648      messages: {
31649        required: false
31650      }
31651    },
31652    zip: registerZipFieldRules,
31653    password: {
31654      rules: 'required|password',
31655      messages: {
31656        required: false
31657      }
31658    },
31659    password2: {
31660      rules: 'required|matches[password]',
31661      messages: {
31662        required: false,
31663        matches: $.translate('The passwords does not match')
31664      }
31665    },
31666    approve_terms: {
31667      rules: 'required',
31668      messages: {
31669        required: false
31670      }
31671    }
31672  };
31673
31674  // password reset 2 form rules
31675  window.validationRules.resetPasswordRules = {
31676    password: {
31677      rules: 'required|password',
31678      messages: {
31679        required: false
31680      }
31681    },
31682    password2: {
31683      rules: 'required|matches[password]',
31684      messages: {
31685        required: false,
31686        matches:  $.translate('The passwords does not match')
31687      }
31688    }
31689  };
31690
31691  window.validationRules.purchaseDomainRulesOwnerName = {
31692    user: {
31693      rules: 'required|one_word|two_words|english',
31694      group: 'owner',
31695      messages: {
31696        required: $.translate('full name is required')
31697      }
31698    },
31699    company: {
31700      rules: 'required|english_numeric|words_count_min[2]',
31701      group: 'owner',
31702      messages: {
31703        required: $.translate('Company name is invalid'),
31704        words_count_min: $.translate('Company name is invalid')
31705      }
31706    }
31707  }
31708
31709  // domain purchase domain admin rules
31710  window.validationRules.purchaseDomainRules = {
31711    // owner info section
31712    ownerEmail: {
31713      rules: 'required|valid_email',
31714      group: 'owner',
31715      messages: {
31716        required: $.translate('Email Is Required')
31717      }
31718    },
31719    ownerFullName: {
31720      rules: window.validationRules.purchaseDomainRulesOwnerName.user.rules,
31721      group: 'owner',
31722      messages: window.validationRules.purchaseDomainRulesOwnerName.user.messages
31723    },
31724    ownerCompanyId: {
31725      rules: 'is_natural|callback_israeli_company_id',
31726      group: 'owner',
31727      messages: {
31728        required: $.translate('Company number is required'),
31729        callback_israeli_company_id: $.translate('Company ID must be 9 digits starting with 5')
31730      },
31731      custom: {
31732        callback_israeli_company_id: function(field) {
31733          // Get the form element
31734          var form = $(field.element).closest('form');
31735          if (form.length === 0) {
31736            form = $('#ownerModal');
31737          }
31738          
31739          // Get the country field value
31740          var countryEl = form.find('[name="ownerAddressCountry"], #ownerAddressCountry');
31741          var country = countryEl.length > 0 ? countryEl.val() : '';
31742          
31743          // Get the client type to check if company ID is required
31744          var clientType = form.find('[name="clientType"]:checked').val();
31745          var isRequired = clientType === 'company';
31746          
31747          // Get the company ID value
31748          var companyId = field.value || '';
31749          
31750          // If not required or country is not IL, skip this validation
31751          if (!isRequired || country !== 'IL' || !companyId) {
31752            return true;
31753          }
31754          
31755          // Validate: must be 9 digits and start with 5
31756          var isValid = /^5\d{8}$/.test(companyId);
31757          
31758          return isValid;
31759        }
31760      }
31761    },
31762    ownerAddressStreet: {
31763      rules: 'required|street|alpha_numeric_space_dot',
31764      group: 'owner',
31765      messages: {
31766        required: $.translate('Street is required')
31767      }
31768    },
31769    ownerAddressCity: {
31770      rules: 'required|english',
31771      group: 'owner',
31772      messages: {
31773        required: $.translate('City is required')
31774      }
31775    },
31776    ownerAddressZip: {
31777      rules: 'required|is_natural|length_one_or_two[7]',
31778      group: 'owner',
31779      messages: {
31780        required: $.translate('Zip is required'),
31781        length_one_or_two: $.translate('{1} characters')
31782      }
31783    },
31784    ownerTel1: {
31785      rules: 'required|is_natural',
31786      group: 'owner'
31787    },
31788    ownerTel3: {
31789      rules: 'required|is_natural',
31790      group: 'owner'
31791    },
31792    ownerTel4: {
31793      rules: 'required|is_natural',
31794      group: 'owner',
31795      // disable validation if element is hidden
31796      depends: function(field) {
31797        var el = $(field.element);
31798        return !el.hasClass('hidden');
31799      }
31800    },
31801    ownerFax1: {
31802      rules: 'is_natural',
31803      group: 'owner'
31804    },
31805    ownerFax2: {
31806      rules: 'is_natural',
31807      group: 'owner'
31808    },
31809    ownerFax3: {
31810      rules: 'is_natural',
31811      group: 'owner'
31812    },
31813
31814    // admin info section
31815
31816    adminEmail: {
31817      rules: 'required|valid_email',
31818      group: 'admin',
31819      messages: {
31820        required: $.translate('Email Is Required')
31821      }
31822    },
31823    adminFullName: {
31824      rules: 'required|one_word|two_words|english',
31825      group: 'admin',
31826      messages: {
31827        required: $.translate('full name is required')
31828      }
31829    },
31830    adminAddressStreet: {
31831      rules: 'required|street|alpha_numeric_space_dot',
31832      group: 'admin',
31833      messages: {
31834        required: $.translate('Street is required')
31835      }
31836    },
31837    adminAddressCity: {
31838      rules: 'required|english',
31839      group: 'admin',
31840      messages: {
31841        required: $.translate('City is required')
31842      }
31843    },
31844    adminAddressZip: {
31845      rules: 'required|is_natural|length_one_or_two[7]',
31846      group: 'admin',
31847      messages: {
31848        required: $.translate('Zip is required'),
31849        length_one_or_two: $.translate('{1} characters')
31850      }
31851    },
31852    adminTel1: {
31853      rules: 'required|is_natural',
31854      group: 'admin'
31855    },
31856    adminTel3: {
31857      rules: 'required|is_natural',
31858      group: 'admin'
31859    },
31860    adminTel4: {
31861      rules: 'required|is_natural',
31862      group: 'admin',
31863      // disable validation if element is hidden
31864      depends: function(field) {
31865        var el = $(field.element);
31866        return !el.hasClass('hidden');
31867      }
31868    },
31869    adminFax1: {
31870      rules: 'is_natural',
31871      group: 'admin'
31872    },
31873    adminFax2: {
31874      rules: 'is_natural',
31875      group: 'admin'
31876    },
31877    adminFax3: {
31878      rules: 'is_natural',
31879      group: 'admin'
31880    },
31881
31882    // purchase credit number validation
31883    creditNumber: {
31884      rules: 'required|valid_credit_card',
31885      messages: {
31886        required: false,
31887        valid_credit_card: $.translate('id is invalid')
31888      },
31889      group: 'payment'
31890    },
31891    creditExpirationYear: {
31892      rules: 'required|greater_than_current_year',
31893      messages: {
31894        greater_than_current_year: 'Year'
31895      },
31896      group: 'payment',
31897      custom: {
31898        greater_than_current_year: function(field) {
31899          return false;
31900        }
31901      }
31902    },
31903    creditExpirationMonth: {
31904      rules: 'required|greater_than_current_month',
31905      messages: {
31906        'greater_than_current_month': 'Month error'
31907      },
31908      group: 'payment',
31909      custom: {
31910        greater_than_current_month: function(field) {
31911          return false;
31912        }
31913      }
31914    }
31915  };
31916
31917})(jQuery);
31918/**
31919 * This file is part of the box.co.il project.
31920
31921 * (c) Alex Buturlakin [email protected]
31922 */
31923;(function($) {
31924  window.isInvalidZipCode = function(zip) {
31925    if (!/^\d{7}$/.test(zip)) {
31926      return false;
31927    }
31928
31929    if (/^(\d)\1{6}$/.test(zip)) {
31930      return true;
31931    }
31932
31933    var ascending = true;
31934    var descending = true;
31935    var i;
31936    var current;
31937    var previous;
31938
31939    for (i = 1; i < zip.length; i++) {
31940      current = parseInt(zip.charAt(i), 10);
31941      previous = parseInt(zip.charAt(i - 1), 10);
31942
31943      if (current !== previous + 1) {
31944        ascending = false;
31945      }
31946      if (current !== previous - 1) {
31947        descending = false;
31948      }
31949    }
31950
31951    return ascending || descending;
31952  };
31953
31954  window.isInvalidOptionalPhone = function(phone) {
31955    phone = $.trim(phone);
31956
31957    if (phone === '') {
31958      return false;
31959    }
31960
31961    if (!/^[\d\s+\-().]+$/.test(phone)) {
31962      return true;
31963    }
31964
31965    var digits = phone.replace(/\D/g, '');
31966
31967    return digits.length < 9 || digits.length > 15;
31968  };
31969
31970  /**
31971   * Get list of validation rules with messages.
31972   *
31973   * @returns {{}}
31974   */
31975  jQuery.fn.getValidationRulesList = function () {
31976
31977    var rules = $(this).data('validation-rules');
31978    
31979    return typeof rules === typeof undefined || rules === false ? {} : rules;
31980  };
31981
31982  /**
31983   * Get list of validation rules with messages.
31984   *
31985   * @returns {{}}
31986   */
31987  jQuery.fn.hasValidationRule = function (rule) {
31988
31989    var rules = $(this).getValidationRulesList();
31990
31991    return rule in rules;
31992  };
31993
31994  /**
31995   * Add status to validated form field
31996   *
31997   * @param {String} status
31998   */
31999  jQuery.fn.validationSetStatus = function(status) {
32000    var container = $(this).closest('.validation');
32001
32002    // add indicator if not exists
32003    if(false == container.hasClass('validation-no-indicate') && 0 == container.find('.validation-state').length) {
32004      container.append('<span class="validation-state">');
32005    }
32006
32007    // remove all statuses
32008    if('none' == status) {
32009      container.removeClass('validation-valid validation-not-valid');
32010    }
32011
32012    // valid
32013    if('valid' == status) {
32014      container.removeClass('validation-not-valid');
32015      container.addClass('validation-valid');
32016    }
32017
32018    // not valid
32019    if('not-valid' == status) {
32020      container.removeClass('validation-valid');
32021      container.addClass('validation-not-valid');
32022    }
32023  };
32024
32025  /**
32026   * Remove validation errors
32027   */
32028  jQuery.fn.validatorClearErrors = function() {
32029    var el = $(this);
32030
32031    el.find('.alert-danger').remove();
32032    el.find('.has-error').removeClass('has-error');
32033  };
32034  
32035  /**
32036   * This extensions provide default validation.
32037   * Creates tooltips for validation errors.
32038   *
32039   * todo@alexbuturlakin: refactoring - create jquery plugin for validate2 package
32040   * 
32041   * @param {{}} rules
32042   * @param {String|function} [container]
32043   * @param [errorHandler]
32044   */
32045  jQuery.fn.validatorEnableDefaultValidation = function (rules, container, errorHandler) {
32046    var form  = $(this);
32047    
32048    // validation callback for form
32049    var callbackForm  = function (status, errors, groups) {
32050      var errorsList = {},
32051          errorContainer;
32052
32053      if('function' == typeof container) {
32054        errorContainer = container(status, errors, groups);
32055      } else {
32056        errorContainer = $(container);
32057        errorContainer = 0 == container.length ? form : container;
32058      }
32059      
32060      // clear container
32061      errorContainer.validatorClearErrors();
32062
32063      // all is ok
32064      if(status) {
32065        return true;
32066      }
32067      
32068      // get all errors
32069      $.each(errors, function(name, values) {
32070        var el          = form.find('[name="{0}"]'.format(name)),
32071            label       = el.data('error-label'),
32072            elContainer = el.closest('.form-group');
32073
32074        elContainer.addClass('has-error');
32075
32076        if(null == label) {
32077          label = elContainer.find('label')
32078              .clone()    //clone the element
32079              .children(':not(span)') //select all the children
32080              .remove()   //remove all the children
32081              .end()      //again go back to selected element
32082              .text().trim();
32083        }
32084
32085        if(typeof undefined == typeof label || null == label) {
32086          label = null;
32087        } else {
32088          label = '<span class="error-field">{0}</span>'.format(label);
32089        }
32090
32091        errorsList[name] = {
32092          error: values[0]['message'],
32093          label: label,
32094          rule:  values[0]['rule']
32095        };
32096      });
32097
32098      // call callback
32099      if('function' == typeof errorHandler) {
32100        errorsList = errorHandler(errorsList);
32101      }
32102
32103      // show errors in container
32104      if($.isPlainObject(errorsList)) {
32105        var message = $.map(errorsList, function(data) {
32106          return null == data['label'] ? data['error'] : '{0}: {1}'.format(data['label'], data['error']);
32107        }).join('<br>');
32108
32109        errorContainer.showAlert(message, 'danger', null, 'append', null, false);
32110      }
32111    };
32112
32113    // init validator
32114    var validator = new FormValidator(form.attr('name'), [], {
32115      callbacks: {form: [callbackForm]}
32116    });
32117
32118    // add rules to FormValidator
32119    $.each(rules, function(name, data) {
32120      var el = form.find('[name="{0}"]'.format(name));
32121      var dataRules = {};
32122      var messages = 'messages' in data ? data.messages : {};
32123
32124      // add validation handler
32125      validator._addField(data, name);
32126
32127      // save rules in el data
32128      var rulesArr = data.rules.split('|');
32129
32130      for (var k in rulesArr) {
32131        var info = validator._getRuleInfo(rulesArr[k]);
32132
32133        // if message was overridden
32134        if (0 !== Object.keys(messages).length && info.method in messages) {
32135          // ping about it validator
32136          validator.setMessage(name + '.' + info.method, messages[info.method]);
32137          dataRules[info.method] = messages[info.method];
32138        } else {
32139          dataRules[info.method] = validator._getMessage(name, info.method, info.params);
32140        }
32141      }
32142
32143      // set default status
32144      if(undefined !== el.val() && null !== el.val() && '' != el.val()) {
32145        el.addClass('has-predefined-value');
32146
32147        // set status
32148        el.validationSetStatus('valid')
32149      }
32150
32151      // add rules to data
32152      el.data('validation-rules', dataRules);
32153    });
32154
32155    form.data('validator', validator);
32156  };  
32157
32158  /**
32159   * This extensions provide to validate forms fields and show errors in qtip2 tooltips.
32160   * Creates tooltips for validation errors.
32161   *
32162   * todo@alexbuturlakin: refactoring - create jquery plugin for validate2 package
32163   *
32164   * @param rules
32165   */
32166  jQuery.fn.validatorEnableTooltipValidation = function (rules) {
32167    // validation callback for form
32168    var callbackForm  = function (status, errors) {
32169      var form = $(this);
32170
32171      if(true == status) {
32172        return true;
32173      }
32174
32175      // get elements with errors
32176      var selectors = [];
32177
32178      $.each(errors, function(name, values) {
32179        selectors.push('[name="{0}"]'.format(name));
32180      });
32181
32182      var inputs   = form.find(selectors.join(','));
32183      var controls = inputs.closest('.validation');
32184
32185      // highlight
32186      controls.addClass('validation-not-valid');
32187      inputs.addClass('highlight');
32188
32189      setTimeout(function(){
32190        inputs.removeClass('highlight');
32191      }, 2000);
32192
32193      // focus to first error
32194      var inputFirst = inputs.eq(0);
32195      inputFirst.scrollToElement(500, -60, function() {
32196        inputFirst.focus();
32197
32198        // if select2
32199        if(inputFirst.hasClass('select2')) {
32200          inputFirst.select2("open");
32201        }
32202      });
32203    };
32204
32205    // validation callback for fields
32206    var callbackFields  = function (status, type, field, errors) {
32207      var el      = $(this);
32208      var tooltip = el.qtip().tooltip;
32209
32210      // =)
32211      if('form' == type) {
32212        return true;
32213      }
32214
32215      if(status) {
32216        // disable tooltip
32217        el.qtip('hide');
32218        el.qtip('disable');
32219
32220        // set status
32221        el.validationSetStatus('valid')
32222      } else {
32223        // enable tooltip
32224        el.qtip('disable', false);
32225        el.qtip('show');
32226
32227        // hide error messages in tooltip
32228        
32229        // get selectors
32230        var liSelectors = ['[data-rule="rule-default"]'];
32231        for(var k in errors) {
32232          var rule = errors[k]['rule'];
32233          
32234          liSelectors.push('[data-rule="{0}"]'.format(rule));
32235        }
32236
32237        // hide not actual errors and show actual
32238        if(tooltip && 0 !== tooltip.length) {
32239          var notActual = tooltip.find('li:not({0})'.format(liSelectors.join(',')));
32240          var actual    = tooltip.find(liSelectors.join(','));
32241
32242          notActual.hide(500);
32243          actual.show(500);
32244        }
32245
32246        // set status
32247        '' == el.val() ? el.validationSetStatus('none') : el.validationSetStatus('not-valid');
32248      }
32249    };
32250
32251    var form      = $(this);
32252    var validator = new FormValidator(form.attr('name'), [], {
32253      callbacks: {fields: [callbackFields], form: [callbackForm]}
32254    });
32255
32256    // add rules to FormValidator
32257    $.each(rules, function(name, data) {
32258      var el        = form.find('[name="{0}"]'.format(name));
32259      var dataRules = {};
32260      var messages  = 'messages' in data ? data.messages : {};
32261      
32262      // add validation handler
32263      validator._addField(data, name);
32264
32265      // save rules in el data
32266      var rulesArr = data.rules.split('|');
32267
32268      for(var k in rulesArr) {
32269        var info = validator._getRuleInfo(rulesArr[k]);
32270
32271        // if message was overridden
32272        if(0 !== Object.keys(messages).length && info.method in messages) {
32273          // ping about it validator
32274          validator.setMessage(name+'.'+info.method, messages[info.method]);
32275          dataRules[info.method] = messages[info.method];
32276        } else {
32277          dataRules[info.method] = validator._getMessage(name, info.method, info.params);
32278        }
32279      }
32280
32281      // set default status
32282      if(undefined !== el.val() && null !== el.val() && '' != el.val()) {
32283        el.addClass('has-predefined-value');
32284      
32285        // set status
32286        el.validationSetStatus('valid')
32287      }
32288
32289      el.data('validation-rules', dataRules);
32290
32291      // form validation on key up
32292      // text inputs integration
32293      el.keyup(function() {
32294        validator.validateField(name);
32295        validator.cleanErrors();
32296
32297        // fast fix for password and password confirm
32298        if(el.hasValidationRule('password')) {
32299          var el2 = el.closest('form').find('[name="password2"]');
32300
32301          if(el2.val() == el.val() && '' != el.val()) {
32302            el2.validationSetStatus('valid');
32303          } else {
32304            el2.validationSetStatus('not-valid');
32305          }
32306        }
32307      });
32308
32309      // checkboxes integration
32310      if('checkbox' == el.attr('type')) {
32311        el.on('change', function() {
32312          validator.validateField(name);
32313          validator.cleanErrors();
32314        });
32315      }
32316
32317      // select boxes integration
32318      if(undefined != el.prop('tagName') && 'select' == el.prop('tagName').toLowerCase()) {
32319        el.on('change', function() {
32320          validator.validateField(name);
32321          validator.cleanErrors();
32322        });
32323      }
32324    });
32325
32326    form.data('validator', validator);
32327  };
32328
32329  /**
32330   * Validate form.
32331   *
32332   * @param {[]} [groups]
32333   * 
32334   * @returns {boolean}
32335   */
32336  jQuery.fn.validateForm = function(groups) {
32337    groups = groups || [];
32338    
32339    var form      = $(this),
32340        validator = form.getValidator();
32341
32342    // if not a form
32343    if(false == validator) {
32344      return false;
32345    }
32346    
32347    // validate
32348    return validator._validateForm(groups);
32349  };
32350
32351  /**
32352   * Get form validator.
32353   * 
32354   * @returns FormValidator
32355   */
32356  jQuery.fn.getValidator = function() {
32357    var form      = $(this),
32358        validator = $(this).data('validator');
32359
32360    // if not a form
32361    if('form' != form.prop('tagName').toLowerCase()) {
32362      return false;
32363    }
32364
32365    // form don't have validator
32366    if(null == validator || 'object' !== typeof validator) {
32367      return false;
32368    }
32369    
32370    return validator;
32371  };
32372
32373  /**
32374   * Disable or enable validation for form.
32375   * 
32376   * @param {Boolean} state
32377   * @param {String} [group]
32378   * @returns {boolean}
32379   */
32380  jQuery.fn.disableValidation = function(state, group) {
32381    var form      = $(this),
32382        validator = form.getValidator();
32383
32384    // if not a form
32385    if(false == validator) {
32386      return false;
32387    }
32388
32389    state ? validator.disable(group) : validator.enable();
32390  };
32391
32392  /**
32393   * Change validator field rules
32394   *
32395   * @param {String} name
32396   * @param {String} rules
32397   * @param {{}}     [messages]
32398   *
32399   * @returns {boolean}
32400   */
32401  jQuery.fn.validatorChangeFieldRules = function (name, rules, messages) {
32402    var form      = $(this),
32403        validator = form.getValidator();
32404
32405    // if not a form
32406    if(false == validator) {
32407      return false;
32408    }
32409
32410    validator.changeFiledRules(name, rules, messages);
32411  };
32412
32413  /**
32414   * Register custom rule.
32415   * 
32416   * @param {String}   name
32417   * @param {function} callback
32418   * @param {String}   [message]
32419   * 
32420   * @returns {boolean}
32421   */
32422  jQuery.fn.validatorAddRule = function(name, callback, message) {
32423    var form      = $(this),
32424        validator = form.getValidator();
32425
32426    // if not a form
32427    if(false == validator) {
32428      return false;
32429    }
32430
32431    validator.registerCallback(name, callback);
32432  };
32433
32434  /**
32435   * Box form submissions
32436   */
32437  jQuery.fn.validateSubmit = function() {
32438    var form   = $(this);
32439    var submit = form.find('button[type="submit"]');
32440
32441    // add data loading
32442    submit.buttonLoading('loading');
32443
32444    $.post(form.getFormSubmitPath(), form.serialize(), function (data) {
32445
32446      if(data.status) {
32447        window.location.href = data.page;
32448      } else {
32449        form.showAlert(nl2br(data.msg, true), 'danger', null, 'prepend').scrollToElement(500, -60);
32450      }
32451
32452      submit.buttonLoading('reset');
32453    });
32454  };
32455
32456  /**
32457   * Concat form values
32458   *
32459   * @param {[]} elements
32460   * @param {String} [sep]
32461   *
32462   * @returns {string}
32463   */
32464  jQuery.fn.concatFormValues = function(elements, sep) {
32465    sep = sep || '';
32466    var res = '';
32467
32468    for(var k in elements) {
32469      var el  = elements[k];
32470      var val = el instanceof jQuery ? el.val().trim() : $(this).find(el).val().trim();
32471
32472      res += sep + val;
32473    }
32474
32475    return res.trim();
32476  };
32477
32478  /**
32479   * Returns actual fields for phone number.
32480   *
32481   * @returns {string[]}
32482   */
32483  jQuery.fn.getTelFields = function() {
32484    var tel2 = $(this).find('.tel-2');
32485
32486    // fast fix for compatibility on different pages
32487    return tel2.closest('.form-control-inner').hasClass('hidden') || tel2.hasClass('hidden') ?
32488        [
32489          '.tel-3',
32490          '.tel-4',
32491          '.tel-1'
32492        ] :
32493        [
32494          '.tel-3',
32495          '.tel-2',
32496          '.tel-1'
32497        ];
32498  };
32499
32500})(jQuery);
32501/**
32502 * This file is part of the box.co.il project.
32503
32504 * (c) Alex Buturlakin [email protected]
32505 */
32506
32507;(function($) {
32508  // company registration form
32509  // #user-auth-register-company form
32510
32511  var registerCompanyForm = $('#user-auth-register-company').find('form');
32512
32513  // enable validation
32514  if (registerCompanyForm.length) {
32515    registerCompanyForm.validatorEnableTooltipValidation(window.validationRules.registerCompanyRules);
32516
32517    // form submit handler
32518    registerCompanyForm.on('submit', function(e) {
32519      e.preventDefault();
32520
32521      var form = $(this);
32522
32523      // pre submit
32524      form.find('[name="primary_phone"]').val(form.concatFormValues(form.getTelFields(), ' '));
32525
32526      // validate and submit
32527      if(form.validateForm()) {
32528        $.localStorage.set('domains_bulk', []);
32529        form.validateSubmit();
32530      }
32531
32532      return false;
32533    });
32534  }
32535
32536
32537  // user registration form
32538  // #user-auth-register-user form
32539
32540  // enable validation
32541  var registerUserForm = $('#user-auth-register-user').find('form');
32542
32543  // enable validation
32544  if (registerUserForm.length) {
32545    registerUserForm.validatorEnableTooltipValidation(window.validationRules.registerUserRules);
32546
32547    // form submit handler
32548    registerUserForm.on('submit', function(e) {
32549      e.preventDefault();
32550
32551      var form = $(this);
32552
32553      // prepare before submit
32554
32555      form.find('[name="primary_phone"]').val(form.concatFormValues(form.getTelFields(), ' '));
32556
32557      // validate and submit
32558      if(form.validateForm()) {
32559        $.localStorage.set('domains_bulk', []);
32560        form.validateSubmit();
32561      }
32562
32563      return false;
32564    });
32565  }
32566
32567  // Unified registration form (#user-auth-register)
32568  var registerForm = $('#user-auth-register').find('form.js-register-form');
32569
32570  if (registerForm.length && window.validationRules.registerRules) {
32571    registerForm.validatorEnableTooltipValidation(window.validationRules.registerRules);
32572
32573    function setRegisterClientType(type) {
32574      var isCompany = type === 'company';
32575      var $companyFields = registerForm.find('.js-register-company-fields');
32576      var $name = registerForm.find('[name="name"]');
32577      var $id = registerForm.find('[name="id"]');
32578      var $invoice = registerForm.find('[name="invoice"]');
32579
32580      registerForm.find('.js-register-label-private').toggleClass('hidden', isCompany);
32581      registerForm.find('.js-register-label-company').toggleClass('hidden', !isCompany);
32582      $companyFields.toggleClass('hidden', !isCompany);
32583
32584      $id.prop('disabled', !isCompany);
32585      $invoice.prop('disabled', !isCompany);
32586
32587      if (!isCompany) {
32588        $id.val('');
32589        $invoice.val('');
32590      }
32591
32592      if ($name.length) {
32593        var placeholder = isCompany
32594          ? $name.attr('data-placeholder-company')
32595          : $name.attr('data-placeholder-private');
32596        if (placeholder) {
32597          $name.attr('placeholder', placeholder);
32598        }
32599      }
32600
32601      if (isCompany) {
32602        registerForm.validatorChangeFieldRules('name', 'required|company_name|english_numeric|words_count_min[2]', {
32603          company_name: false,
32604          words_count_min: false
32605        });
32606        registerForm.validatorChangeFieldRules('id', 'required|is_natural', { required: false });
32607        registerForm.validatorChangeFieldRules('invoice', 'required|english_numeric', { required: false });
32608      } else {
32609        registerForm.validatorChangeFieldRules('name', 'required|one_word|two_words|english', {
32610          required: false
32611        });
32612        registerForm.validatorChangeFieldRules('id', 'custom', {'custom': function () { return true; }});
32613        registerForm.validatorChangeFieldRules('invoice', 'custom', {'custom': function () { return true; }});
32614      }
32615    }
32616
32617    registerForm.find('[name="clientType"]').on('change', function() {
32618      setRegisterClientType($(this).val());
32619    });
32620
32621    setRegisterClientType(registerForm.find('[name="clientType"]:checked').val() || 'private');
32622
32623    registerForm.on('submit', function(e) {
32624      e.preventDefault();
32625
32626      var form = $(this);
32627
32628      form.find('[name="primary_phone"]').val(form.concatFormValues(form.getTelFields(), ' '));
32629
32630      if (form.validateForm()) {
32631        $.localStorage.set('domains_bulk', []);
32632        form.validateSubmit();
32633      }
32634
32635      return false;
32636    });
32637  }
32638  // user reset password 2 form
32639  // #user-auth-register-company form
32640
32641  // enable validation
32642  var resetPasswordForm = $('#user-auth-password-reset2').find('form');
32643
32644  // enable validation
32645  resetPasswordForm.validatorEnableTooltipValidation(window.validationRules.resetPasswordRules);
32646
32647  // form submit handler
32648  resetPasswordForm.on('submit', function(e) {
32649    e.preventDefault();
32650
32651    var form = $(this);
32652
32653    // validate and submit
32654    if(form.validateForm()) {
32655      $.localStorage.set('domains_bulk', []);
32656      form.validateSubmit();
32657    }
32658
32659    return false;
32660  });
32661
32662  // domain purchase
32663  // domain owner info
32664  // enable validation
32665
32666  // enable validation
32667  var domainPurchaseForm = $('#domain-purchase-form');
32668
32669  var errorHandler = function (errors) {
32670    // if one of tel1, tel2, tel3 or tel4 is empty => show one message
32671    var phoneFields = ['ownerTel3', 'ownerTel4', 'ownerTel1', 'adminTel3', 'adminTel4', 'adminTel1'];
32672    var telRequired = false;
32673
32674    $.each(errors, function(name, data) {
32675      if(phoneFields.indexOf(name) > -1 && 'required' == data.rule) {
32676        telRequired = true;
32677
32678        return false;
32679      }
32680    });
32681
32682    if(telRequired) {
32683      for (var key in errors) {
32684        if (errors.hasOwnProperty(key) && phoneFields.indexOf(key) > -1) {
32685          delete errors[key];
32686        }
32687      }
32688
32689      errors['phone'] = {
32690        'label': '<span class="error-field">{0}</span>'.format($.translate('Primary Phone')),
32691        'error': $.translate('Primary phone is required')
32692      }
32693    }
32694
32695    return errors;
32696  };
32697
32698  // enable validation
32699  domainPurchaseForm.validatorEnableDefaultValidation(window.validationRules.purchaseDomainRules,
32700      function(status, errors, groups) {
32701        if(-1 !== $.inArray('owner', groups)) {
32702          return $('#ownerModal').find('.modal-base-content');
32703        }
32704
32705        if(-1 !== $.inArray('admin', groups)) {
32706          return $('#adminModal').find('.modal-base-content');
32707        }
32708
32709        if(-1 !== $.inArray('default', groups)) {
32710          return $('#creditDetails').find('.modal-base-content');
32711        }
32712
32713        return $('#domain-purchase-form');
32714      },
32715      errorHandler
32716  );
32717
32718  // save owner info
32719  domainPurchaseForm.find('#ownerModal button').on('click', function(e) {
32720    e.preventDefault();
32721
32722    var name = $('#ownerFullName'),
32723        modal = $('#ownerModal'),
32724        primaryPhone = modal.find('[name="ownerPrimaryPhone"]'),
32725        faxNumber    = modal.find('[name="ownerFaxNumber"]');
32726
32727    // add LTD
32728    if ($('input[name=clientType]:checked').val() == 'company' && name.val() != '' && !stristr(name.val(), 'LTD')) {
32729      name.val(name.val().trim() + ' LTD');
32730    }
32731
32732    // copy paste from domain.purchase.js
32733    if(domainPurchaseForm.validateForm(['owner'])) {
32734      $('.ownerDetails .error').hide();
32735      $('.ownerDetails .ok').removeClass('hidden');
32736      modal.modal('hide');
32737
32738      // set primary phone and fax
32739      primaryPhone.val(modal.concatFormValues(modal.getTelFields(), ' '));
32740      faxNumber.val(modal.concatFormValues(['[name="ownerFax3"]', '[name="ownerFax2"]', '[name="ownerFax1"]'], ' '));
32741    } else {
32742      $('.ownerDetails .error').show();
32743      $('.ownerDetails .ok').addClass('hidden');
32744    }
32745
32746    isReadyToBuy();
32747  });
32748
32749  // save admin info
32750  domainPurchaseForm.find('#adminModal button').on('click', function(e) {
32751    e.preventDefault();
32752
32753    var modal = $('#adminModal'),
32754        primaryPhone = modal.find('[name="adminPrimaryPhone"]'),
32755        faxNumber    = modal.find('[name="adminFaxNumber"]');
32756
32757    // copy paste from domain.purchase.js
32758    if(domainPurchaseForm.validateForm(['admin'])) {
32759      $('.adminDetails .error').hide();
32760      $('.adminDetails .ok').removeClass('hidden');
32761      modal.modal('hide');
32762      // set primary phone and fax number
32763      primaryPhone.val(modal.concatFormValues(modal.getTelFields(), ' '));
32764      faxNumber.val(modal.concatFormValues(['[name="adminFax3"]', '[name="adminFax2"]', '[name="adminFax1"]'], ' '));
32765
32766    } else {
32767      $('.adminDetails .error').show();
32768      $('.adminDetails .ok').addClass('hidden');
32769    }
32770
32771    isReadyToBuy();
32772  });
32773
32774  // admin info use default values or not
32775  domainPurchaseForm.find('input[name="contact"]').change(function() {
32776    var select  = domainPurchaseForm.find('#contacts'),
32777        exclude = ['adminContacts', 'contact'],
32778        modal   = $('#adminModal');
32779
32780    if('contacts' == $(this).val()) {
32781      select.prop('disabled', false);
32782      modal.lockForm(true, exclude);
32783      select.trigger('change');
32784      domainPurchaseForm.disableValidation(true, 'admin');
32785    } else {
32786      select.prop('disabled', true);
32787      modal.lockForm(false, exclude);
32788      modal.resetForm(exclude);
32789      domainPurchaseForm.disableValidation(false);
32790    }
32791  });
32792
32793  // clear error on default data populated
32794  $('#ownerModal, #adminModal').on('default-data-populated', function() {
32795    $(this).validatorClearErrors();
32796  });
32797
32798  // change owner validation if client type was changed
32799  $.purchaseOwnerValidationRules = function(type) {
32800    if('company' == type) {
32801      domainPurchaseForm.validatorChangeFieldRules('ownerFullName', 'required|company_name|english|words_count_min[2]', {
32802        company_name: $.translate('Name Company Limited')
32803      });
32804      domainPurchaseForm.validatorChangeFieldRules('ownerCompanyId', 'required|is_natural|callback_israeli_company_id', {
32805        required: $.translate('Company number is required'),
32806        callback_israeli_company_id: $.translate('Company ID must be 9 digits starting with 5')
32807      });
32808    } else {
32809      domainPurchaseForm.validatorChangeFieldRules('ownerFullName', 'required|one_word|two_words|english');
32810      domainPurchaseForm.validatorChangeFieldRules('ownerCompanyId', 'custom', {'custom': function () {return true;}}
32810);
32811    }
32812  };
32813
32814  // listener to change domain purchase owner validation
32815  $('#ownerModal').find('[type="radio"]').on('change', function() {
32816    $.purchaseOwnerValidationRules($(this).val());
32817  });
32818
32819  // fast hard code to set default validation for adminFullName
32820  if(0 != domainPurchaseForm.length) {
32821    var clientType = $('#ownerModal').find('[type="radio"]:checked').trigger('change');
32822
32823    if(0 != clientType.length) {
32824      $.purchaseOwnerValidationRules(clientType.val());
32825    }
32826  }
32827
32828
32829  var purchaseSubmitting = false;
32830  $(document).on('click', '#infoSubmit', function (e) {
32831    e.preventDefault();
32832    if (purchaseSubmitting) return;
32833    var form = $(this).closest('form');
32834    var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
32835    var emailEl = form.find('#ownerEmail');
32836    var urlRe = /[a-zA-Z0-9]+\.[a-zA-Z0-9]+|[a-zA-Z0-9]+\.[a-zA-Z0-9]+(\.[a-zA-Z0-9]+(\.[a-zA-Z0-9]+)?)/g;
32837    var creditReg = /^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|6(?:011|5[0-9]{2})[0-9]{12}|(?:2131|1800|35\d{3})\d{11})$/;
32838    var stringRe = /^[A-Za-z\s][A-Za-z0-9\s]*$/;
32839    var fullNameEl = form.find('#ownerFullName');
32840    var ownerCompanyIdEl = form.find('#ownerCompanyId');
32841    var priPhoneEl = form.find('#ownerPrimaryPhone');
32842    var ownerFaxEl = form.find('#ownerFaxNumber');
32843    var streetEl = form.find('#ownerAddressStreet');
32844    var cityEl = form.find('#ownerAddressCity');
32845    var countryEl = form.find('#ownerAddressCountry');
32846    var zipEl = form.find('#ownerAddressZip');
32847    var creditCardEl = form.find('#creditNumber');
32848    var creditYrEl = form.find('#creditExpirationYear');
32849    var creditMoEl = form.find('#creditExpirationMonth');
32850    var creditCardCvvEl = form.find('#creditCvv');
32851    var creditIdEl = form.find('#creditId');
32852    var approve_termsEl = form.find('#approve_terms');
32853    var approve_terms = approve_termsEl.is(":checked");
32854    var date = new Date();
32855    var domainPeriodEl = form.find('#domainPeriod');
32856    var creditCard = creditCardEl.val();
32857    var creditCardYr = creditYrEl.val();
32858    var creditCardMo = creditMoEl.val();
32859    var creditCardCvv = creditCardCvvEl.val();
32860    var creditCardId = creditIdEl.val();
32861
32862    var email = emailEl.val();
32863    var fullName = fullNameEl.val();
32864    var ownerCompanyId = ownerCompanyIdEl.val();
32865    var street = streetEl.val();
32866    var city = cityEl.val();
32867    var country = countryEl.val();
32868    var zip = zipEl.val();
32869    var domainPeriod = parseInt($('[name=domainPeriod]:checked').val());
32870
32871    var phone1 = form.find('#tel1').val();
32872    var phone2 = form.find('#tel2').val(validatePerf(form.find('#tel2').val())).val();
32873    var phone3 = form.find('#tel3').val();
32874
32875    var fax1 = form.find('#fax1').val();
32876    var fax2 = form.find('#fax2').val(validatePerf(form.find('#fax2').val())).val();
32877    var fax3 = form.find('#fax3').val();
32878
32879    var priPhone = priPhoneEl.val();
32880    var ns = $('.domain-purchase-ns-name');
32881    var nsvals = [];
32882
32883    ns.each(function (i) {
32884      var val = ns[i].value;
32885      if (val !== '') {
32886        nsvals[i] = val;
32887      }
32888    });
32889    var errors = '';
32890    if (!approve_terms) {
32891      approve_termsEl.parent().addClass('has-error');
32892      errors += $.translate('Approve Terms is required') + '\n';
32893
32894    }
32895    else {
32896      approve_termsEl.parent().removeClass('has-error');
32897    }
32898    if (domainPeriod < 1 && domainPeriod > 5) {
32899      domainPeriodEl.parent().addClass('has-error');
32900      errors += $.translate('Domain Period is invalid') + '\n';
32901    }
32902    else {
32903      domainPeriodEl.parent().removeClass('has-error');
32904    }
32905    if (isNaN(creditCardYr) || parseInt(creditCardYr) < date.getFullYear()) {
32906      creditYrEl.parent().addClass('has-error');
32907      errors += $.translate('Expiry Year is invalid') + '\n';
32908    }
32909    else {
32910      creditYrEl.parent().removeClass('has-error');
32911    }
32912    if (isNaN(creditCardMo) || creditCardYr == date.getFullYear() && creditCardMo < date.getMonth()) {
32913      creditMoEl.parent().addClass('has-error');
32914      errors += $.translate('Expiry Month is invalid') + '\n';
32915    }
32916    else {
32917      creditMoEl.parent().removeClass('has-error');
32918    }
32919    if (isNaN(creditCardCvv) || creditCardCvv.length < 3 || creditCardCvv.length > 4) {
32920      creditCardCvvEl.parent().addClass('has-error');
32921      errors += $.translate('cvv is invalid') + '\n';
32922    }
32923    else {
32924      creditCardCvvEl.parent().removeClass('has-error');
32925    }
32926    if (isNaN(creditCardId) || creditCardId.length < 9 || creditCardId.length > 9) {
32927      creditIdEl.parent().addClass('has-error');
32928      errors += $.translate('id is invalid') + '\n';
32929    }
32930    else {
32931      creditIdEl.parent().removeClass('has-error');
32932    }
32933    if (isNaN(creditCard) || creditCard.length < 8 || creditCard.length > 17 || !creditReg.test(creditCard) && creditCard.length > 9 || creditCard[0] === 0) {
32934      creditCardEl.parent().addClass('has-error');
32935      errors += $.translate('card is invalid') + '\n';
32936    }
32937    else {
32938      creditCardEl.parent().removeClass('has-error');
32939    }
32940    if (!re.test(email) || email === '') {
32941      emailEl.parent().addClass('has-error');
32942      errors += $.translate('Email is invalid') + '\n';
32943    }
32944    else {
32945      emailEl.parent().removeClass('has-error');
32946    }
32947    if (fullName === '' || !stringRe.test(fullName)) {
32948      fullNameEl.parent().addClass('has-error');
32949      errors += $.translate('full name is required') + '\n';
32950    } else {
32951      fullNameEl.parent().removeClass('has-error');
32952    }
32953
32954    if ($('input[name=clientType]:checked').val() == 'company') {
32955      if (ownerCompanyId === '' || ownerCompanyId.length == 0) {
32956        ownerCompanyIdEl.parent().addClass('has-error');
32957        errors += $.translate('id is invalid') + '\n';
32958      } else {
32959        ownerCompanyIdEl.parent().removeClass('has-error');
32960      }
32961    }
32962
32963    if (priPhone === '' || priPhone.length < 8 || phone1 === '' || phone2 === '' || phone3 === '') {
32964      priPhoneEl.parent().addClass('has-error');
32965      errors += $.translate('Primary phone is required') + '\n';
32966    }
32967    else {
32968      priPhoneEl.parent().removeClass('has-error');
32969    }
32970    if (street === '' || street.length < 2 || !/[0-9]/.test(street)) {
32971      streetEl.parent().addClass('has-error');
32972      errors += $.translate('Street is required') + '\n';
32973    }
32974    else {
32975      streetEl.parent().removeClass('has-error');
32976    }
32977    if (city === '' || !stringRe.test(city)) {
32978      cityEl.parent().addClass('has-error');
32979      errors += $.translate('City is required') + '\n';
32980    }
32981    else {
32982      cityEl.parent().removeClass('has-error');
32983    }
32984    if (country === '' || !stringRe.test(country)) {
32985      countryEl.parent().addClass('has-error');
32986      errors += $.translate('Country is required') + '\n';
32987    }
32988    else {
32989      countryEl.parent().removeClass('has-error');
32990    }
32991    if (zip === '') {
32992      zipEl.parent().addClass('has-error');
32993      errors += $.translate('Zip is required') + '\n';
32994    }
32995    else {
32996      zipEl.parent().removeClass('has-error');
32997    }
32998
32999    if (nsvals.length > 0) {
33000      $.each(nsvals, function (i) {
33001        if (nsvals[i] !== '' || !urlRe.test(nsvals[i])) {
33002          ns.parent().removeClass('has-error');
33003        }
33004        else {
33005          ns.parent().addClass('has-error');
33006          errors += $.translate('you must fill at least one correct Name Server') + '\n';
33007        }
33008      });
33009    }
33010    else {
33011      errors += $.translate('you must fill at least one Name Server') + '\n';
33012      ns.parent().addClass('has-error');
33013    }
33014    if (errors !== '') {
33015      $('#info-errors').html(nl2br(errors, true)).removeClass('hidden');
33016      window.scrollTo(0, 0);
33017      return false;
33018    } else {
33019      purchaseSubmitting = true;
33020      $('#infoSubmit').button('loading');
33021      $('#info-errors').addClass('hidden');
33022      $.post($('#domain_order form').attr('action'), $('#domain_order form').serialize(), function (data) {
33023        if (data.status === 0) {
33024            $.showError(nl2br(data.msg, true));
33025
33026            purchaseSubmitting = false;
33027            $('#infoSubmit').button('reset');
33028        }
33029
33030        if (data.status === 1) {
33031          $('#main-content').html(data.msg);
33032          window.location = Storage.getData('app_url') + data.page;
33033        }
33034
33035        if (data.status == 2) {
33036          window.location = window.location;
33037        }
33038      }).fail(function () {
33039        purchaseSubmitting = false;
33040        $('#infoSubmit').button('reset');
33041        $.showError($.translate('unkown error occured'));
33042      });
33043    }
33044  });
33045
33046})(jQuery);
33047
33048/**
33049 * HERE address lookup expander for unified registration form.
33050 * PHP/jQuery era compatible (no ES6).
33051 */
33052;(function($) {
33053  'use strict';
33054
33055  function getConfig() {
33056    var cfg = Storage.getData('here_geocode', {});
33057    if (!cfg || typeof cfg !== 'object') {
33058      cfg = {};
33059    }
33060    return cfg;
33061  }
33062
33063  function translate(key) {
33064    if ($.translate) {
33065      return $.translate(key);
33066    }
33067    return key;
33068  }
33069
33070  function appUrl(path) {
33071    var base = Storage.getData('app_url', '/');
33072    if (base.charAt(base.length - 1) !== '/') {
33073      base += '/';
33074    }
33075    return base + path.replace(/^\//, '');
33076  }
33077
33078  function isEnabled() {
33079    var cfg = getConfig();
33080    return !!(cfg.enabled);
33081  }
33082
33083  function RegisterAddressLookup($form) {
33084    this.$form = $form;
33085    this.$wrap = $form.find('.js-register-address');
33086    this.$toggle = this.$wrap.find('.js-address-lookup-toggle');
33087    this.$toggleLabel = this.$wrap.find('.js-address-lookup-toggle-label');
33088    this.$panel = this.$wrap.find('.js-address-lookup-panel');
33089    this.$input = this.$wrap.find('#register-address-lookup-q');
33090    this.$results = this.$wrap.find('.js-address-lookup-results');
33091    this.$msg = this.$wrap.find('.js-address-lookup-msg');
33092    this.$searchBtn = this.$wrap.find('.js-address-lookup-search');
33093    this.open = false;
33094
33095    if (!this.$wrap.length || this.$wrap.attr('data-address-lookup') !== '1' || !this.$panel.length) {
33096      return;
33097    }
33098
33099    this.bind();
33100  }
33101
33102  RegisterAddressLookup.prototype.bind = function() {
33103    var self = this;
33104
33105    this.$toggle.on('click', function(e) {
33106      e.preventDefault();
33107      if (!self.open && !isEnabled()) {
33108        alert(translate('Address lookup limit reached. Please fill the address manually.'));
33109        return;
33110      }
33111      self.setOpen(!self.open);
33112    });
33113
33114    this.$searchBtn.on('click', function(e) {
33115      e.preventDefault();
33116      self.search();
33117    });
33118
33119    this.$input.on('keydown', function(e) {
33120      if (e.keyCode === 13) {
33121        e.preventDefault();
33122        self.search();
33123      }
33124    });
33125
33126    this.$results.on('click', '.js-address-lookup-pick', function(e) {
33127      e.preventDefault();
33128      var address = $(this).data('address');
33129      if (!address) {
33130        return;
33131      }
33132      self.applyAddress(address);
33133      self.$results.find('.js-address-lookup-pick').removeClass('is-selected');
33134      $(this).addClass('is-selected');
33135      self.setOpen(false);
33136    });
33137  };
33138
33139  RegisterAddressLookup.prototype.setOpen = function(open) {
33140    this.open = !!open;
33141    this.$panel.toggleClass('hidden', !this.open);
33142    this.$toggle.toggleClass('is-open', this.open);
33143    this.$wrap.toggleClass('address-lookup-expanded', this.open);
33144
33145    var label = this.open
33146      ? this.$toggle.attr('data-label-close')
33147      : this.$toggle.attr('data-label-open');
33148    if (label) {
33149      this.$toggleLabel.text(label);
33150    }
33151
33152    if (this.open) {
33153      this.showMessage('');
33154      var self = this;
33155      setTimeout(function() {
33156        self.$input.focus();
33157      }, 50);
33158    } else {
33159      this.$results.empty();
33160      this.showMessage('');
33161    }
33162  };
33163
33164  RegisterAddressLookup.prototype.showMessage = function(text) {
33165    if (!text) {
33166      this.$msg.addClass('hidden').text('');
33167      return;
33168    }
33169    this.$msg.removeClass('hidden').text(text);
33170  };
33171
33172  RegisterAddressLookup.prototype.search = function() {
33173    var self = this;
33174    var q = $.trim(this.$input.val() || '');
33175
33176    if (!isEnabled()) {
33177      this.showMessage(translate('Address lookup limit reached. Please fill the address manually.'));
33178      return;
33179    }
33180
33181    if (q.length < 3) {
33182      this.showMessage(translate('Please enter a more complete address.'));
33183      return;
33184    }
33185
33186    this.showMessage('');
33187    this.$results.empty();
33188    this.$searchBtn.prop('disabled', true);
33189    if (this.$searchBtn.button) {
33190      this.$searchBtn.button('loading');
33191    }
33192
33193    $.ajax({
33194      url: appUrl('address-lookup/geocode'),
33195      type: 'POST',
33196      dataType: 'json',
33197      data: {
33198        q: q,
33199        csrf_token: self.$form.find('[name=csrf_token]').val(),
33200        csrf_token_name: self.$form.find('[name=csrf_token_name]').val()
33201      }
33202    }).done(function(response) {
33203      if (!response) {
33204        self.showMessage(translate('Address lookup failed. Please fill manually.'));
33205        return;
33206      }
33207
33208      if (response.status !== 1) {
33209        self.showMessage(response.msg || translate('Address lookup failed. Please fill manually.'));
33210        return;
33211      }
33212
33213      var results = response.results || [];
33214      if (!results.length) {
33215        self.showMessage(translate('No addresses found. Try a different query or fill manually.'));
33216        return;
33217      }
33218
33219      self.renderResults(results);
33220    }).fail(function() {
33221      self.showMessage(translate('Address lookup failed. Please fill manually.'));
33222    }).always(function() {
33223      self.$searchBtn.prop('disabled', false);
33224      if (self.$searchBtn.button) {
33225        self.$searchBtn.button('reset');
33226      }
33227    });
33228  };
33229
33230  RegisterAddressLookup.prototype.renderResults = function(results) {
33231    var self = this;
33232    this.$results.empty();
33233
33234    $.each(results, function(_, item) {
33235      var label = item.label || (item.street + ', ' + item.city);
33236      var $btn = $('<button type="button" class="list-group-item js-address-lookup-pick"></button>');
33237      $btn.text(label);
33238      $btn.data('address', item);
33239      self.$results.append($btn);
33240    });
33241  };
33242
33243  RegisterAddressLookup.prototype.applyAddress = function(address) {
33244    if (!address) {
33245      return;
33246    }
33247
33248    var $street = this.$form.find('#user-auth-register-street');
33249    var $number = this.$form.find('#user-auth-register-number');
33250    var $city = this.$form.find('#user-auth-register-city');
33251    var $zip = this.$form.find('#user-auth-register-zip');
33252    var $country = this.$form.find('#user-auth-register-country');
33253
33254    if ($street.length) {
33255      $street.val(address.street_name || address.street || '').trigger('change');
33256    }
33257    if ($number.length) {
33258      $number.val(address.street_number || '').trigger('change');
33259    }
33260    if ($city.length && address.city) {
33261      $city.val(address.city).trigger('change');
33262    }
33263    if ($zip.length && address.zip) {
33264      $zip.val(address.zip).trigger('change');
33265    }
33266    if ($country.length && address.country) {
33267      $country.val(address.country).trigger('change');
33268      if ($country.hasClass('select2-hidden-accessible') || $country.data('select2')) {
33269        $country.trigger('change.select2');
33270      }
33271    }
33272  };
33273
33274  $(function() {
33275    var $form = $('#user-auth-register').find('form.js-register-form');
33276    if ($form.length && isEnabled()) {
33277      new RegisterAddressLookup($form);
33278    }
33279  });
33280})(jQuery);
33281
33282/**
33283 * This file is part of the box.co.il project.
33284
33285 * (c) Alex Buturlakin [email protected]
33286 */
33287
33288;(function($) {
33289
33290  // Enable ALL jquery plugins here
33291  
33292  // enable select2
33293  $(document).ready(function () {
33294    $('.select2').each(function() {
33295      // select2
33296      var select2 = $(this).select2({
33297        dir: "rtl",
33298        allowClear: false,
33299        language: "he",
33300        //placeholder: '', ??
33301        minimumResultsForSearch: 0,
33302        width: '100%',
33303        // maximumSelectionLength: 10,
33304        containerCssClass: 'select2-box-theme',
33305        dropdownCssClass:  'select2-box-theme'
33306      }).css("max-height","400px");
33307
33308      // add focus events
33309      // select2.next(".select2").find(".select2-selection").focus(function() {
33310      //   select2.select2("open");
33311      // });
33312
33313      // add scroll bar
33314      var scrollContent;
33315      select2.on('select2:open', function () {
33316
33317        if(scrollContent) {
33318          return true;
33319        }
33320
33321        // show scroll bar
33322        scrollContent = $('.select2-container--open .select2-results>ul').niceScroll({
33323          autohidemode: false,
33324          cursorcolor: '#565656',
33325          cursorwidth: 5,
33326          rtlmode: true,
33327          railalign:'left',
33328          cursorborder: '1px solid #e6e6e6',
33329          // rtlmode:true,
33330          hwacceleration:false,
33331          cursorminheight: 54
33332        });
33333      });
33334    });
33335  });
33336
33337  // enable qtip2
33338  $(document).ready(function () {
33339
33340    /**
33341     * Get get value from element data attribute.
33342     *
33343     * @param {String} name
33344     * @param {String} [defaultTitle]
33345     */
33346    var getQtipData = function(name, defaultTitle) {
33347      defaultTitle = defaultTitle || null;
33348      var title    = this.data(name);
33349
33350      if (typeof title === typeof undefined || title === false) {
33351        return defaultTitle;
33352      }
33353
33354      return title;
33355    };
33356
33357    /**
33358     * Get validation text.
33359     */
33360    var getQtipValidationText = function() {
33361      var list    = this.getValidationRulesList();
33362      var valName = getQtipData.call(this, 'qtip2-validation-name');
33363      var html    = '';
33364
33365      // generate html for ul li element
33366      var generateLIHtml = function (rule, message) {
33367        var html     = '';
33368        var template = '<li data-rule="{0}">{1}</li>';
33369
33370        // if rule has more than one messages
33371        if(Array.isArray(message)) {
33372          for(var k in message) {
33373            html += template.format(rule, message[k])
33374          }
33375        } else {
33376          html = template.format(rule, message);
33377        }
33378
33379        return html;
33380      };
33381
33382      // if no validation rules added for element
33383      if(0 === Object.keys(list).length) {
33384        return false;
33385      }
33386
33387      // generate html for ul element
33388      html = '<ul class="qtip2-validation-content">';
33389
33390      // default messages (not from rules). Can be separated by |||
33391      if(valName) {
33392        var vna = valName.split('|||');
33393
33394        for(var n in vna) {
33395          html += generateLIHtml('rule-default', vna[n]);
33396        }
33397      }
33398
33399      // all rules messages
33400      $.each(list, function (rule, message) {
33401        if(false == message || '' == message) {
33402          return true;
33403        }
33404
33405        html += generateLIHtml(rule, message);
33406      });
33407
33408      return html + '</ul>';
33409    };
33410
33411    // form validation qtip
33412    $('.validation input:not(.validation-disable-qtip), .validation select:not(.validation-disable-qtip)').each(function() {
33413      var el       = $(this);
33414      var title    = getQtipData.call(el, 'qtip2-title', $.translate('This Field Must Contain:'));
33415      var adjustX  = getQtipData.call(el, 'qtip2-x', -51);
33416      var text     = getQtipValidationText.call(el);
33417
33418      el.qtip({
33419        content: {
33420          text: text,
33421          title: function () { return title }
33422        },
33423        hide: {
33424          event: 'blur select2:close'
33425        },
33426        show: {
33427          event: 'focus select2:open'
33428        },
33429        style: {
33430          classes: 'qtip-box-form-validation qtip-bootstrap',
33431          tip: false
33432        },
33433        position: {
33434          my: 'top right',
33435          at: 'top left',
33436          adjust: {
33437            x: adjustX
33438          }
33439        }
33440      });
33441
33442      if(el.hasClass('has-predefined-value')) {
33443        el.qtip('disable');
33444      }
33445
33446      // fix for checkboxes
33447      if('checkbox' == el.attr('type')) {
33448        el.on('focus', function() {
33449          el.qtip('disable', false);
33450          el.qtip('show');
33451        });
33452      }
33453    });
33454  });
33455
33456
33457  // enable fancy box
33458  // ??
33459
33460})(jQuery);
33461
33462/**
33463 * This file is part of the box.co.il project.
33464
33465 * (c) Alex Buturlakin [email protected]
33466 */
33467;(function($) {
33468  $(document).ready(function() {
33469
33470    // enable or disable blocks by click in switch link
33471    jQuery(document).on('click', '.link-switch', function (e) {
33472      var el     = $(this),
33473          open   = el.data('switch-open')    || '',
33474          toggle = el.data('switch-toggle')  || '',
33475          close  = el.data('switch-close')   || '';
33476
33477      open   = $(open);
33478      close  = $(close);
33479      toggle = $(toggle);
33480
33481      toggle.toggleClass('hidden');
33482      open.removeClass('hidden');
33483      close.addClass('hidden');
33484
33485      e.preventDefault();
33486    });
33487
33488    // populate form default values
33489    $('.populate-default-values').on('change', function() {
33490      var el        = $(this),
33491          selector  = el.data('populate-in'),
33492          container = typeof selector === typeof undefined || selector === false ? el.closest('form') : $(selector),
33493          name      = el.attr('name'),
33494          exclude   = el.data('populate-exclude');
33495
33496      exclude = typeof exclude === typeof undefined || exclude === false ? [] : exclude.split('|');
33497
33498      // add current el to exclude
33499      if(typeof name !== typeof undefined) {
33500        exclude.push(name);
33501      }
33502      
33503      if(1 == container.length) {
33504        if(undefined != el.prop('tagName') && 'select' == el.prop('tagName').toLowerCase()) {
33505          container.populateDefaultDataSelect(el.find('option:selected'), exclude);
33506        } else {
33507          container.populateDefaultData(el.prop('checked'), exclude);
33508        }
33509      }
33510    });
33511
33512    // add/remove tel2 select box
33513    $('.tel-3').on('keyup', function() {
33514      var el   = $(this),
33515          selector  = el.data('tel-in'),
33516          container = typeof selector === typeof undefined || selector === false ? el.closest('form') : $(selector),
33517          tel2      = container.find('.tel-2').closest('.form-control-inner'),
33518          tel4      = container.find('.tel-4').closest('.form-control-inner');
33519
33520      // fast fix for compatibility on different pages
33521      if(0 == tel2.length) {
33522        tel2 = container.find('.tel-2');
33523        tel4 = container.find('.tel-4');
33524      }
33525      
33526      // if is Israel number
33527      if('972' == el.val() && tel2.hasClass('hidden')) {
33528        tel2.removeClass('hidden');
33529        tel4.addClass('hidden');
33530      }
33531
33532      // not Israel number
33533      if('972' != el.val() && tel4.hasClass('hidden')) {
33534        tel4.removeClass('hidden');
33535        tel2.addClass('hidden');
33536      }
33537    }).on('default-data-populated', function() {
33538      $(this).keyup();
33539    });
33540
33541    // open support window
33542    $('.zendesk-open-window').click(function() {
33543      zE('messenger', 'open');
33544
33545      return false;
33546    });
33547
33548  });
33549})(jQuery);
33550/**
33551 * This file is part of the box.co.il project.
33552
33553 * (c) Alex Buturlakin [email protected]
33554 */
33555// todo@alexbuturlakin: this file was created from inlined code in main.php template. Looks like it need some refactoring.
33556;(function($) {
33557  $(document).ready(function() {
33558    $(".domainsCheck .option:not(.current)").each(function() {
33559      var zone = $(this).attr("data-tld");
33560      var dom = $(this).attr("data-domain");
33561      var domain_id = $(this).attr("data-domain-id");
33562      $(this).attr('id', 'id'+zone);
33563      var domain = dom + zone;
33564
33565      var csrfToken     = $(this).find('[name=csrf_token]').val(),
33566          csrfTokenName = $(this).find('[name=csrf_token_name]').val()
33567      ;
33568
33569      if (dom.length <= 2 || dom.indexOf(' ') != -1 || $(this).hasClass('sld-not-valid')) {
33570        $(this).find('.progressWhois').css('display','none');
33571        $(this).find('.NotSupported').css('display','block');
33572        $(this).find('.delayed').css('display','none');
33573        // $('#ok').attr('class','hidden');
33574        // $('#error').removeClass('hidden');
33575      } else {
33576        check_domain(domain_id, domain,csrfTokenName, csrfToken);
33577      }
33578    });
33579
33580    var checkDomainFail = function(domain_id) {
33581      $('#whois_'+domain_id).css('display','none');
33582      var id = '#taken_'+domain_id;
33583      $(id).removeClass('hidden');
33584    };
33585
33586    var checkDomainSuccess = function(domain_id) {
33587      $('#whois_'+domain_id).addClass('hidden');
33588      var id = '#avilable_'+domain_id;
33589      $(id).removeClass('hidden');
33590    };
33591
33592    function check_domain(domain_id, domain, tokenName, token) {
33593      var
33594        csrfConfig   = Storage.getData('csrf_config'),
33595        tokenKey     = csrfConfig['token_key'],
33596        tokenNameKey = csrfConfig['token_name_key'],
33597        data         = {}
33598      ;
33599
33600      // set request data
33601      data['domain']     = domain;
33602      data[tokenKey]     = token;
33603      data[tokenNameKey] = tokenName;
33604
33605      $.ajax({
33606        url: "/domainsCheck/",
33607        type: "GET",
33608        data: data,
33609        success: function(data) {
33610          if(true == data['free']) {
33611            checkDomainSuccess(domain_id);
33612          } else {
33613            checkDomainFail(domain_id);
33614          }
33615        },
33616        error: function () {
33617          checkDomainFail(domain_id);
33618        }
33619      });
33620    }
33621
33622    $(".check_btn").click(function() {
33623      var layer = $(this).closest(".option");
33624
33625      var zone = layer.attr("data-tld");
33626      var dom = layer.attr("data-domain");
33627      var domain_id = layer.attr("data-domain-id");
33628      layer.attr('id', 'id'+zone);
33629      var domain = dom + zone;
33630      layer.find(".delayed").hide();
33631      layer.find(".progressWhois").show();
33632
33633      check_domain(domain_id, domain);
33634    });
33635  });
33636})(jQuery);
33637
33638/**
33639 * This file is part of the box.co.il project.
33640
33641 * (c) Alex Buturlakin [email protected]
33642 */
33643// todo@alexbuturlakin: this file was created from inlined code in domain/info.php template. Looks like it need some refactoring (rm -rf ??).
33644;(function($) {
33645  // hm... may be need to remove this
33646  if (typeof(ctype_print) != "function") {
33647    function ctype_print(str) {
33648      var allowed = 'abcdefghijklmnopqrstuvwxyz0123456789*!@#$%^?:&*~=_.,<>{}"|-;`+()[]/\\\' ';
33649      allowed = allowed.split('');
33650      var chars = str.split('');
33651      var status = true;
33652      for (var i = 0; i < chars.length; i++) {
33653        var singleChar = chars[i].toLowerCase();
33654        if (allowed.indexOf(singleChar) === -1) {
33655          status = false;
33656          break;
33657        }
33658      }
33659      return status;
33660    }
33661  }
33662
33663  $(document).ready(function() {
33664    var isNotifiedAboutPremium = false;
33665
33666    // select domain purchase period
33667    $('input[name=domainPeriod]').change(function () {
33668      var el          = $(this),
33669          validation  = el.closest('label').siblings('.validation'),
33670          success     = validation.find('.ok'),
33671          cardDetails = $('#creditCardDetails');
33672
33673      // show success message
33674      if(success.hasClass('hidden')) {
33675        // hide error
33676        validation.find('.error').addClass('hidden');
33677
33678        // show success message
33679        success.removeClass('hidden');
33680      }
33681
33682      // change message
33683      success.find('span>span').html(' ' + el.data('date'));
33684
33685      // update price info
33686      $.updateTotalPrice();
33687
33688      // clean card form fields
33689      cardDetails.resetForm();
33690      $('#cpn-error').addClass('hidden');
33691
33692      isReadyToBuy();
33693    });
33694
33695    // change label by selected client type
33696    $('#ownerModal').find('[name="clientType"]').on('change', function() {
33697      var el        = $(this),
33698          val       = el.val(),
33699          container = el.closest('.modal-body'),
33700          label     = container.find('[for="ownerFullName"]'),
33701          input     = container.find('[name="ownerFullName"]');
33702
33703      // set label and placeholder
33704      label.find('span').html(input.data('label-{0}'.format(val)));
33705      input.attr('placeholder', input.data('placeholder-{0}'.format(val)));
33706
33707      // Change validation rules for owner name
33708      var nameValidation = 'clientTypeCompany' === el.attr('id')
33709        ? window.validationRules.purchaseDomainRulesOwnerName.company
33710        : window.validationRules.purchaseDomainRulesOwnerName.user
33711      ;
33712
33713      el.closest('form').validatorChangeFieldRules('ownerFullName', nameValidation.rules, nameValidation.messages);
33714
33715      // clear input
33716      input.val('');
33717
33718      container.find('.form-group-{0}'.format(val)).removeClass('hidden');
33719      container.find('.form-group-{0}'.format('company' === val ? 'private' : 'company')).addClass('hidden');
33720    });
33721
33722    $('#ownerCompanyId').on('default-data-populated', function() {
33723      if ($('input[name=clientType]:checked').val() == 'company') {
33724        $(this).closest('.form-group-company').removeClass('hidden');
33725      }
33726    });
33727
33728    $('input[name=clientType]').change(function () {
33729      var name = $('#ownerFullName');
33730      if ($('input[name=clientType]:checked').val() == 'company' && $('#ownerFullName').val() != '') {
33731        if (!stristr(name.val(), 'LTD')) {
33732          name.val(name.val().trim() + ' LTD');
33733        }
33734      } else {
33735        name.val(name.val().replace('LTD', '').trim());
33736      }
33737    });
33738
33739    $('input[name=ownerFullName]').focusout(function () {
33740      var name = $('#ownerFullName');
33741      if ($('input[name=clientType]:checked').val() == 'company' && $('#ownerFullName').val() != '') {
33742        if (!stristr(name.val(), 'LTD')) {
33743          name.val(name.val().trim() + ' LTD');
33744        }
33745      } else {
33746        name.val(name.val().replace('LTD', '').trim());
33747      }
33748    });
33749
33750    $('input[name=dnsType]').change(function () {
33751      var val = $('input[name=dnsType]:checked').val();
33752      if (val == 'adv') {
33753        $('input.names').each(function () {
33754          $(this).val($(this).attr('data-value'));
33755        });
33756
33757        $('#dnsAdv').show();
33758      }
33759
33760      if ('cloud' == val) {
33761        $('#dnsAdv').hide();
33762
33763        $('input.names').each(function () {
33764          $(this).val($(this).attr('data-value-cloud'));
33765        });
33766      }
33767
33768      if (val == 'default') {
33769        $('#dnsAdv').hide();
33770        $('input.names').each(function () {
33771          $(this).val($(this).attr('data-value'));
33772        });
33773      }
33774    });
33775
33776    $('#creditCardDetails .cvvhelp').hover(function () {
33777      $(this).find('img').show();
33778    }, function () {
33779      $(this).find('img').hide();
33780    });
33781
33782    $('#domainCheckout').click(function () {
33783      var el   = $(this),
33784          next = el.attr('data-next');
33785      if (isReadyToBuy()) {
33786        if('email-account' === next) {
33787          var eaBlock = $('#domain-purchase-email-account');
33788          eaBlock.removeClass('hidden');
33789          $(document).scrollTop(eaBlock.offset().top-100);
33790          // $([document.documentElement, document.body]).animate({
33791          //     scrollTop: $('.form-group.isReady').offset().top+550
33792          // }, 2000);
33793        }
33794
33795        if('card-data' === next) {
33796          $('#creditCardDetails').removeClass('hidden');
33797
33798          $('.show-tooltip').addTooltip();
33799
33800          $.updateTotalPrice();
33801          $(document).scrollTop($('#domainCheckout').offset().top+100);
33802
33803          // $([document.documentElement, document.body]).animate({
33804          //     scrollTop: $(".form-group.isReady").offset().top+600
33805          // }, 2000);
33806
33807        }
33808      }
33809    });
33810
33811    // step 2
33812    $('#domain-purchase-email-account-accept').click(function() {
33813      $('#domain-purchase-cashback').removeClass('hidden');
33814      $(document).scrollTop($('#domain-purchase-cashback').offset().top);
33815    });
33816
33817    $('#domain-purchase-owner-email-verify-accept').click(function() {
33818      var valid = true;
33819
33820      if (!$('#ownerEmailVerificationCode').val() || $('#ownerEmailVerificationCode').val().length != 8) {
33821        $('#domain-purchase-owner-email-verify-errors').html($.translate('Email verification code is invalid')).removeClass('hidden');
33822        valid = false;
33823      }
33824
33825      if (isReadyToBuy() && valid) {
33826        $('#domain-purchase-owner-email-verify-errors').addClass('hidden');
33827        $('#creditCardDetails').removeClass('hidden');
33828        $.updateTotalPrice();
33829        $(document).scrollTop($('#creditCardDetails').offset().top);
33830        // $([document.documentElement, document.body]).animate({
33831        //     scrollTop: $('.form-group.isReady').offset().top+300
33832        // }, 1000);
33833        // notify user about premium domain
33834
33835        $('.show-tooltip').addTooltip();
33836
33837
33838        if (true === Storage.getData('isPremiumDomain') && false == isNotifiedAboutPremium) {
33839          $.showSuccess(
33840            $.translate('Premium Domain Purchasing'),
33841            Storage.getData('premiumMessage'),
33842            false,
33843            true
33844          );
33845
33846          isNotifiedAboutPremium = true;
33847        }
33848      }
33849    });
33850
33851    $('#domain-purchase-email-accounts-decline').click(function() {
33852      $('#domain-purchase-email-account input[type=checkbox]').prop('checked', false);
33853      $('#domain-purchase-email-account').addClass('hidden');
33854
33855      $('#domain-purchase-cashback').removeClass('hidden');
33856    });
33857
33858    $('#domain-purchase-promo-accept').click(function() {
33859      $('.domainCashback').val('true')
33860      emailVerify(true)
33861    });
33862
33863    $('#domain-purchase-promo-decline').click(function() {
33864      $('.domainCashback').val('false')
33865      $('#domain-purchase-cashback').addClass('hidden')
33866      emailVerify(false)
33867    });
33868
33869    function emailVerify(scroll){
33870      if (isReadyToBuy()) {
33871        if ($('#domain-purchase-owner-email-verify').length) {
33872          $('#domain-purchase-owner-email-verify').removeClass('hidden');
33873          $('#domain-purchase-owner-email-verify-send-email span').text(' ' + $('#ownerEmail').val());
33874
33875          if(scroll){
33876            $(document).scrollTop($('#domain-purchase-owner-email-verify').offset().top - 100);
33877          }
33878        } else {
33879          $('#creditCardDetails').removeClass('hidden');
33880          $.updateTotalPrice();
33881
33882          if(scroll){
33883            $(document).scrollTop($('#creditCardDetails').offset().top - 100);
33884          }
33885
33886          $('.show-tooltip').addTooltip();
33887
33888          if (true === Storage.getData('isPremiumDomain') && false == isNotifiedAboutPremium) {
33889            $.showSuccess(
33890              $.translate('Premium Domain Purchasing'),
33891              Storage.getData('premiumMessage'),
33892              false,
33893              true
33894            );
33895
33896            isNotifiedAboutPremium = true;
33897          }
33898        }
33899      }
33900    }
33901
33902    $('#domain-purchase-owner-email-verify-send-email,#form-domain-purchase-owner-email-verify-resend').click(function (e) {
33903      e.preventDefault();
33904      $('#domain-purchase-owner-email-verify-send-email').button('loading');
33905      $('#form-domain-purchase-owner-email-verify-resend').button('loading');
33906
33907      $.ajax({
33908        url: '/domain-email-verify/purchase',
33909        type: 'POST',
33910        data: {
33911          'email': $('#ownerEmail').val()
33912        },
33913        success: function (response) {
33914          if (0 == response.status) {
33915            $('#domain-purchase-owner-email-verify-errors').html(nl2br(response.msg, true)).removeClass('hidden');
33916            $('#domain-purchase-owner-email-verify-send-email').button('reset');
33917            $('#form-domain-purchase-owner-email-verify-resend').button('reset');
33918          }
33919
33920          if (1 == response.status) {
33921            $('.domain-purchase-owner-email-verify-step-1').addClass('hidden');
33922            $('.domain-purchase-owner-email-verify-step-2').removeClass('hidden');
33923            $('#domain-purchase-owner-email-verify-send-email').button('reset');
33924            $('#form-domain-purchase-owner-email-verify-resend').button('reset');
33925          }
33926        },
33927        error: function (xhr) {
33928          if (403 === xhr.status) {
33929            window.location.href = '/user/login';
33930          }
33931
33932          $('#domain-purchase-owner-email-verify-errors').html(xhr.responseJSON.error).removeClass('hidden');
33933        }
33934      });
33935    });
33936
33937    $('#domain-purchase-email-account').on('click', 'input[type=checkbox]', function() {
33938      var ec = $('#domain-purchase-email-account-errors');
33939
33940      ec.addClass('hidden');
33941    });
33942
33943    $('#domain-purchase-email-account .form-group > span').click(function () {
33944      $('#domain-purchase-email-account-text').focus();
33945    });
33946
33947    $('#domain-purchase-email-account-add').click(function() {
33948      var el      = $(this),
33949          input   = el.siblings('input'),
33950          value   = input.val(),
33951          proto   = el.attr('data-prototype'),
33952          eDomain = el.attr('data-email-domain'),
33953          cbBoxes = $('#domain-purchase-email-account input[type=checkbox]'),
33954          erCont  = $('#domain-purchase-email-account-errors'),
33955          cbCount = cbBoxes.length;
33956
33957      var validator    = $('#domain-purchase-form').data('validator'),
33958          emailAccount = value + eDomain,
33959          isValid      = validator._hooks.valid_email({'value': emailAccount});
33960
33961      erCont.addClass('hidden');
33962
33963      // todo@alexbuturlakin: need to refactor
33964      if(value && value.length > 0 && isValid) {
33965        if(isValid) {
33966          if($('#domain-purchase-email-account input[value="{0}"][type="checkbox"]'.format(emailAccount)).length > 0) {
33967            erCont
33968                .html($.translate('Email account with the same name already added'))
33969                .removeClass('hidden');
33970          } else {
33971            var cbNew = $(proto.format(cbCount, cbCount, value));
33972
33973            cbBoxes.last().parent().after(cbNew);
33974
33975            cbNew = $('#domain-purchase-email-account-{0}'.format(cbCount));
33976
33977            input.val('');
33978            cbNew.val(emailAccount);
33979
33980            if(9 === cbBoxes.length) {
33981              el.parent().remove();
33982            }
33983          }
33984        }
33985      } else {
33986        erCont
33987            .html($.translate('Only English letters (a-z), numbers, periods, @<br><span>Example: [email protected]</span>'))
33988            .removeClass('hidden');
33989      }
33990    });
33991  });
33992
33993  /**
33994   * Update total price
33995   */
33996  $.updateTotalPrice = function() {
33997    var title  = $('#creditCardDetails').find('.UISection > span'),
33998        period = parseInt($('input[name=domainPeriod]:checked').val()),
33999        total  = 0;
34000
34001    // update total price
34002    for (var i = 1; i < period + 1; i++) {
34003      var yearPrice = title.attr('data-price-{0}'.format(i));
34004
34005      if (undefined !== yearPrice) {
34006        total += parseFloat(yearPrice);
34007      }
34008    }
34009    perYear = total / period;
34010	  totalPerYear = Number(perYear).toFixed(2);
34011    // update total price
34012    title.find('span').html(Number(total).toFixed(2));
34013    $("#PriceperYear").html(totalPerYear);
34014  };
34015
34016})(jQuery);
34017
34018/**
34019 * This file is part of the "box" project.
34020 *
34021 * (c) Alex Buturlakin [email protected]
34022 */
34023;(function($) {
34024
34025  /**
34026   * Update checked checkboxes from storage.
34027   */
34028  $.bulkStorageUpdateCheckboxes = function () {
34029    var storage = $.localStorage,
34030        data    = storage.isSet('domains_bulk') ? storage.get('domains_bulk') : [];
34031
34032    // update all checkboxes
34033    $.each(data, function() {
34034      $('[data-domain="{0}"]'.format(this)).prop('checked', true);
34035    });
34036
34037    // update main bulk checkbox
34038    if(0  == $('.domain-bulk-op-item:not(:checked)').length && 0 != $('.domain-bulk-op-item:checked').length) {
34039      $('#domain-bulk-op-select-all').prop('checked', true);
34040    }
34041  };
34042
34043  /**
34044   * Update bulk control block
34045   */
34046  $.bulkStorageUpdateControl = function() {
34047    var storage     = $.localStorage,
34048        bulkControl = $('#domain-bulk-control'),
34049        data        = storage.isSet('domains_bulk') ? storage.get('domains_bulk') : [];
34050
34051    // update count of selected domains in table head
34052    0 == data.length ? bulkControl.addClass('hidden') : bulkControl.removeClass('hidden');
34053    bulkControl.find('span>span').html(data.length);
34054  };
34055
34056  /**
34057   * Clear selected domains.
34058   */
34059  $.bulkClearSelectedDomains = function() {
34060    $.localStorage.set('domains_bulk', []);
34061
34062    // uncheck checkboxes
34063    $('.domain-bulk-op-item').prop('checked', false);
34064    $('#domain-bulk-op-select-all').prop('checked', false);
34065
34066    // hide control block
34067    $.bulkStorageUpdateControl();
34068  };
34069
34070  /**
34071   * Get selected domains.
34072   *
34073   * @return {Array}
34074   */
34075  $.bulkGetSelectedDomains = function() {
34076    var checkboxes = $('.domain-bulk-op-item:checked'),
34077        storage    = $.localStorage,
34078        data       = storage.isSet('domains_bulk') ? storage.get('domains_bulk') : [],
34079        domains    = [];
34080
34081    $.each(checkboxes, function() {
34082      domains.push($(this).data('domain'));
34083    });
34084
34085    $.each(data, function() {
34086      if(-1 == $.inArray(this, domains)) {
34087        domains.push(this);
34088      }
34089    });
34090
34091    return domains;
34092  };
34093
34094  $(document).ready(function(e) {
34095
34096    // update checkboxes
34097    $.bulkStorageUpdateCheckboxes();
34098
34099    // update bulk control block
34100    $.bulkStorageUpdateControl();
34101
34102    // clear selected domains
34103    $('#domain-bulk-control').find('a').click(function(e) {
34104      $.bulkClearSelectedDomains();
34105
34106      e.preventDefault();
34107    });
34108
34109    // change domains per page
34110    $('#domains-per-page').change(function () {
34111      $.pageReload({'domains_qty': $(this).val()});
34112    });
34113
34114    // check/uncheck all checkboxes
34115    $('#domain-bulk-op-select-all').change(function () {
34116      $('.domain-bulk-op-item').not(':disabled').prop('checked', $(this).prop("checked"));
34117      $.bulkStorageDomainsUpdate();
34118    });
34119
34120    // update bulk control
34121    $('.domain-bulk-op-item').change(function () {
34122      $.bulkStorageDomainsUpdate();
34123    });
34124
34125    // bulk renew
34126    $('#domain-bulk-renew-action').click(function(e) {
34127      var el = $(this);
34128
34129      el.buttonLoading('loading');
34130
34131      // get selected domains
34132      var domains = $.bulkGetSelectedDomains();
34133
34134      // no domains selected
34135      if(0 == domains.length) {
34136        el.buttonLoading('reset');
34137
34138        $.showError($.translate('Please select domains.'));
34139
34140        e.preventDefault();
34141        return;
34142      }
34143
34144      // get form
34145      $.get(el.attr('href'), {domains: domains}, function(response) {
34146        el.buttonLoading('reset');
34147
34148        // if user is anonymous
34149        if(0 == response.status && undefined != response.page) {
34150          window.location = Storage.getData('app_url') + response.page;
34151
34152          return;
34153        }
34154
34155        // if error message and need to show errors
34156        if(0 == response.status && undefined != response.message) {
34157          $.showError(response.message);
34158
34159          return;
34160        }
34161
34162        // show form
34163        $.fancybox.open({
34164          type:    'iframe',
34165          padding: 0,
34166          content: response.html,
34167          afterShow: function () {
34168            // vars
34169            var form           = $('#renew-domain-bulk-op'),
34170                years          = form.find('input[type="radio"]'),
34171                domains        = form.find('#bulk-op-domains-list input[type="checkbox"]'),
34172                cvvHelp        = form.find('.cvvhelp'),
34173                cvvHelpImage   = form.find('.cvvhelp img'),
34174                checkCoupon    = form.find('#checkCoupon'),
34175                couponCode     = form.find('#couponCode');
34176                couponError    = form.find('#cpn-error'),
34177                couponMessage  = form.find('#cpnDis'),
34178                button         = $('button#renew');
34179
34180            // tooltips name
34181            $('.show-tooltip').addTooltip();
34182
34183            // cvv help image
34184            cvvHelp.hover(function () {
34185              cvvHelpImage.show();
34186            }, function () {
34187              cvvHelpImage.hide();
34188            });
34189
34190            // update price
34191            years.change(function() {
34192              $.bulkOpUpdatePrice(form, years, domains);
34193            });
34194
34195            domains.change(function() {
34196              $.bulkOpUpdatePrice(form, years, domains);
34197            });
34198
34199            $.bulkUpdateYearlyPrices();
34200
34201            // check coupon
34202            couponCode.on('keyup change', function() {
34203              var el = $(this), state = false;
34204
34205              if('' == el.val() || 0 == years.filter(':checked').length || 0 == domains.filter(':checked').length) {
34206                state = true;
34207              }
34208
34209              checkCoupon.prop('disabled', state);
34210            });
34211
34212            checkCoupon.click(function (e) {
34213              var code = $('#couponCode').val();
34214              checkCoupon.buttonLoading('loading');
34215
34216              $.get(Storage.getData('app_url') + 'checkCpn/' + code, '', function (response) {
34217                $.bulkOpUpdatePrice(form, years, domains, parseFloat(response));
34218
34219                checkCoupon.button('reset');
34220              });
34221            });
34222
34223            // submit form
34224            var bulkRenewSubmitting = false;
34225            form.on('submit', function() {
34226              e.preventDefault();
34227              if (bulkRenewSubmitting) return false;
34228              button.buttonLoading('loading');
34229
34230              // validate form
34231              var errors = $.domainBulkValidatePurchase(form);
34232
34233              // hide/show errors
34234              $.bulkOpShowErrors(form, errors, form.find('.modal-footer>div>div'));
34235
34236              if(errors.length > 0) {
34237                button.buttonLoading('reset');
34238
34239                return false;
34240              }
34241
34242              bulkRenewSubmitting = true;
34243
34244              // submit form
34245              var url      = Storage.getData('app_url') + 'domain/bulk-renew/submit';
34246              var postData = $(this).serialize();
34247
34248              $.post(url, postData, function (response) {
34249                bulkRenewSubmitting = false;
34250                button.buttonLoading('reset');
34251
34252                if (0 == response.status && undefined != response.premiumDomains) {
34253                  // show warning about new price
34254                  $.bulkOpShowWarnings(form, [{message: response.message}], form.find('.modal-footer>div>div'));
34255
34256                  // update form
34257                  $('#domain-purchase-is-premium').val(1);
34258
34259                  // update prices
34260                  $.each(response.premiumDomains, function(key, value) {
34261                    var domain = form.find('[name="domains[{0}]"]'.format(key));
34262
34263                    for (var year in value) {
34264                      domain.attr('data-price-{0}'.format(year), value[year])
34265                    }
34266                  });
34267
34268                  $.bulkOpUpdatePrice(form, years, domains);
34269                } else if (
34270                  undefined !== response.format
34271                  && undefined !== response.type
34272                  && 'popin' === response.format
34273                  && 'pendingRenew'  === response.type
34274                ) {
34275                  if (0 !== $('#domain-renew-confirm-pending-bulk').length) {
34276                    $('#domain-renew-confirm-pending-bulk').modal('show');
34277                  } else {
34278                    $(response.msg).modal('show');
34279                  }
34280                } else {
34281                  // show error message
34282                  if (0 == response.status && undefined != response.message) {
34283                    $.bulkOpShowErrors(form, [{message: response.message}], form.find('.modal-footer>div>div'));
34284                  }
34285
34286                  // do redirect
34287                  if(0 == response.status && undefined != response.page) {
34288                    window.location = Storage.getData('app_url') + response.page;
34289                  }
34290                }
34291
34292                // all is ok
34293                if (response.status == 1) {
34294                  $.fancybox.close();
34295                  $.bulkClearSelectedDomains();
34296
34297                  if(undefined != response.message && undefined != response.message.text && undefined != response.message.title) {
34298                    $.showSuccess(response.message.title, response.message.text);
34299                  }
34300                }
34301              }).fail(function () {
34302                bulkRenewSubmitting = false;
34303                button.buttonLoading('reset');
34304              });
34305
34306              return false;
34307            });
34308          }
34309        });
34310      });
34311
34312      e.preventDefault();
34313    });
34314
34315    // bulk op update price
34316    $.bulkOpUpdatePrice = function(form, years, domains, coupon) {
34317      $.bulkUpdateYearlyPrices();
34318
34319
34320      var years          = years.filter(':checked'),
34321          domains        = domains.filter(':checked'),
34322          price          = form.find('#domain-bulk-op-total-prise'),
34323          paymentSection = $('#renew-domain-bulk-op-payment-section'),
34324          couponError    = form.find('#cpn-error'),
34325          couponMessage  = form.find('#cpnDis'),
34326          checkCoupon    = form.find('#checkCoupon'),
34327          couponInput    = $('#couponCode');
34328
34329      // set default price
34330      if(0 == years.length || 0 == domains.length) {
34331        price.html('0.00');
34332
34333        return;
34334      }
34335
34336      // calculate price
34337      var totalYears = parseInt(years.val()),
34338          total      = 0
34339      ;
34340
34341      $.each(domains, function() {
34342        var
34343            domainPrice = 0
34344        ;
34345
34346        for (var i = 1; i < totalYears + 1; i++) {
34347          var yearPrice = $(this).attr('data-price-{0}'.format(i));
34348
34349          if (undefined !== yearPrice) {
34350            domainPrice += parseFloat(yearPrice);
34351          }
34352        }
34353
34354        total += domainPrice;
34355      });
34356
34357      price.html(Number(total).toFixed(2));
34358
34359      // coupon feature
34360      // no coupon defined - hide discount messages
34361      if(typeof undefined == typeof coupon) {
34362        couponError.addClass('hidden');
34363        couponMessage.addClass('hidden');
34364        paymentSection.removeClass('hidden');
34365        couponInput.val('');
34366        checkCoupon.prop('disabled', true);
34367      } else if (coupon <= 0) {
34368        // wrong response or wrong coupon - show error message
34369        couponError.removeClass('hidden');
34370        couponMessage.addClass('hidden');
34371        paymentSection.removeClass('hidden')
34372      } else {
34373        // all is ok
34374        couponError.addClass('hidden');
34375        couponMessage.removeClass('hidden');
34376
34377        // calculate discount
34378        var afterCoupon = total - coupon;
34379
34380        afterCoupon <= 0 ? paymentSection.addClass('hidden') : paymentSection.removeClass('hidden');
34381        form.find('#cpnDis .amount').html(total);
34382        form.find('#cpnDis .sum').html(afterCoupon >= 0 ? Number(afterCoupon).toFixed(2) : 0);
34383      }
34384    };
34385
34386    $.bulkUpdateYearlyPrices = function(){
34387      var form           = $('#renew-domain-bulk-op'),
34388          periods          = form.find('input[type="radio"]'),
34389          domains        = form.find('#bulk-op-domains-list input[type="checkbox"]').filter(':checked'),
34390          total = 0.0;
34391
34392      const periodValues = Array.from(periods).map(radio => parseInt(radio.value)).sort((a, b) => a - b);
34393
34394      periodValues.forEach(period => {
34395        //loop all selected domains
34396        $.each(domains, function() {
34397          var yearPrice = $(this).attr(`data-price-${period}`);
34398
34399          if (undefined !== yearPrice) {
34400            total += parseFloat(yearPrice);
34401          }
34402        });
34403
34404        $(`#price-total-year${period}`).html(Number(total).toFixed(2));
34405        $(`#price-per-year-year${period}`).html(Number(total/period).toFixed(2));
34406      })
34407    }
34408
34409    /**
34410     * Update bulk domains storage.
34411     */
34412    $.bulkStorageDomainsUpdate = function() {
34413      var storage     = $.localStorage,
34414          checked     = $('.domain-bulk-op-item:checked'),
34415          unchecked   = $('.domain-bulk-op-item:not(:checked)'),
34416          data        = storage.isSet('domains_bulk') ? storage.get('domains_bulk') : [];
34417
34418      // add checked domains
34419      $.each(checked, function() {
34420        var id = $(this).data('domain');
34421
34422        if(-1 == jQuery.inArray(id, data)) {
34423          data.push(id);
34424        }
34425      });
34426
34427      // remove unchecked
34428      $.each(unchecked, function() {
34429        var id = $(this).data('domain');
34430
34431        if(-1 != jQuery.inArray(id, data)) {
34432          var index = data.indexOf(id);
34433          data.splice(index, 1);
34434        }
34435      });
34436
34437      // update storage
34438      storage.set('domains_bulk', data);
34439
34440      // update control block
34441      $.bulkStorageUpdateControl();
34442    };
34443
34444    /**
34445     * Show errors
34446     * todo@alexbuturlakin: need to remove this method after validation will be refactored.
34447     *
34448     * @param {jQuery} form
34449     * @param {[]}     errors
34450     * @param {jQuery} el
34451     */
34452    $.bulkOpShowErrors = function(form, errors, el) {
34453      var messages = [];
34454
34455      // clear errors
34456      form.find('.has-error').removeClass('has-error');
34457      form.find('.alert-danger').remove();
34458
34459      $.each(errors, function(k, v) {
34460        if(undefined != v['el']) {
34461          $(v['el']).parent().addClass('has-error');
34462        }
34463
34464        messages.push(v['message']);
34465      });
34466
34467      if(messages.length > 0) {
34468        el.showAlert(messages.join('<br/>'), 'danger');
34469      }
34470    };
34471
34472    /**
34473     * Show errors
34474     * todo@alexbuturlakin: need to remove this method after validation will be refactored.
34475     *
34476     * @param {jQuery} form
34477     * @param {[]}     errors
34478     * @param {jQuery} el
34479     */
34480    $.bulkOpShowWarnings = function(form, errors, el) {
34481      var messages = [];
34482
34483      // clear warnings
34484      form.find('.alert-warning').remove();
34485
34486      $.each(errors, function(k, v) {
34487        if(undefined != v['el']) {
34488          $(v['el']).parent().addClass('has-error');
34489        }
34490
34491        messages.push(v['message']);
34492      });
34493
34494      if(messages.length > 0) {
34495        el.showAlert(messages.join('<br/>'), 'warning');
34496      }
34497    };
34498
34499    // validate card
34500    // todo@alexbuturlakin: this is hardcode from domain renew. Need to refactor and use plugin for validation.
34501    $.domainBulkValidatePurchase = function (form) {
34502      var creditReg = /^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|6(?:011|5[0-9]{2})[0-9]{12}|(?:2131|1800|35\d{3})\d{11})$/;
34503      var creditCardEl = form.find('#creditNumber');
34504      var creditYrEl = form.find('#creditExpirationYear');
34505      var creditMoEl = form.find('#creditExpirationMonth');
34506      var creditCardCvvEl = form.find('#creditCvv');
34507      var creditIdEl = form.find('#creditId');
34508      var domainPeriodEl = form.find('#domainPeriod');
34509      var date = new Date();
34510      var creditCard = creditCardEl.val();
34511      var creditCardYr = creditYrEl.val();
34512      var creditCardMo = creditMoEl.val();
34513      var creditCardCvv = creditCardCvvEl.val();
34514      var creditCardId = creditIdEl.val();
34515      var domainPeriod = parseInt($('[name=domainPeriod]:checked').val());
34516      var approve_termsEl = $('#approve_terms');
34517      var approve_terms = approve_termsEl.is(":checked");
34518      var errors = [];
34519
34520      var addError = function(el, message) {
34521        errors.push({el: el, message: message});
34522      };
34523
34524      if(approve_terms != undefined) {
34525        if (!approve_terms) {
34526          addError(approve_termsEl, $.translate('Approve Terms is required'));
34527        }
34528      }
34529
34530      if(false == $('#renew-domain-bulk-op-payment-section').hasClass('hidden')) {
34531        if (isNaN(creditCardYr) || parseInt(creditCardYr) < date.getFullYear()) {
34532          addError(creditYrEl, $.translate('Expiry Year is invali
34532d'));
34533        }
34534
34535        if (isNaN(creditCardMo) || creditCardYr == date.getFullYear() && creditCardMo < date.getMonth()) {
34536          addError(creditMoEl, $.translate('Expiry Month is invalid'));
34537        }
34538
34539        if (isNaN(creditCardCvv) || creditCardCvv.length < 3 || creditCardCvv.length > 4) {
34540          addError(creditCardCvvEl, $.translate('cvv is invalid'));
34541        }
34542
34543        if (isNaN(creditCardId) || creditCardId.length < 9 || creditCardId.length > 9) {
34544          addError(creditIdEl, $.translate('id is invalid'));
34545        }
34546
34547        if (isNaN(creditCard) || creditCard.length < 9 || creditCard.length > 17 || !creditReg.test(creditCard) && creditCard.length > 9 || creditCard[0] === 0) {
34548          addError(creditCardEl, $.translate('card is invalid'));
34549        }
34550      }
34551
34552      if (domainPeriod < 1 && domainPeriod > 5) {
34553        addError(domainPeriodEl, $.translate('Domain Period is invalid'));
34554      }
34555      return errors;
34556    };
34557
34558    $(document).on('click', '#domain-renew-confirm-bulk-confirm', function() {
34559      $('#domain-renew-confirm-pending-bulk').modal('hide');
34560      $('#domain-renew-pending-confirmed').val(1);
34561      $('#renew').trigger('click');
34562    });
34563
34564    $(document).on('click', '#domain-renew-confirm-bulk-cancel', function() {
34565      $('#domain-renew-confirm-pending-bulk').modal('hide');
34566    });
34567
34568  });
34569})(jQuery);
34570
34571/**
34572 * This file is part of the "box" project.
34573 *
34574 * (c) Alex Buturlakin [email protected]
34575 */
34576
34577;(function($) {
34578
34579  // copy - paste from main.js, this code needs refactoring
34580  function validateContact(form) {
34581    var priPhoneEl = form.find('#contactLanding');
34582    var contactFax = form.find('#contactFax');
34583    var streetEl   = form.find('#contactStreet');
34584    var cityEl     = form.find('#contactCity');
34585    var countryEl  = form.find('#contactCountry');
34586    var zipEl      = form.find('#contactZip');
34587
34588    if(0 == priPhoneEl.length && 0 == contactFax.length && 0 == cityEl.length) {
34589      return true;
34590    }
34591
34592    var street     = streetEl.val();
34593    var city       = cityEl.val();
34594    var country    = countryEl.val();
34595    var zip        = zipEl.val();
34596    var phone1     = form.find('#tel1').val();
34597    var phone2     = form.find('#tel2').val(validatePerf(form.find('#tel2').val())).val();
34598    var phone3     = form.find('#tel3').val();
34599    var fax1       = form.find('#fax1').val();
34600    var fax2       = form.find('#fax2').val(validatePerf(form.find('#fax2').val())).val();
34601    var fax3       = form.find('#fax3').val();
34602    priPhoneEl.val(phone3 + ' ' + phone2 + ' ' + phone1);
34603    contactFax.val(fax3 + ' ' + fax2 + ' ' + fax1);
34604
34605    var priPhone = priPhoneEl.val();
34606    var errors   = '';
34607    var ct       = true;
34608
34609    form.find('input').each(function () {
34610      if (!ctype_print($(this).val())) {
34611        ct = false;
34612      }
34613    });
34614
34615    if (!ct) {
34616      errors += $.translate('English Only') + '\n';
34617    }
34618
34619    if (priPhone === '' || priPhone.length < 13 || !/[0-9\s]+/.test(priPhone)) {
34620      priPhoneEl.parent().addClass('has-error');
34621      errors += $.translate('Primary phone is required') + '\n';
34622    } else {
34623      priPhoneEl.parent().removeClass('has-error');
34624    }
34625
34626    if (street === '' || street.length < 2 || !/[0-9]/.test(street)) {
34627      streetEl.parent().addClass('has-error');
34628      errors += $.translate('Street is required') + '\n';
34629    } else {
34630      streetEl.parent().removeClass('has-error');
34631    }
34632
34633    if (city === '' || city.length < 2 || /[0-9]/.test(city)) {
34634      cityEl.parent().addClass('has-error');
34635      errors += $.translate('City is required') + '\n';
34636    } else {
34637      cityEl.parent().removeClass('has-error');
34638    }
34639
34640    if (zip === '' || zip.length !== 7) {
34641      zipEl.parent().addClass('has-error');
34642      errors += $.translate('Zip is required') + '\n';
34643    } else if (window.isInvalidZipCode(zip)) {
34644      zipEl.parent().addClass('has-error');
34645      errors += $.translate('Zip is invalid') + '\n';
34646    } else {
34647      zipEl.parent().removeClass('has-error');
34648    }
34649
34650    if (country === '') {
34651      countryEl.parent().addClass('has-error');
34652      errors += $.translate('Country is required') + '\n';
34653    } else {
34654      countryEl.parent().removeClass('has-error');
34655    }
34656
34657    if (errors !== '') {
34658      $('#updatecnt-errors').html(nl2br(errors, true)).removeClass('hidden');
34659
34660      return false;
34661    } else {
34662      $('#updatecnt-errors').addClass('hidden');
34663
34664      return true;
34665    }
34666  }
34667
34668  $(document).ready(function(e) {
34669    // change domain contacts
34670    $(document).on('click', '.update-cnt', function (e) {
34671      e.preventDefault();
34672      var uid = $(this).parent().parent().data('uid');
34673      $.get(Storage.getData('app_url') + 'domain/updatecnt/' + uid, function (response) {
34674        if (3 == response.status) {
34675          window.location = Storage.getData('app_url') + 'user/login';
34676          return;
34677        }
34678
34679        if(0 == response.status) {
34680          return;
34681        }
34682
34683        $.fancybox.open({
34684          type: 'iframe',
34685          padding: 0,
34686          content: response.html,
34687          afterShow: function () {
34688            $('#saveCnt').click(function (e) {
34689              e.preventDefault();
34690              var form = $(this).closest('form');
34691              $(this).button('loading');
34692              if(validateContact(form)) {
34693                $.post(form.attr('action') + '/' + uid, form.serialize(), function (r) {
34694                  r = JSON.parse(r);
34695                  if (r.status == 1) {
34696                    $('#domainflash').html(r.msg).removeClass('hidden');
34697                    $('#updatecnt-errors').addClass('hidden');
34698                    $.fancybox.close();
34699                  }
34700                  if (r.status == 0) {
34701                    $('#updatecnt-errors').html(nl2br(r.msg, true)).removeClass('hidden');
34702                    $('#contactEmailVerify').prop('disabled', true);
34703                    $('#VerifyEmailSection').addClass('hidden');
34704                    $('#VerifyEmailSection').removeClass('has-error');
34705                    $('#updatecnt-info').addClass('hidden');
34706                    $('#saveCnt').button('reset');
34707                  }
34708                  if (r.status == 4) {
34709                      $('#updatecnt-errors').addClass('hidden');
34710                      $('#updatecnt-info').html(nl2br(r.msg, true)).removeClass('hidden');
34711                      $('#contactEmailVerify').prop('disabled', false);
34712                      $('#VerifyEmailSection').removeClass('hidden');
34713                      $('#VerifyEmailSection').addClass('has-error');
34714                      $('.fancybox-overlay').scrollTop($('#VerifyEmailSection').offset().top);
34715                      $('#saveCnt').button('reset');
34716                  }
34717                })
34718              }else{
34719                $('#saveCnt').button('reset');
34720              }
34721            })
34722          }
34723        })
34724      });
34725    });
34726
34727    // domain after transfer set contact
34728    if(Storage.hasData('newTransferedDomain')) {
34729      var uid = Storage.getData('newTransferedDomain'),
34730          modalCallback = function(params) {
34731
34732      // copy - paste from user/account.php inline js code
34733      var msg = typeof undefined === typeof params.msg ? false : params.msg,
34734          ec  = $('#updatecnt-errors'),
34735          uid = params.uid;
34736
34737      if (false != msg) {
34738        $('#updatecnt-suc').html(msg).removeClass('hidden');
34739      }
34740
34741      $('#saveCnt').click(function (e) {
34742        e.preventDefault();
34743
34744        var form   = $(this).closest('form'),
34745            submit = $(this);
34746
34747        ec.addClass('hidden');
34748
34749        submit.buttonLoading('loading');
34750
34751        if(validateContact(form))
34752
34753        $.post(Storage.getData('app_url') + 'domain/transfer-rcv/' + uid, $('#updatecnt').serialize(), function (response) {
34754
34755          submit.buttonLoading('reset');
34756
34757          if (response.status == 1) {
34758            $('#domainflash').html(response.msg).removeClass('hidden');
34759            ec.addClass('hidden');
34760            $.fancybox.close();
34761          }
34762
34763          if (response.status == 0) {
34764            ec.html(nl2br(response.msg, true)).removeClass('hidden');
34765          }
34766
34767          if (response.status == 2) {
34768            ec.addClass('hidden');
34769            $.fancybox.close();
34770
34771            $.showXHRModal(Storage.getData('app_url') + 'domain/updatecnt/' + response.next, modalCallback, {'uid': response.next, 'msg': response.msg});
34772          }
34773        });
34774      });
34775    };
34776
34777      $.showXHRModal(Storage.getData('app_url') + 'domain/updatecnt/' + uid, modalCallback, {'uid': uid});
34778    }
34779  });
34780})(jQuery);
34781;(function($) {
34782
34783    $(document).ready(function() {
34784
34785        $(document).on('click', '.renew-link', function(e) {
34786
34787            e.preventDefault();
34788            var domain = $(this).data('did');
34789            
34790            $.get(Storage.getData('app_url') + 'domain/getRenewLink/' + domain, function (response) {
34791                if(response.status == 1) {
34792                    $.fancybox.open({
34793                        type: 'iframe',
34794                        padding: 5,
34795                        content: response.html,
34796                        afterShow: function () {
34797                            var form = $('#renew-link');
34798                            e.preventDefault();
34799                            form.on('submit', function(e) {
34800                                e.preventDefault();
34801                                var submitButton = $(e.originalEvent && e.originalEvent.submitter || document.activeElement);
34802                                submitButton.button('loading');
34803                                var userEmail = form.find('#userEmail').val();
34804                                $.post(Storage.getData('app_url') + 'domain/generateRenewLink/' + domain, {
34805                                    userEmail: userEmail
34806                                }, function(response) {
34807                                    var resSection = $('#renew-link-response');
34808                                    if(response.status == 1) {
34809                                      
34810                                        resSection.
34811                                            removeClass('hidden').
34812                                            removeClass('alert-danger alert').
34813                                            addClass('alert-success alert').
34814                                            html(response.msg)
34815                                        ;
34816                                        submitButton.button('reset');
34817                                        
34818                                        // Add click handler for the link after it's added to DOM
34819                                        resSection.find('a').on('click', function(e) {
34820                                            e.preventDefault();
34821                                            
34822                                            var linkUrl = $(this).attr('href');
34823                                            var $temp = $('<textarea>');
34824                                            $('body').append($temp);
34825                                            $temp.val(linkUrl).select();
34826                                            document.execCommand('copy');
34827                                            $temp.remove();
34828                                            
34829                                            // Optional: show feedback
34830                                            var $link = $(this);
34831                                            var originalText = $link.text();
34832                                            $link.text('הועתק!');
34833                                            setTimeout(function() {
34834                                                $link.text(originalText);
34835                                            }, 2000);
34836                                        });
34837                                    }else{
34838                                        resSection.
34839                                            removeClass('hidden').
34840                                            removeClass('alert-success alert').
34841                                            addClass('alert-danger alert').
34842                                            html(response.msg)
34843                                        ;
34844                                        submitButton.button('reset');
34845                                    }
34846
34847                                });
34848                                
34849                            });
34850                          
34851                        }
34852                    })
34853                }else{
34854                    $(this).button('reset');
34855                    console.log(response.status, response.msg);
34856                }
34857            });
34858            
34859        });
34860     
34861    });
34862
34863  
34864
34865    
34866})(jQuery);
34867;(function ($) {
34868  var showTFAReminderPopin = function (popinData) {
34869    var html = '<div id="tfa-reminder" class="modal-ok" style="width: 400px;">',
34870      head = '<div class="modal-header"><span class="UISectionTitleSummary UILabelIconValid">{0}</span></div>'.format(popinData.title),
34871      body = '<div class="modal-body">{0}</div>'.format(popinData.text),
34872      foot =
34873        '<div class="modal-footer">' +
34874        '<button class="btn btn-success">{0}</a>'.format(popinData.buttons.accept) +
34875        '<button class="btn btn-info close-window">{0}</button>'.format(popinData.buttons.cancel) +
34876        '<div class="form-group">' +
34877        '<label for="tfa-reminder-checkbox">{0}</label>'.format(popinData.checkbox) +
34878        '<input id="tfa-reminder-checkbox" type="checkbox" class="clean"/>' +
34879        '</div>' +
34880        '</div>'
34881    ;
34882
34883    html = html + head + body + foot + '</div>';
34884
34885    var closeFancyBox = function (fancybox, notShowAgain, redirect) {
34886      if (false === notShowAgain) {
34887        fancybox.close();
34888
34889        if (undefined !== redirect) {
34890          window.location.href = redirect;
34891        }
34892
34893        return false;
34894      }
34895
34896      var
34897        csrfConfig = Storage.getData('csrf_config'),
34898        data = { 'tfaReminder': false }
34899      ;
34900
34901      data[csrfConfig['token_name_key']] = popinData.csrf.name;
34902      data[csrfConfig['token_key']] = popinData.csrf.token;
34903
34904      $.post('/user/profile', data)
34905        .done(function() {
34906          if (undefined !== redirect) {
34907            window.location.href = redirect;
34908          }
34909        })
34910        .fail(function (response) {
34911          if (403 === response.status) {
34912            window.location.href = '/user/login';
34913          }
34914        })
34915      ;
34916
34917      fancybox.close();
34918    };
34919
34920    $.fancybox.open({
34921      content: html,
34922      padding: 0,
34923      type: 'iframe',
34924      afterShow: function () {
34925        $('#tfa-reminder button.close-window').click(function () {
34926          closeFancyBox($.fancybox, $('#tfa-reminder-checkbox').is(':checked'));
34927        });
34928
34929        $('#tfa-reminder button.btn-success').click(function () {
34930          closeFancyBox($.fancybox, $('#tfa-reminder-checkbox').is(':checked'), '/user/profile/tfa');
34931        });
34932
34933      }
34934    });
34935  };
34936
34937  $(document).ready(function () {
34938    // TFA popin reminder
34939    if (Storage.hasData('tfaReminderPopin')) {
34940      showTFAReminderPopin(Storage.getData('tfaReminderPopin'));
34941    }
34942
34943    // tfa configuration
34944    if (Storage.hasData('tfaConfiguration')) {
34945      $('#form-enable-tfa-submit').click(function (e) {
34946        e.preventDefault();
34947
34948        var next = $(this),
34949          state = next.attr('data-state'),
34950          urls = Storage.getData('tfaConfiguration').urls,
34951          csrfConfig = Storage.getData('csrf_config'),
34952          data = {}
34953        ;
34954
34955        next.buttonLoading('loading');
34956
34957        if ('phone' === state) {
34958          $.post(urls.code, next.closest('form').serialize())
34959            .done(function () {
34960              $('#form-enable-tfa-code').removeClass('hidden');
34961              $('#auth-code').prop('disabled', false);
34962              $('#form-enable-tfa-phone .alert').alert('close');
34963
34964              next.attr('data-state', 'verification');
34965            })
34966            .fail(function (response) {
34967              if (403 === response.status) {
34968                window.location.href = '/user/login';
34969              }
34970
34971              $('#form-enable-tfa-phone').showAlert(response.responseJSON.error, 'danger', null, 'prepend', 'col-sm-8');
34972              next.buttonLoading('reset');
34973            })
34974            .always(function () {
34975              next.buttonLoading('reset');
34976            })
34977          ;
34978        }
34979
34980        if ('verification' === state) {
34981          data = {
34982            phone: {
34983              number: $('#authy-cellphone').val(),
34984              code: $('#countries-input-0').val()
34985            },
34986            code: $('#auth-code').val()
34987          };
34988
34989          data[csrfConfig['token_name_key']] = $('input[name=csrf_token_name]').val();
34990          data[csrfConfig['token_key']] = $('input[name=csrf_token]').val();
34991
34992
34993          $.post(urls.verify, next.closest('form').serialize())
34994            .done(function (response) {
34995              $('#form-enable-tfa-qr').removeClass('hidden');
34996              $('#form-user-auth-tfa-image').attr('src', response.qr);
34997              $('#form-enable-tfa-ga').removeClass('hidden');
34998
34999              $('#form-enable-tfa-phone input').attr('disabled', 'disabled');
35000              $('#form-enable-tfa-code input').attr('disabled', 'disabled');
35001
35002              next.attr('data-state', 'ga');
35003              next.button('ga');
35004            })
35005            .fail(function (response) {
35006              if (403 === response.status) {
35007                window.location.href = '/user/login';
35008              }
35009
35010              $('#form-enable-tfa-code').showAlert(response.responseJSON.error, 'danger', null, 'prepend', 'col-sm-8');
35011
35012              next.buttonLoading('reset');
35013            })
35014          ;
35015        }
35016
35017        if ('ga' === state) {
35018          data = next.closest('form').serialize();
35019          data['code'] = $('#ga-code').val();
35020
35021          $.post(urls.ga, data)
35022            .done(function (response) {
35023              $('#form-enable-tfa-ga input').attr('disabled', 'disabled');
35024
35025              if (undefined !== response.redirect) {
35026                window.location.href = response.redirect;
35027                return;
35028              }
35029
35030              window.location.href = urls.account;
35031            })
35032            .fail(function (response) {
35033              if (403 === response.status) {
35034                window.location.href = '/user/login';
35035              }
35036
35037              $('#form-enable-tfa-ga').showAlert(response.responseJSON.error, 'danger', null, 'prepend', 'col-sm-8');
35038
35039              next.buttonLoading('ga');
35040            })
35041          ;
35042        }
35043      });
35044
35045      $('#form-enable-tfa-verified-submit').click(function (e) {
35046        e.preventDefault();
35047
35048        var
35049          next = $(this),
35050          urls = Storage.getData('tfaConfiguration').urls,
35051          data = next.closest('form').serialize()
35052        ;
35053
35054        next.buttonLoading('loading');
35055
35056        $.post(urls.ga, data)
35057          .done(function (response) {
35058            $('#form-enable-tfa-verified-ga input').attr('disabled', 'disabled');
35059
35060            if (undefined !== response.redirect) {
35061              window.location.href = response.redirect;
35062              return;
35063            }
35064
35065            window.location.href = urls.account;
35066          })
35067          .fail(function (response) {
35068            if (403 === response.status) {
35069              window.location.href = '/user/login';
35070            }
35071
35072            $('#form-enable-tfa-verified-ga').showAlert(response.responseJSON.error, 'danger', null, 'prepend', 'col-sm-8');
35073
35074            next.buttonLoading('reset');
35075          })
35076        ;
35077      });
35078    }
35079
35080    $('#tfa-backup-codes-confirm').change(function () {
35081      var continueLink = $('#tfa-backup-codes-continue');
35082
35083      if ($(this).is(':checked')) {
35084        continueLink.removeClass('disabled').attr('aria-disabled', 'false');
35085      } else {
35086        continueLink.addClass('disabled').attr('aria-disabled', 'true');
35087      }
35088    });
35089
35090    $('#tfa-backup-codes-continue').click(function (e) {
35091      if (!$('#tfa-backup-codes-confirm').is(':checked')) {
35092        e.preventDefault();
35093      }
35094    });
35095
35096    $('#tfa-backup-codes-download').click(function () {
35097      var button = $(this),
35098        codes = button.attr('data-codes') || '',
35099        filename = button.attr('data-filename') || 'backup-codes.txt',
35100        blob = new Blob([codes], {type: 'text/plain;charset=utf-8'}),
35101        link = document.createElement('a')
35102      ;
35103
35104      link.href = window.URL.createObjectURL(blob);
35105      link.download = filename;
35106      document.body.appendChild(link);
35107      link.click();
35108      document.body.removeChild(link);
35109      window.URL.revokeObjectURL(link.href);
35110    });
35111
35112    $('#update-settings-form-tfa').click(function (e) {
35113      e.preventDefault();
35114
35115      var csrfConfig = Storage.getData('csrf_config'),
35116        form = $(this.closest('form')),
35117        button = $(this),
35118        state = 'enabled' === button.attr('data-state') ? 'disabled' : 'enabled',
35119        data = {'tfa': 'enabled' === state}
35120      ;
35121
35122      button.buttonLoading('loading');
35123
35124      data[csrfConfig['token_name_key']] = form.find('[name=csrf_token_name]').val();
35125      data[csrfConfig['token_key']] = form.find('[name=csrf_token]').val();
35126
35127      $.post('/user/profile', data)
35128        .done(function (response) {
35129          if (403 === response.status) {
35130            window.location.href = '/user/login';
35131
35132            return false;
35133          }
35134
35135          if (undefined !== response.redirect) {
35136            window.location.href = response.redirect;
35137
35138            return false;
35139          }
35140
35141          if ('enabled' === state && undefined !== response.qr) {
35142            if (0 === response.qr.length) {
35143              $('#update-settings-form-qr-view').removeClass('hidden');
35144            } else {
35145              $('#update-settings-form-qr-actions').removeClass('hidden');
35146              $('#update-settings-form-enable-qr img').attr('src', response.qr).removeClass('hidden');
35147              $('#update-settings-form-qr-remove').removeClass('hidden');
35148              $('#update-settings-form-qr-view').addClass('hidden');
35149            }
35150            $('#update-settings-form-enable-qr').removeClass('hidden');
35151            $('#update-settings-form-qr-generate').addClass('hidden');
35152
35153            if (true === response.sc.profilePhone.access) {
35154              $('#user-profile-change-phone button').removeClass('hidden');
35155            } else {
35156              $('#user-profile-change-phone button').addClass('hidden');
35157            }
35158          }
35159
35160          if ('disabled' === state) {
35161            $('#update-settings-form-enable-qr img').attr('src', '');
35162            $('#update-settings-form-enable-qr').addClass('hidden');
35163            $('#user-profile-change-phone').removeClass('hidden');
35164            $('#user-profile-change-phone button').removeClass('hidden');
35165          }
35166
35167          button.button(state);
35168          button.attr('class', button.attr('data-class-' + state));
35169          button.attr('data-state', state);
35170        })
35171        .fail(function (response) {
35172          button.buttonLoading('reset');
35173
35174          if (403 === response.status && 'session.not_verified' === response.responseJSON.type) {
35175            window.verifySession();
35176
35177            return false;
35178          }
35179        })
35180    });
35181
35182    $('#update-settings-form-qr-remove').click(function (e) {
35183      e.preventDefault();
35184
35185      var link = $(this);
35186
35187      link.buttonLoading('loading');
35188
35189      var
35190        button = $('#update-settings-form-tfa'),
35191        csrfConfig = Storage.getData('csrf_config'),
35192        actions = $('#update-settings-form-qr-actions'),
35193        data = {}
35194      ;
35195
35196      data[csrfConfig['token_name_key']] = actions.attr('data-token-name');
35197      data[csrfConfig['token_key']] = actions.attr('data-token');
35198
35199      $.post('/user/profile/qr/remove', data)
35200        .done(function (response) {
35201          link.addClass('hidden');
35202          $('#update-settings-form-qr-generate').removeClass('hidden');
35203          $('#update-settings-form-qr-img').addClass('hidden').attr('src', '');
35204
35205          var buttonState = 'disabled';
35206
35207          button.button(buttonState);
35208          button.attr('class', button.attr('data-class-' + buttonState));
35209          button.attr('data-state', buttonState);
35210
35211          $('#update-settings-form-enable-qr img').attr('src', '');
35212          $('#update-settings-form-enable-qr').addClass('hidden');
35213
35214          if (true === response.sc.profilePhone.access) {
35215            $('#user-profile-change-phone button').removeClass('hidden');
35216          } else {
35217            $('#user-profile-change-phone button').addClass('hidden');
35218          }
35219        })
35220        .fail(function (response) {
35221          if (403 === response.status && 'session.not_verified' === response.responseJSON.type) {
35222            window.verifySession();
35223
35224            return false;
35225          }
35226
35227          if (403 === response.status) {
35228            window.location.href = '/user/login';
35229
35230            return false;
35231          }
35232        }).
35233        always(function() {
35234          link.buttonLoading('reset');
35235        })
35236    });
35237
35238    $('#update-settings-form-qr-generate').click(function (e) {
35239      e.preventDefault();
35240
35241      var link = $(this);
35242
35243      link.buttonLoading('loading');
35244
35245      var
35246        csrfConfig = Storage.getData('csrf_config'),
35247        actions = $('#update-settings-form-qr-actions'),
35248        data = {}
35249      ;
35250
35251      data[csrfConfig['token_name_key']] = actions.attr('data-token-name');
35252      data[csrfConfig['token_key']] = actions.attr('data-token');
35253
35254      $.post('/user/profile/qr/generate', data)
35255        .done(function (response) {
35256          link.addClass('hidden');
35257          $('#update-settings-form-qr-remove').removeClass('hidden');
35258          $('#update-settings-form-qr-img').removeClass('hidden').attr('src', response.qr)
35259
35260          if (true === response.sc.profilePhone.access) {
35261            $('#user-profile-change-phone button').removeClass('hidden');
35262          } else {
35263            $('#user-profile-change-phone button').addClass('hidden');
35264          }
35265        })
35266        .fail(function (response) {
35267          if (403 === response.status && 'session.not_verified' === response.responseJSON.type) {
35268            window.verifySession();
35269
35270            return false;
35271          }
35272
35273          if (403 === response.status) {
35274            window.location.href = '/user/login';
35275
35276            return false;
35277          }
35278        }).always(function() {
35279          link.buttonLoading('reset');
35280        })
35281      ;
35282    });
35283
35284    $('#update-settings-form-qr-view').click(function (e) {
35285      e.preventDefault();
35286
35287      var link = $(this);
35288
35289      link.buttonLoading('loading');
35290
35291      var data = {};
35292
35293      $.get('/user/profile/qr/view', data)
35294        .done(function (response) {
35295          link.addClass('hidden');
35296
35297          if (0 < response.qr.length) {
35298            $('#update-settings-form-qr-remove').removeClass('hidden');
35299            $('#update-settings-form-qr-generate').addClass('hidden');
35300            $('#update-settings-form-qr-img').removeClass('hidden').attr('src', response.qr);
35301          } else {
35302            $('#update-settings-form-qr-remove').addClass('hidden');
35303            $('#update-settings-form-qr-generate').removeClass('hidden');
35304          }
35305
35306          $('#update-settings-form-qr-actions').removeClass('hidden');
35307        })
35308        .fail(function (response) {
35309          if (403 === response.status && 'session.not_verified' === response.responseJSON.type) {
35310            window.verifySession();
35311
35312            return false;
35313          }
35314
35315          if (403 === response.status) {
35316            window.location.href = '/user/login';
35317
35318            return false;
35319          }
35320        })
35321        .always(function() {
35322          link.buttonLoading('reset');
35323        })
35324    });
35325
35326    // update phone number
35327    if (Storage.hasData('changePhoneConfiguration')) {
35328      $('button.btn-success').click(function (e) {
35329        e.preventDefault();
35330
35331        var next = $(this),
35332          state = next.attr('data-state'),
35333          urls = Storage.getData('changePhoneConfiguration').urls,
35334          csrfConfig = Storage.getData('csrf_config')
35335        ;
35336
35337        next.buttonLoading('loading');
35338
35339        if ('phone' === state) {
35340          $.post(urls.code, next.closest('form').serialize())
35341            .done(function () {
35342              $('#form-profile-change-phone-number input').prop('disabled', true);
35343              $('#form-profile-change-phone-number .alert').alert('close');
35344              $('#form-profile-change-phone-code').removeClass('hidden');
35345
35346              next.attr('data-state', 'verification');
35347              next.button('verify');
35348            })
35349            .fail(function (response) {
35350              if (403 === response.status) {
35351                window.location.href = '/user/login';
35352              }
35353
35354              $('#form-profile-change-phone-number').showAlert(response.responseJSON.error, 'danger', null, 'prepend', 'col-sm-8');
35355              next.buttonLoading('reset');
35356            })
35357          ;
35358        }
35359
35360        if ('verification' === state) {
35361          var data = {
35362            phone: {
35363              number: $('#authy-cellphone').val(),
35364              code: $('#countries-input-0').val()
35365            },
35366            code: $('#auth-code').val()
35367          };
35368
35369          data[csrfConfig['token_name_key']] = $('input[name=csrf_token_name]').val();
35370          data[csrfConfig['token_key']] = $('input[name=csrf_token]').val();
35371
35372          $.post(urls.verify, data)
35373            .done(function (response) {
35374              $('#form-profile-change-phone-code input').attr('disabled', 'disabled');
35375
35376              next.addClass('hidden');
35377
35378              $('.btn-info').addClass('hidden');
35379              $('a.btn-success').removeClass('hidden');
35380            })
35381            .fail(function (response) {
35382              if (403 === response.status) {
35383                window.location.href = '/user/login';
35384              }
35385
35386              $('#form-profile-change-phone-number').showAlert(response.responseJSON.error, 'danger', null, 'prepend', 'col-sm-8');
35387
35388              next.buttonLoading('reset');
35389            })
35390          ;
35391        }
35392      });
35393    }
35394
35395    $('#update-settings-phone').click(function(e) {
35396      e.preventDefault();
35397
35398      var button = $(this);
35399
35400      button.button('loading');
35401
35402      window.checkAccess('profile_phone', 'update',
35403        function() {
35404          window.location.href = '/user/profile/phone';
35405        },
35406        function() {
35407          button.buttonLoading('reset');
35408        }
35409      )
35410    });
35411  });
35412})(jQuery);
35413;(function($) {
35414
35415  var urls = {
35416    'popin': '/security/popin',
35417    'sendCode': '/security/send-code',
35418    'verifyCode': '/security/verify-code'
35419  };
35420
35421  var getDataValue = function(el, state, name) {
35422    return el.attr('data-' + state + '-' + name);
35423  };
35424
35425  var getTokens = function(el, state) {
35426    var
35427      csrfConfig = Storage.getData('csrf_config'),
35428      data = {}
35429    ;
35430
35431    data[csrfConfig['token_name_key']] = getDataValue(el, state, 'token-name');
35432    data[csrfConfig['token_key']]      = getDataValue(el, state, 'token');
35433
35434    return data;
35435  };
35436
35437  var changeState = function(el, state) {
35438    el.button(state);
35439    el.attr('class', getDataValue(el, state, 'class'));
35440    el.attr('data-state', state);
35441  };
35442
35443  window.verifySession = function() {
35444    $.get(urls.popin)
35445      .done(function(data) {
35446        $.fancybox.open({
35447          content: data.html,
35448          padding: 0,
35449          type: 'iframe',
35450          afterShow: function () {
35451            $('#form-verify-session button').click(function (e) {
35452              e.preventDefault();
35453
35454              var
35455                next  = $(this),
35456                state = next.attr('data-state')
35457              ;
35458
35459              if ('send' === state) {
35460                next.buttonLoading('loading');
35461
35462                $.post(urls.sendCode, getTokens(next, state))
35463                  .done(function () {
35464
35465                    $('#form-verify-session .alert').remove();
35466                    $('#form-verify-session-code').removeClass('hidden');
35467
35468                    changeState(next, 'verify');
35469                  })
35470                  .fail(function (response) {
35471                    if (403 === response.status) {
35472                      window.location.href = '/user/login';
35473                    }
35474
35475                    $('#form-verify-session .alert').remove();
35476                    $('#form-verify-session-code').showAlert(response.responseJSON.error, 'danger', null, 'before', '', false);
35477
35478                    next.buttonLoading('reset');
35479                  })
35480                ;
35481              }
35482
35483              if ('verify' === state) {
35484                next.buttonLoading('loading');
35485
35486                var data = getTokens(next, state);
35487
35488                data['code'] = $('#verification-code').val();
35489
35490                $.post(urls.verifyCode, data)
35491                  .done(function () {
35492                    // need to improve in future
35493                    $('#update-settings-phone').removeClass('hidden');
35494
35495                    $.fancybox.close();
35496                  })
35497                  .fail(function (response) {
35498                    if (403 === response.status) {
35499                      window.location.href = '/user/login';
35500                    }
35501
35502                    $('#form-verify-session .alert').remove();
35503                    $('#form-verify-session-code').showAlert(response.responseJSON.error, 'danger', null, 'prepend', '', false);
35504
35505                    next.buttonLoading('reset');
35506                  })
35507                ;
35508              }
35509            });
35510          }
35511        });
35512      })
35513      .fail(function() {})
35514    ;
35515  };
35516
35517  window.checkAccess = function(context, action, onSuccess, onFail) {
35518    var
35519      data = {
35520        context: context,
35521        action: action
35522      }
35523    ;
35524
35525    $.post('/security/access', data)
35526      .done(function () {
35527        if (undefined !== onSuccess) {
35528          onSuccess();
35529        }
35530      })
35531      .fail(function (response) {
35532        if (undefined !== onFail) {
35533          onFail();
35534        }
35535
35536        if (403 === response.status) {
35537          window.verifySession();
35538
35539          return false;
35540        }
35541
35542        if (undefined !== response.responseJSON.redirect) {
35543          window.location.href = redirect;
35544
35545          return false;
35546        }
35547      })
35548    ;
35549  }
35550})(jQuery);
35551;(function($) {
35552  var updateProfile = function (button, popin, data, onSuccess, state) {
35553    var csrfConfig = Storage.getData('csrf_config');
35554    button.buttonLoading('loading');
35555
35556    data[csrfConfig['token_name_key']] = popin.attr('data-csrf-name');
35557    data[csrfConfig['token_key']]      = popin.attr('data-csrf-token');
35558
35559    $.post('/admin/user-profile/{0}'.format(popin.attr('data-user-id')), data)
35560      .done(function() {
35561        popin.find('.alert-danger').addClass('hidden');
35562        onSuccess();
35563      })
35564      .fail(function (response) {
35565        if (403 === response.status) {
35566          window.location.href = '/admin/login';
35567
35568          return false;
35569        }
35570        var
35571          message = undefined === response.responseJSON.error ? 'Undefined error' : response.responseJSON.error,
35572          error   = popin.find('.alert-danger');
35573
35574        error.removeClass('hidden');
35575        error.text(message);
35576      })
35577      .always(function (data, textStatus, jqXHR) {
35578        button.buttonLoading('reset');
35579
35580        if (undefined !== state && 'success' === textStatus) {
35581          button.button(state)
35582        }
35583      })
35584    ;
35585  };
35586
35587  var showUserPopin = function (data) {  
35588    $.fancybox.open({
35589      content: data.popin,
35590      padding: 0,
35591      type: 'iframe',
35592      afterShow: function () {
35593
35594          var userIsActive = $('#userStatusToggle').is(':checked');
35595          $('#userStatusLabel').css('color', userIsActive ? '#5cb85c' : '#d9534f');
35596          $('#userStatusToggle').on('change', function() {
35597              var userIsActive = $(this).is(':checked');
35598              var label = $('#userStatusLabel');
35599              if (userIsActive) {
35600                  label.text('פעיל').css('color', '#5cb85c');
35601              } else {
35602                  label.text('לא פעיל').css('color', '#d9534f');
35603              }
35604                          
35605          });
35606        
35607        $('#admin-user-popin button.close-window').click(function() {
35608          $.fancybox.close();
35609        });
35610
35611        $('#admin-user-popin .admin-disable-tfa-button').click(function(e) {
35612          e.preventDefault();
35613
35614          var
35615            popin  = $('#admin-user-popin'),
35616            button = $(this)
35617          ;
35618
35619          updateProfile(button, popin, {'tfa': false}, function () {
35620            popin.find('.admin-disable-tfa-disabled-text').removeClass('hidden');
35621            popin.find('.admin-disable-tfa-enabled-text').addClass('hidden');
35622            popin.find('.admin-tfa-reminder-button').removeClass('hidden');
35623            popin.find('.admin-tfa-reminder-text').addClass('hidden');
35624            button.parent().remove();
35625          });
35626        });
35627
35628        $('#admin-user-popin .admin-tfa-reminder-button').click(function (e) {
35629          e.preventDefault();
35630
35631          var
35632            button = $(this),
35633            popin  = $('#admin-user-popin'),
35634            state  = 'enabled' === button.attr('data-state') ? 'disabled' : 'enabled',
35635            enabled = 'enabled' === state
35636          ;
35637
35638          updateProfile(button, popin, {'tfaReminder': enabled}, function () {
35639            button.attr('data-state', state);
35640          }, state);
35641        });
35642
35643        $('#admin-user-popin .admin-verify-phone-button').click(function (e) {
35644          var
35645            button = $(this),
35646            popin  = $('#admin-user-popin'),
35647            phone  = { code: button.attr('data-phone-code'), number: button.attr('data-phone-number') }
35648          ;
35649
35650          updateProfile(button, popin, {phone: phone}, function () {
35651            button.remove();
35652            popin.find('.admin-verify-phone-text').removeClass('hidden');
35653          });
35654        });
35655
35656        $('#admin-user-form-submit').click(function (e) {
35657          e.preventDefault();
35658
35659          $(this).button('loading');
35660
35661          var
35662            button = $(this),
35663            popin  = $('#admin-user-popin'),
35664            email = $('#admin-user-email-address-input').val(),
35665            userStatus = $('#userStatusToggle').is(':checked') ? 1 : 0,
35666            errors = '',
35667            re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
35668          ;
35669
35670          if (!re.test(email) || email === '') {
35671            errors += $.translate('Email is invalid') + '\n';
35672          }
35673
35674          if (errors !== '') {
35675            $('#admin-user-form-errors').html(nl2br(errors, true)).removeClass('hidden');
35676            $('#admin-user-form-submit').button('reset');
35677
35678            return false;
35679          } else {
35680            $('#update-settings-errors').addClass('hidden');
35681            $('#admin-user-form-errors').html('');
35682
35683            updateProfile(button, popin, {'email': email, 'userStatus': userStatus, }, function () {
35684              $('#admin-user-form-submit').button('reset');
35685              $.fancybox.close();
35686            });
35687          }
35688        });
35689      }
35690    });
35691  };
35692
35693  $(document).ready(function() {
35694    $('.admin-user-settings-popin').click(function (e) {
35695
35696      e.preventDefault();
35697
35698      var button = $(this);
35699
35700      button.buttonLoading('loading');
35701
35702      $.get('/admin/user/{0}'.format(button.attr('data-user-id')))
35703        .done(function (response) {
35704          showUserPopin(response)
35705        })
35706        .fail(function (response) {
35707          if (403 === response.status) {
35708            window.location.href = '/admin/login';
35709          }
35710        })
35711        .always(function () {
35712          button.buttonLoading('reset')
35713        })
35714      ;
35715    });
35716  });
35717})(jQuery);
35718
35719//var cur_domain = '';
35720jQuery(document).ready(function ($) {
35721
35722    $(window).scroll(function(){
35723        if ($(window).scrollTop() >= 100) {
35724             $('#Header').addClass('fixed-header');
35725            // $('#topHeader,#bottomHeader').addClass('fixed-header');
35726            // $('#bottomHeader').addClass('fixed-header1');
35727            // $('#Header').css('height',119);
35728            $('#h-helper').css('height',119);
35729        }
35730        else {
35731            $('#Header').removeClass('fixed-header');
35732            // $('#bottomHeader').removeClass('fixed-header1');
35733            // $('#Header').css('height','unset');
35734            $('#h-helper').css('height',0);
35735        }
35736    });
35737
35738    $(".boxNavButton").click(function () {
35739        $(window).width() < 768
35740            ? $(this).hasClass("activeSideBar")
35741                ? $(this).removeClass("activeSideBar").closest("header").find("#mobileSideBar").css({ right: "100%", left: "-100%" })
35742                : $(this).addClass("activeSideBar").closest("header").find("#mobileSideBar").css({  left
35742: "0px",right : "0" })
35743            : $(this).hasClass("activeSideBar")
35744            ? $(this).removeClass("activeSideBar").closest("header").find("#mobileSideBar").css({ right: "100%", left: "-100%" })
35745            : $(this)
35746                  .addClass("activeSideBar")
35747                  .closest("header")
35748                  .find("#mobileSideBar")
35749                  .css({ left: ($(window).width() - 768) / 2, right: ($(window).width() - 768) / 2 });
35750    })
35751    var pos = '';
35752    var tr;
35753    $(document).on('click', '#addDnsRow button', function(e){
35754        e.preventDefault();
35755        pos = '';
35756        $('#' + $(this).attr('data-target')).modal('show').find('.alert').addClass('hidden');
35757    });
35758    $(document).on('click', '#settings, #contacts, #invoices, #mDomains', function(e){
35759        $([document.documentElement, document.body]).animate({
35760            scrollTop: $("#settings").offset().top+45
35761        }, 2000);
35762    });
35763
35764    $(document).on('click','a.editZoneEntry',function(e){
35765        e.preventDefault();
35766        pos = '';
35767        tr = $(this).closest('tr');
35768
35769        var updateCsrfToken = function (form, response) {
35770            form.find('[name=csrf_token]').val(response['csrf_token']);
35771            form.find('[name=csrf_token_name]').val(response['csrf_token_name']);
35772        };
35773
35774        tr.find('select').each(function(){
35775            var name_attr = $(this).attr('name');
35776            if (name_attr.indexOf('type')>0)
35777            {
35778                var sel = $(this).val();
35779                var uid = $(this).closest('form').attr('data-uid');
35780                var url = Storage.getData('app_url') + 'domain/manageEditDomain/' + uid;
35781                var res = name_attr.match(/[0-9]+/gi);
35782                var zone = res[0];
35783                var ttlSelect = $('.modal-dns-edit-record').find('select');
35784                pos = parseInt(zone);
35785
35786                var target = tr.find('input[name$="[record]"]').val();
35787                var domain = tr.find('input[name$="[name]"]').val();
35788                var ttl = tr.find('select[name^="zone["][name$="[ttl]"]').val();
35789                var sub = domain.replace(cur_d, '').replace(/\.+$/, "");
35790
35791                var priority = tr.find('input[name^="priority["]').val();
35792
35793                if(typeof undefined !== typeof ttl && ttlSelect.length > 0) {
35794                    ttlSelect.val(ttl);
35795                }
35796
35797                if(sel === "HTTPRED"){
35798                    var redType = tr.find('input[name$="[status]"]').val();
35799
35800                    $('#editDnsRowREDModal').modal('show').find('.alert').addClass('hidden');
35801                    $('#editDnsRowREDModal').find('input[name=recordRED]').val(target);
35802
35803                    if(redType == '301')
35804                    {
35805                        $('#typered3').prop( "checked", true );
35806                        $('#typered4').prop( "checked", false );
35807
35808                        $('#editDnsRowREDModal').find('input[id=typered3]').prop( "checked", true );
35809                        $('#editDnsRowREDModal').find('input[id=typered4]').prop( "checked", false );
35810                    }
35811                    else
35812                    {
35813                        $('#typered3').prop( "checked", false );
35814                        $('#typered4').prop( "checked", true );
35815
35816                        $('#editDnsRowREDModal').find('input[id=typered3]').prop( "checked", false );
35817                        $('#editDnsRowREDModal').find('input[id=typered4]').prop( "checked", true );
35818                    }
35819                    return;
35820                }
35821
35822                if(sel === "CNAME")
35823                {
35824                    $('#editDnsRowCNAMEModal').modal('show').find('.alert').addClass('hidden');
35825                    $('#editDnsRowCNAMEModal').find('input[name=hostnameCNAME]').val(sub);
35826                    $('#editDnsRowCNAMEModal').find('input[name=recordCNAME]').val(target);
35827
35828                    $('#editDnsRowCNAMEModal').find('.select2').val(ttl);
35829
35830                    return;
35831                }
35832
35833                if(sel === "TXT")
35834                {
35835                    $('#editDnsRowTXTModal').modal('show').find('.alert').addClass('hidden');
35836                    $('#editDnsRowTXTModal').find('input[name=hostnameTXT]').val(sub);
35837                    $('#editDnsRowTXTModal').find('input[name=recordTXT]').val(target);
35838
35839                    $('#editDnsRowTXTModal').find('.select2').val(ttl);
35840
35841                    return;
35842                }
35843
35844                if(sel === "A")
35845                {
35846                    $('#editDnsRowAModal').modal('show').find('.alert').addClass('hidden');
35847                    $('#editDnsRowAModal').find('input[name=hostnameA]').val(sub);
35848                    $('#editDnsRowAModal').find('input[name=recordA]').val(target);
35849
35850                    $('#editDnsRowAModal').find('.select2').val(ttl);
35851
35852                    return;
35853                }
35854
35855                if(sel === "AAAA")
35856                {
35857                    $('#editDnsRowAAAAModal').modal('show').find('.alert').addClass('hidden');
35858                    $('#editDnsRowAAAAModal').find('input[name=hostnameAAAA]').val(sub);
35859                    $('#editDnsRowAAAAModal').find('input[name=recordAAAA]').val(target);
35860
35861                    $('#editDnsRowAAAAModal').find('.select2').val(ttl);
35862
35863                    return;
35864                }
35865
35866                if(sel === "MX")
35867                {
35868                    $('#editDnsRowMXModal').modal('show').find('.alert').addClass('hidden');
35869                    $('#editDnsRowMXModal').find('input[name=hostMX]').val(sub);
35870                    $('#editDnsRowMXModal').find('input[name=hostnameMX]').val(target);
35871                    $('#editDnsRowMXModal').find('input[name=recordMX]').val(priority);
35872
35873                    $('#editDnsRowMXModal').find('.select2').val(ttl);
35874
35875                    return;
35876                }
35877
35878                if(sel === "SRV")
35879                {
35880                    $('#editDnsRowSRVModal').modal('show').find('.alert').addClass('hidden');
35881
35882                    var spl = domain.split('.');
35883
35884                    $('#editDnsRowSRVModal').find('input[name=serviceSRV]').val(spl[0]);
35885                    $('#editDnsRowSRVModal').find('input[name=hostnameSRV]').val(spl[1]);
35886                    $('#editDnsRowSRVModal').find('input[name=recordSRV]').val(priority);
35887
35888                    var prt = target.split(' ');
35889                    $('#editDnsRowSRVModal').find('input[name=weightSRV]').val(prt[0]);
35890                    $('#editDnsRowSRVModal').find('input[name=portSRV]').val(prt[1]);
35891                    $('#editDnsRowSRVModal').find('input[name=targetSRV]').val(prt[2]);
35892
35893                    $('#editDnsRowSRVModal').find('.select2').val(ttl)
35894
35895                    return;
35896                }
35897            }
35898
35899        });
35900
35901        //$('#editDnsRowAModal').modal('show').find('.alert').addClass('hidden');
35902    });
35903
35904    // todo@alexbuturlakin: this hardcode need to be refactored
35905    //create new / edit
35906    $(document).on('click', '.modalDns .btn-primary', function(e){
35907
35908        e.preventDefault();
35909        var window = $(this).closest('div.modalDns');
35910        var type   = $('.modalDns.in').attr('data-type');
35911        var ttl    = $('.modalDns.in [name=ttl]').val();
35912
35913        var
35914          csrfConfig    = Storage.getData('csrf_config'),
35915          tokenKey      = csrfConfig['token_key'],
35916          tokenNameKey  = csrfConfig['token_name_key'],
35917          csrfToken     = $('.modalDns.in').find('[name=csrf_token]').val(),
35918          csrfTokenName = $('.modalDns.in').find('[name=csrf_token_name]').val()
35919        ;
35920
35921        var addCSRFToDNSData = function (updatednsdata) {
35922            if (null === updatednsdata) {
35923                return updatednsdata;
35924            }
35925
35926            if ('object' === typeof updatednsdata) {
35927                updatednsdata[tokenKey] = csrfToken;
35928                updatednsdata[tokenNameKey] = csrfTokenName;
35929
35930                return updatednsdata;
35931            }
35932
35933            updatednsdata += '&'+tokenKey+'='+csrfToken+'&'+tokenNameKey+'='+csrfTokenName;
35934
35935            return updatednsdata;
35936        };
35937
35938        var clearDNSModal = function () {
35939          $('.modalDns.in input:not([type=hidden])').val('');
35940        };
35941
35942        k++;
35943        switch(type){
35944            case 'A':
35945                var ct = true;
35946                var errors = '';
35947                $('.modalDns.in input.form-control').each(function () {
35948                    if($(this).attr('name') != 'hostnameA') {
35949                        if (!ctype_print($(this).val())) {
35950                            ct = false;
35951                        }
35952                        if ($(this).val() == '') {
35953                            ct = false;
35954                        }
35955                    }
35956                });
35957                if (!ct) {
35958                    errors += $.translate('English Only') + '\n';
35959                }
35960
35961                if(!isValidIPv4( $('.modalDns.in [name=recordA]').val() )){
35962                     errors += $.translate('Not Valid IPV4') + '\n';
35963                }
35964                if(!isValidSubdomain( $('.modalDns.in [name=hostnameA]').val() )){
35965                     errors += $.translate('Not Valid HostName') + '\n';
35966                }
35967
35968                if((errors !== '')){
35969                    $('.modalDns.in .alert').html(nl2br(errors)).removeClass('hidden');
35970                    return;
35971                }else{
35972                    $('.modalDns.in .alert').addClass('hidden');
35973                    var sub = $('.modalDns.in [name=hostnameA]').val();
35974                    var dom = sub + '.' + cur_d + '.';
35975                    if(sub == '' || ('string' === typeof sub  && '@' == sub.trim())){
35976                        dom = cur_d + '.';
35977                    }
35978
35979                    var updatednsdata = '';
35980                    if(pos === '') {
35981                        $('#updatezone .table tbody tr').eq($('#updatezone .table tbody tr').length - 1).before('\
35982							<tr class="row-a">\
35983								<td>\
35984									<input readonly disabled type="text" value="'+dom+'" name="zone[' + k + '][name]">\
35985								</td>\
35986								<td>\
35987									<select  readonly disabled name="zone['+k+'][ttl]">\
35988										<option value="3600">3600</option>\
35989										<option value="' + ttl + '" selected="selected">' + ttl + '</option>\
35990									</select>\
35991								</td>\
35992								<td>\
35993									<select readonly disabled name="zone['+k+'][type]">\
35994										<option value="NS" class="hidden">NS</option>\
35995										<option value="A" selected="selected">A</option>\
35996                                        <option value="AAAA">AAAA</option>\
35997										<option value="MX">MX</option>\
35998										<option value="SRV">SRV</option>\
35999										<option value="TXT">TXT</option>\
36000										<option value="CNAME">CNAME</option>\
36001										<option value="HTTPRED">HTTPRED</option>\
36002									</select>\
36003								</td>\
36004								<td>\
36005									<input readonly disabled type="text" value="'+ $('.modalDns.in [name=recordA]').val()  +'" name="zone['+k+'][record]">\
36006								</td>\
36007								<td>\
36008									<a class="delZoneEntry" href="#del" title="מחיקה">\
36009										<span class="glyphicon glyphicon-trash"></span></a>\
36010									<a class="editZoneEntry" href="#edit" title="מחיקה">\
36011										<span class="glyphicon glyphicon-edit"></span></a>\
36012									</td>\
36013							<tr>\
36014						');
36015                        updatednsdata = 'zone[name]='+dom+'&zone[record]='+ $('.modalDns.in [name=recordA]').val()+'&zone[ttl]=' + ttl + '&zone[type]=A';
36016                    } else {
36017                        $("input[name='zone\\["+pos+"\\]\\[record\\]']").val($('.modalDns.in [name=recordA]').val());
36018                        $("input[name='zone\\["+pos+"\\]\\[name\\]']").val(dom);
36019                        if(typeof undefined !== typeof ttl) {
36020                            $("select[name='zone\\["+pos+"\\]\\[ttl\\]']").val(ttl);
36021                        }
36022                        updatednsdata = 'zone[name]='+dom+'&zone[record]='+ $('.modalDns.in [name=recordA]').val()+'&zone[ttl]=' + ttl + '&zone[type]=A';
36023                    }
36024                    clearDNSModal();
36025                    //ALIN:
36026                    var id = window.attr('id');
36027
36028                    updatednsdata = addCSRFToDNSData(updatednsdata);
36029
36030                    if (id.indexOf('addDns') >=0)
36031                    {
36032                        $.post(Storage.getData('app_url') + 'domain/new-record/' + $('#updatezone').attr('data-uid'), updatednsdata, function(r){
36033                            /*	r = JSON.parse(r);
36034                             if(r.status == 0){
36035                             $('#zone-error').html(r.msg).removeClass('hidden');
36036                             }
36037                             if(r.status == 1){
36038                             $.fancybox.close();
36039                             $('#domainflash').html(r.msg).removeClass('hidden');
36040                             }*/
36041                            $('#save-zone').button('reset');
36042                        });
36043                    }
36044                    else
36045                    {
36046                        $('#save-zone').button('reset');
36047                    }
36048                    //:ALIN
36049                    $('.modalDns.in').modal('hide');
36050                }
36051                break;
36052            case 'AAAA':
36053                var ct = true;
36054                var errors = '';
36055                $('.modalDns.in input.form-control').each(function () {
36056                    if($(this).attr('name') != 'hostnameAAAA') {
36057                        if (!ctype_print($(this).val())) {
36058                            ct = false;
36059                        }
36060                        if ($(this).val() == '') {
36061                            ct = false;
36062                        }
36063                    }
36064                });
36065                if (!ct) {
36066                    errors += $.translate('English Only') + '\n';
36067                }
36068
36069                if(!isValidIPv6( $('.modalDns.in [name=recordAAAA]').val() )){
36070                     errors += $.translate('Not Valid IPV4') + '\n';
36071                }
36072                if(!isValidSubdomain( $('.modalDns.in [name=hostnameAAAA]').val() )){
36073                     errors += $.translate('Not Valid HostName') + '\n';
36074                }
36075
36076                if((errors !== '')){
36077                    $('.modalDns.in .alert').html(nl2br(errors)).removeClass('hidden');
36078                    return;
36079                }else{
36080                    $('.modalDns.in .alert').addClass('hidden');
36081                    var sub = $('.modalDns.in [name=hostnameAAAA]').val();
36082                    var dom = sub + '.' + cur_d + '.';
36083                    if(sub == '' || ('string' === typeof sub  && '@' == sub.trim())){
36084                        dom = cur_d + '.';
36085                    }
36086
36087                    var updatednsdata = '';
36088                    if(pos === '') {
36089                        $('#updatezone .table tbody tr').eq($('#updatezone .table tbody tr').length - 1).before('\
36090							<tr class="row-aaaa">\
36091								<td>\
36092									<input readonly disabled type="text" value="'+dom+'" name="zone[' + k + '][name]">\
36093								</td>\
36094								<td>\
36095									<select  readonly disabled name="zone['+k+'][ttl]">\
36096										<option value="3600">3600</option>\
36097										<option value="' + ttl + '" selected="selected">' + ttl + '</option>\
36098									</select>\
36099								</td>\
36100								<td>\
36101									<select readonly disabled name="zone['+k+'][type]">\
36102										<option value="NS" class="hidden">NS</option>\
36103										<option value="A">A</option>\
36104                                        <option value="AAAA" selected="selected">AAAA</option>\
36105										<option value="MX">MX</option>\
36106										<option value="SRV">SRV</option>\
36107										<option value="TXT">TXT</option>\
36108										<option value="CNAME">CNAME</option>\
36109										<option value="HTTPRED">HTTPRED</option>\
36110									</select>\
36111								</td>\
36112								<td>\
36113									<input readonly disabled type="text" value="'+ $('.modalDns.in [name=recordAAAA]').val()  +'" name="zone['+k+'][record]">\
36114								</td>\
36115								<td>\
36116									<a class="delZoneEntry" href="#del" title="מחיקה">\
36117										<span class="glyphicon glyphicon-trash"></span></a>\
36118									<a class="editZoneEntry" href="#edit" title="מחיקה">\
36119										<span class="glyphicon glyphicon-edit"></span></a>\
36120									</td>\
36121							<tr>\
36122						');
36123                        updatednsdata = 'zone[name]='+dom+'&zone[record]='+ $('.modalDns.in [name=recordAAAA]').val()+'&zone[ttl]=' + ttl + '&zone[type]=AAAA';
36124                    } else {
36125                        $("input[name='zone\\["+pos+"\\]\\[record\\]']").val($('.modalDns.in [name=recordAAAA]').val());
36126                        $("input[name='zone\\["+pos+"\\]\\[name\\]']").val(dom);
36127                        if(typeof undefined !== typeof ttl) {
36128                            $("select[name='zone\\["+pos+"\\]\\[ttl\\]']").val(ttl);
36129                        }
36130                        updatednsdata = 'zone[name]='+dom+'&zone[record]='+ $('.modalDns.in [name=recordAAAA]').val()+'&zone[ttl]=' + ttl + '&zone[type]=AAAA';
36131                    }
36132                    clearDNSModal();
36133                    //ALIN:
36134                    var id = window.attr('id');
36135
36136                    updatednsdata = addCSRFToDNSData(updatednsdata);
36137
36138                    if (id.indexOf('addDns') >=0)
36139                    {
36140                        $.post(Storage.getData('app_url') + 'domain/new-record/' + $('#updatezone').attr('data-uid'), updatednsdata, function(r){
36141                            /*	r = JSON.parse(r);
36142                             if(r.status == 0){
36143                             $('#zone-error').html(r.msg).removeClass('hidden');
36144                             }
36145                             if(r.status == 1){
36146                             $.fancybox.close();
36147                             $('#domainflash').html(r.msg).removeClass('hidden');
36148                             }*/
36149                            $('#save-zone').button('reset');
36150                        });
36151                    }
36152                    else
36153                    {
36154                        $('#save-zone').button('reset');
36155                    }
36156                    //:ALIN
36157                    $('.modalDns.in').modal('hide');
36158                }
36159                break;
36160            case 'CNAME':
36161                var ct = true;
36162                var errors = '';
36163                $('.modalDns.in input.form-control').each(function () {
36164                    if($(this).attr('name') != 'hostnameCNAME') {
36165
36166                        if (!ctype_print($(this).val())) {
36167                            ct = false;
36168                        }
36169                        if ($(this).val() == '') {
36170                            ct = false;
36171                        }
36172                    }
36173                });
36174                if (!ct) {
36175                    errors += $.translate('English Only') + '\n';
36176                }
36177                if($('.modalDns.in [name=hostnameCNAME]').val().length === 0){
36178                    errors += $.translate('Cannot config CNAME for primary host') + '\n';
36179                }
36180
36181                if (!isValidSubdomain($('.modalDns.in [name=hostnameCNAME]').val(), true)) {
36182                    errors += $.translate('Not Valid HostName') + '\n';
36183                }
36184                if (!isValidFullDomain($('.modalDns.in [name=recordCNAME]').val(), true)) {
36185                    errors += $.translate('Not Valid HostName Target') + '\n';
36186                }
36187                
36188                if((errors !== '')){
36189                    $('.modalDns.in .alert').html(nl2br(errors)).removeClass('hidden');
36190                    return;
36191                }else{
36192                    $('.modalDns.in .alert').addClass('hidden');
36193                    var sub = $('.modalDns.in [name=hostnameCNAME]').val();
36194                    var dom = sub + '.' + cur_d + '.';
36195                    if(sub == '' || ('string' === typeof sub  && '@' == sub.trim())){
36196                        dom = cur_d + '.';
36197                    }
36198                    var updatednsdata = '';
36199                    if(pos === ''){
36200                        $('#updatezone .table tbody tr').eq($('#updatezone .table tbody tr').length - 1).before('\
36201						<tr class="row-cname">\
36202							<td>\
36203								<input readonly disabled type="text" value="' + dom + '" name="zone[' + k + '][name]">\
36204							</td>\
36205							<td>\
36206								<select readonly disabled name="zone['+k+'][ttl]">\
36207									<option value="3600">3600</option>\
36208									<option value="' + ttl + '" selected="selected">' + ttl + '</option>\
36209								</select>\
36210							</td>\
36211							<td>\
36212								<select readonly disabled name="zone['+k+'][type]">\
36213									<option value="NS" class="hidden">NS</option>\
36214									<option value="A">A</option>\
36215                                    <option value="AAAA">AAAA</option>\
36216									<option value="MX">MX</option>\
36217									<option value="SRV">SRV</option>\
36218									<option value="TXT">TXT</option>\
36219									<option value="CNAME" selected="selected">CNAME</option>\
36220									<option value="HTTPRED">HTTPRED</option>\
36221								</select>\
36222							</td>\
36223							<td>\
36224								<input readonly disabled type="text" value="'+ $('.modalDns.in [name=recordCNAME]').val()  +'" name="zone['+k+'][record]">\
36225							</td>\
36226							<td>\
36227								<a class="delZoneEntry" href="#del" title="מחיקה">\
36228									<span class="glyphicon glyphicon-trash"></span></a>\
36229								<a class="editZoneEntry" href="#edit" title="מחיקה">\
36230									<span class="glyphicon glyphicon-edit"></span></a>\
36231								</td>\
36232						<tr>\
36233					');
36234
36235                    } else {
36236                        $("input[name='zone\\["+pos+"\\]\\[record\\]']").val($('.modalDns.in [name=recordCNAME]').val());
36237                        $("input[name='zone\\["+pos+"\\]\\[name\\]']").val(dom);
36238                        if(typeof undefined !== typeof ttl) {
36239                            $("select[name='zone\\["+pos+"\\]\\[ttl\\]']").val(ttl);
36240                        }
36241                    }
36242                    updatednsdata = 'zone[name]='+dom+'&zone[record]='+ $('.modalDns.in [name=recordCNAME]').val()+'&zone[ttl]=' + ttl + '&zone[type]=CNAME';
36243                    var id = window.attr('id');
36244
36245                    updatednsdata = addCSRFToDNSData(updatednsdata);
36246
36247                    if (id.indexOf('addDns') >=0)
36248                    {
36249                        $.post(Storage.getData('app_url') + 'domain/new-record/' + $('#updatezone').attr('data-uid'), updatednsdata, function(r){
36250                            /*	r = JSON.parse(r);
36251                             if(r.status == 0){
36252                             $('#zone-error').html(r.msg).removeClass('hidden');
36253                             }
36254                             if(r.status == 1){
36255                             $.fancybox.close();
36256                             $('#domainflash').html(r.msg).removeClass('hidden');
36257                             }*/
36258                            $('#save-zone').button('reset');
36259                        });
36260                    }
36261                    else {
36262                        $('#save-zone').button('reset');
36263                    }
36264                    //:ALIN
36265                    clearDNSModal();
36266
36267                    $('.modalDns.in').modal('hide');
36268                }
36269                break;
36270            case 'TXT':
36271                var ct = true;
36272                var errors = '';
36273                //	if(pos === ''){
36274                $('.modalDns.in input.form-control').each(function () {
36275                    if($(this).attr('name') != 'hostnameTXT') {
36276                        if (!ctype_print($(this).val())) {
36277                            ct = false;
36278                        }
36279                        if ($(this).val() == '') {
36280                            ct = false;
36281                        }
36282                    }
36283                });
36284                if (!ct) {
36285                    errors += $.translate('English Only') + '\n';
36286                }
36287                if (!isValidSubdomain($('.modalDns.in [name=hostnameTXT]').val(), true)) {
36288                     errors += $.translate('Not Valid HostName') + '\n';
36289                }
36290                if((errors !== '')){
36291                    $('.modalDns.in .alert').html(nl2br(errors)).removeClass('hidden');
36292                    return;
36293                } else {
36294                    $('.modalDns.in .alert').addClass('hidden');
36295                    var sub = $('.modalDns.in [name=hostnameTXT]').val();
36296                    var dom = sub + '.' + cur_d + '.';
36297
36298                    if(sub == '' || ('string' === typeof sub  && '@' == sub.trim())){
36299                        dom = cur_d + '.';
36300                    }
36301
36302                    var updatednsdata = '';
36303
36304                    if(pos === ''){
36305                        $('#updatezone .table tbody tr').eq($('#updatezone .table tbody tr').length - 1).before('\
36306						<tr class="row-txt">\
36307							<td>\
36308								<input readonly disabled type="text" value="' + dom + '" name="zone[' + k + '][name]">\
36309							</td>\
36310							<td>\
36311								<select readonly disabled name="zone['+k+'][ttl]">\
36312									<option value="3600">3600</option>\
36313									<option value="' + ttl + '" selected="selected">' + ttl + '</option>\
36314								</select>\
36315							</td>\
36316							<td>\
36317								<select readonly disabled name="zone['+k+'][type]">\
36318									<option value="NS" class="hidden">NS</option>\
36319									<option value="A">A</option>\
36320                                    <option value="AAAA">AAAA</option>\
36321									<option value="MX">MX</option>\
36322									<option value="SRV">SRV</option>\
36323									<option value="TXT" selected="selected">TXT</option>\
36324									<option value="CNAME">CNAME</option>\
36325									<option value="HTTPRED">HTTPRED</option>\
36326								</select>\
36327							</td>\
36328							<td>\
36329								<input readonly disabled type="text" value="'+ $('.modalDns.in [name=recordTXT]').val()  +'" name="zone['+k+'][record]">\
36330							</td>\
36331							<td>\
36332								<a class="delZoneEntry" href="#del" title="מחיקה">\
36333									<span class="glyphicon glyphicon-trash"></span></a>\
36334								<a class="editZoneEntry" href="#edit" title="מחיקה">\
36335									<span class="glyphicon glyphicon-edit"></span></a>\
36336								</td>\
36337						<tr>\
36338					');
36339                    } else {
36340                        $("input[name='zone\\["+pos+"\\]\\[record\\]']").val($('.modalDns.in [name=recordTXT]').val());
36341                        $("input[name='zone\\["+pos+"\\]\\[name\\]']").val(dom);
36342                        if(typeof undefined !== typeof ttl) {
36343                            $("select[name='zone\\["+pos+"\\]\\[ttl\\]']").val(ttl);
36344                        }
36345                    }
36346
36347                    updatednsdata = {
36348                        zone: {
36349                            name_entered: sub,
36350                            name: dom,
36351                            record: $('.modalDns.in [name=recordTXT]').val(),
36352                            ttl: ttl,
36353                            type: 'TXT'
36354                        }
36355                    };
36356
36357                    var id = window.attr('id');
36358                    updatednsdata = addCSRFToDNSData(updatednsdata);
36359
36360                    if (id.indexOf('addDns') >=0)
36361                    {
36362                        $.post(Storage.getData('app_url') + 'domain/new-record/' + $('#updatezone').attr('data-uid'), updatednsdata, function(r){
36363                            /*	r = JSON.parse(r);
36364                             if(r.status == 0){
36365                             $('#zone-error').html(r.msg).removeClass('hidden');
36366                             }
36367                             if(r.status == 1){
36368                             $.fancybox.close();
36369                             $('#domainflash').html(r.msg).removeClass('hidden');
36370                             }*/
36371                            $('#save-zone').button('reset');
36372                        });
36373                    }
36374                    else
36375                    {
36376                        $('#save-zone').button('reset');
36377                    }
36378                    //:ALIN
36379                    clearDNSModal();
36380                    $('.modalDns.in').modal('hide');
36381                }
36382                break;
36383            case 'MX':
36384                var ct = true;
36385                var errors = '';
36386                $('.modalDns.in input.form-control').each(function () {
36387                    if($(this).attr('name') != 'hostMX') {
36388                        if (!ctype_print($(this).val())) {
36389                            ct = false;
36390                        };
36391                        if($(this).val() == ''){
36392                            ct = false;
36393                        }
36394                    }
36395                });
36396                if (!ct) {
36397                    errors += $.translate('English Only') + '\n';
36398                }
36399                if (!isValidFullDomain($('.modalDns.in [name=hostnameMX]').val())) {
36400                    errors += $.translate('Not Valid HostName Target') + '\n';
36401                }
36402
36403                var priority = $('.modalDns.in [name=recordMX]').val();
36404                if(isNaN(priority) || parseInt(priority) < 0 || parseInt(priority) > 65535){
36405                    errors += $.translate('Priority must be between 0 and 65535') + '\n';
36406                }
36407
36408                if((errors !== '')){
36409                    $('.modalDns.in .alert').html(nl2br(errors)).removeClass('hidden');
36410                    return;
36411                }else{
36412                    $('.modalDns.in .alert').addClass('hidden');
36413                    var sub = $('.modalDns.in [name=hostMX]').val();
36414                    var dom = sub + '.' + cur_d + '.';
36415                    if(sub == '' || ('string' === typeof sub  && '@' == sub.trim())){
36416                        dom = cur_d + '.';
36417                    }
36418                    if(pos === ''){
36419                        $('#updatezone .table tbody tr').eq($('#updatezone .table tbody tr').length - 1).before('\
36420						<tr class="row-mx">\
36421							<td>\
36422							    <input type="hidden" name="priority[' + k + ']" value="'+$('.modalDns.in [name=recordMX]').val()+'">\
36423								<input readonly disabled type="text" value="'+dom+'." name="zone[' + k + '][name]">\
36424							</td>\
36425							<td>\
36426								<select readonly disabled name="zone['+k+'][ttl]">\
36427									<option value="3600">3600</option>\
36428									<option value="' + ttl + '" selected="selected">' + ttl + '</option>\
36429								</select>\
36430							</td>\
36431							<td>\
36432								<select readonly disabled name="zone['+k+'][type]">\
36433									<option value="NS" class="hidden">NS</option>\
36434									<option value="A">A</option>\
36435                                    <option value="AAAA">AAAA</option>\
36436									<option value="MX" selected="selected">MX</option>\
36437									<option value="SRV">SRV</option>\
36438									<option value="TXT">TXT</option>\
36439									<option value="CNAME">CNAME</option>\
36440									<option value="HTTPRED">HTTPRED</option>\
36441								</select>\
36442							</td>\
36443							<td>\
36444								<input readonly disabled type="text" value="' + $('.modalDns.in [name=hostnameMX]').val() + '." name="zone['+k+'][record]">\
36445							</td>\
36446							<td>\
36447								<a class="delZoneEntry" href="#del" title="מחיקה">\
36448									<span class="glyphicon glyphicon-trash"></span></a>\
36449								<a class="editZoneEntry" href="#edit" title="מחיקה">\
36450									<span class="glyphicon glyphicon-edit"></span></a>\
36451								</td>\
36452						<tr>\
36453					');
36454                    } else {
36455                        $("input[name='zone\\["+pos+"\\]\\[record\\]']").val($('.modalDns.in [name=hostnameMX]').val());
36456                        $("input[name='zone\\["+pos+"\\]\\[name\\]']").val(dom);
36457                        $("input[name='priority\\["+pos+"\\]']").val($('.modalDns.in [name=recordMX]').val());
36458                        if(typeof undefined !== typeof ttl) {
36459                            $("select[name='zone\\["+pos+"\\]\\[ttl\\]']").val(ttl);
36460                        }
36461                    }
36462                    var updatednsdata = 'zone[name]=' + dom + '&zone[priority]='+ $('.modalDns.in [name=recordMX]').val() + '&zone[record]=' + $('.modalDns.in [name=hostnameMX]').val() +'&zone[ttl]=' + ttl + '&zone[type]=MX';
36463                    var id = window.attr('id');
36464
36465                    updatednsdata = addCSRFToDNSData(updatednsdata);
36466
36467                    if (id.indexOf('addDns') >=0) {
36468                        $.post(Storage.getData('app_url') + 'domain/new-record/' + $('#updatezone').attr('data-uid'), updatednsdata, function(r){
36469                            /*	r = JSON.parse(r);
36470                             if(r.status == 0){
36471                             $('#zone-error').html(r.msg).removeClass('hidden');
36472                             }
36473                             if(r.status == 1){
36474                             $.fancybox.close();
36475                             $('#domainflash').html(r.msg).removeClass('hidden');
36476                             }*/
36477                            $('#save-zone').button('reset');
36478                        });
36479                    } else {
36480                        $('#save-zone').button('reset');
36481                    }
36482                    //:ALIN
36483                    clearDNSModal();
36484                    $('.modalDns.in').modal('hide');
36485                }
36486                break;
36487            case 'SRV':
36488                var ct = true;
36489                var errors = '';
36490                $('.modalDns.in input.form-control').each(function () {
36491                    if (!ctype_print($(this).val())) {
36492                        ct = false;
36493                    };
36494                    if($(this).val() == ''){
36495                        ct = false;
36496                    }
36497                });
36498                if (!ct) {
36499                    errors += $.translate('English Only') + '\n';
36500                }
36501                if((errors !== '')){
36502                    $('.modalDns.in .alert').html(nl2br(errors)).removeClass('hidden');
36503                    return;
36504                }else{
36505                    $('.modalDns.in .alert').addClass('hidden');
36506                    var sub = $('.modalDns.in [name=hostnameSRV]').val();
36507                    var dom = sub + '.' + cur_d + '.';
36508                    if(sub == '' || ('string' === typeof sub  && '@' == sub.trim())){
36509                        dom = cur_d + '.';
36510                    }
36511                    if(pos === ''){ // +St: name["serviceSRV"] ==> hostnameSRV
36512                        $('#updatezone .table tbody tr').eq($('#updatezone .table tbody tr').length - 1).before('\
36513						<tr class="row-srv">\
36514							<td>\
36515							    \<input type="hidden" name="priority[' + k + ']" value="'+$('.modalDns.in [name=recordSRV]').val()+'">\
36516								<input readonly disabled type="text" value="' + $('.modalDns.in [name="serviceSRV"]').val() + '.'  + $('.modalDns.in [name="hostnameSRV"]').val() + '.' + cur_d + '" name="zone[' + k + '][name]">\
36517							</td>\
36518							<td>\
36519								<select readonly disabled name="zone['+k+'][ttl]">\
36520									<option value="3600">3600</option>\
36521									<option value="' + ttl + '" selected="selected">' + ttl + '</option>\
36522								</select>\
36523							</td>\
36524							<td>\
36525								<select readonly disabled name="zone['+k+'][type]">\
36526									<option value="NS" class="hidden">NS</option>\
36527									<option value="A">A</option>\
36528                                    <option value="AAAA">AAAA</option>\
36529									<option value="MX">MX</option>\
36530									<option value="SRV" selected="selected">SRV</option>\
36531									<option value="TXT">TXT</option>\
36532									<option value="CNAME">CNAME</option>\
36533									<option value="HTTPRED">HTTPRED</option>\
36534								</select>\
36535							</td>\
36536							<td>\
36537								<input readonly disabled type="text" value="' /*+ $('.modalDns.in [name=recordSRV]').val()  + ' '*/ + $('.modalDns.in [name=weightSRV]').val() + ' ' + $('.modalDns.in [name=portSRV]').val() + ' ' + $('.modalDns.in [name=targetSRV]').val() + '" name="zone['+k+'][record]">\
36538							</td>\
36539							<td>\
36540								<a class="delZoneEntry" href="#del" title="מחיקה">\
36541									<span class="glyphicon glyphicon-trash"></span></a>\
36542								<a class="editZoneEntry" href="#edit" title="מחיקה">\
36543									<span class="glyphicon glyphicon-edit"></span></a>\
36544								</td>\
36545						<tr>\
36546					');
36547                    } else {
36548                        /*$("input[name='zone\\["+pos+"\\]\\[record\\]']").val(
36549						$('.modalDns.in [name=recordSRV]').val());
36550                        $("input[name='zone\\["+pos+"\\]\\[name\\]']").val(cur_d);*/
36551
36552						$("input[name='zone\\["+pos+"\\]\\[record\\]']").val(
36553						$('.modalDns.in [name=weightSRV]').val() + ' '
36554						+ $('.modalDns.in [name=portSRV]').val() + ' '
36555						+ $('.modalDns.in [name=targetSRV]').val());
36556
36557                        $("input[name='priority\\["+pos+"\\]']").val($('.modalDns.in [name=recordSRV]').val());
36558
36559                        if(typeof undefined !== typeof ttl) {
36560                            $("select[name='zone\\["+pos+"\\]\\[ttl\\]']").val(ttl);
36561                        }
36562
36563                        $("input[name='zone\\["+pos+"\\]\\[name\\]']").val($('.modalDns.in [name=serviceSRV]').val() + '.' + $('.modalDns.in [name=hostnameSRV]').val() + '.' + cur_d);
36564
36565                    }
36566					/*
36567                    var updatednsdata = 'zone[name]='+cur_d+'&zone[record]='+ $('.modalDns.in [name=recordSRV]').val()+'&zone[ttl]=14400&zone[type]=SRV';
36568                    */
36569					// +St:
36570					var hostCode  =
36571					  $('.modalDns.in [name=serviceSRV]').val() + '.'
36572					+ $('.modalDns.in [name=hostnameSRV]').val() + '.'
36573					/*+ $('.modalDns.in [name=recordSRV]').val() + '.'*/ + cur_d;
36574					var ValueCode =
36575					  $('.modalDns.in [name=weightSRV]').val() + ' '
36576					+ $('.modalDns.in [name=portSRV]').val() + ' '
36577					+ $('.modalDns.in [name=targetSRV]').val();
36578
36579					var updatednsdata =
36580					'zone[name]='+ hostCode + '&zone[record]='+ ValueCode+'&zone[ttl]=' + ttl + '&zone[type]=SRV&zone[priority]='+$('.modalDns.in [name=recordSRV]').val();
36581					var id = window.attr('id');
36582
36583                    updatednsdata = addCSRFToDNSData(updatednsdata);
36584
36585                    if (id.indexOf('addDns') >=0) {
36586                        $.post(Storage.getData('app_url') + 'domain/new-record/' + $('#updatezone').attr('data-uid'), updatednsdata, function(r){
36587
36588                            /*	r = JSON.parse(r);
36589                             if(r.status == 0){
36590                             $('#zone-error').html(r.msg).removeClass('hidden');
36591                             }
36592                             if(r.status == 1){
36593                             $.fancybox.close();
36594                             $('#domainflash').html(r.msg).removeClass('hidden');
36595                             }*/
36596                            $('#save-zone').button('reset');
36597                        });
36598                    } else {
36599                        $('#save-zone').button('reset');
36600                    }
36601                    //:ALIN
36602
36603                    clearDNSModal();
36604                    $('.modalDns.in').modal('hide');
36605                }
36606                break;
36607            case 'RED':
36608                var ct = true;
36609                var errors = '';
36610                $('.modalDns.in input.form-control').each(function () {
36611                    if (!ctype_print($(this).val())) {
36612                        ct = false;
36613                    };
36614                    if($(this).val() == ''){
36615                        ct = false;
36616                    }
36617                });
36618                if (!ct) {
36619                     errors += $.translate('English Only') + '\n';
36620                }
36621                if(!isValidURL( $('.modalDns.in [name=recordRED]').val() )){
36622                     errors += $.translate('Not Valid URL') + '\n';
36623                }
36624
36625                if((errors !== '')){
36626                    $('.modalDns.in .alert').html(nl2br(errors)).removeClass('hidden');
36627                    return;
36628                }else{
36629                    $('.modalDns.in .alert').addClass('hidden');
36630                    var sub = $('.modalDns.in [name=hostnameSRV]').val();
36631                    var dom = sub + '.' + cur_d + '.';
36632                    if(sub == '' || ('string' === typeof sub  && '@' == sub.trim())){
36633                        dom = cur_d + '.';
36634                    }
36635
36636                    var redtype = 301;
36637                    if($('#typered3').is(':checked')) { redtype=302;}
36638
36639                    if(pos === ''){
36640                        $('#updatezone .table tbody tr.row-red').remove();
36641                        $('#updatezone .table tbody tr').eq($('#updatezone .table tbody tr').length - 1).before('\
36642						<tr class="row-red">\
36643							<td>\
36644								<input  type="hidden" value="' + redtype + '" name="zone[' + k + '][status]">\
36645								<input readonly disabled type="text" value="' + cur_d + '" name="zone[' + k + '][name]">\
36646							</td>\
36647							<td>\
36648								<select readonly disabled name="zone['+k+'][ttl]">\
36649									<option value="3600">3600</option>\
36650									<option value="' + ttl + '" selected="selected">' + ttl + '</option>\
36651								</select>\
36652							</td>\
36653							<td>\
36654								<select readonly disabled name="zone['+k+'][type]">\
36655									<option value="NS" class="hidden">NS</option>\
36656									<option value="A">A</option>\
36657                                    <option value="AAAA">AAAA</option>\
36658									<option value="MX">MX</option>\
36659									<option value="SRV">SRV</option>\
36660									<option value="TXT">TXT</option>\
36661									<option value="CNAME">CNAME</option>\
36662									<option value="HTTPRED"  selected="selected">HTTPRED</option>\
36663								</select>\
36664							</td>\
36665							<td>\
36666								<input readonly disabled type="text" value="'+ $('.modalDns.in [name=recordRED]').val()  +'" name="zone['+k+'][record]">\
36667							</td>\
36668							<td>\
36669								<a class="delZoneEntry" href="#del" title="מחיקה">\
36670									<span class="glyphicon glyphicon-trash"></span></a>\
36671								<a class="editZoneEntry" href="#edit" title="מחיקה">\
36672									<span class="glyphicon glyphicon-edit"></span></a>\
36673								</td>\
36674						<tr>\
36675					');
36676                    } else {
36677                        $("input[name='zone\\["+pos+"\\]\\[record\\]']").val($('.modalDns.in [name=recordRED]').val());
36678                        $("input[name='zone\\["+pos+"\\]\\[name\\]']").val(cur_d);
36679                        $("input[name='zone\\["+pos+"\\]\\[status\\]']").val(redtype);
36680                        if(typeof undefined !== typeof ttl) {
36681                            $("select[name='zone\\["+pos+"\\]\\[ttl\\]']").val(ttl);
36682                        }
36683                    }
36684
36685
36686                    var zone = {
36687                        name: cur_d,
36688                        redtype: redtype,
36689                        record: $('.modalDns.in [name=recordRED]').val(),
36690                        ttl: ttl,
36691                        type: 'HTTPRED'
36692                    };
36693
36694                    var updatednsdata = {
36695                        zone: zone
36696                    };
36697
36698                    var id = window.attr('id');
36699
36700                    updatednsdata = addCSRFToDNSData(updatednsdata);
36701
36702                    if (id.indexOf('addDns') >=0)
36703                    {
36704                        $.post(Storage.getData('app_url') + 'domain/new-record/' + $('#updatezone').attr('data-uid'), updatednsdata, function(r){
36705                            /*	r = JSON.parse(r);
36706                             if(r.status == 0){
36707                             $('#zone-error').html(r.msg).removeClass('hidden');
36708                             }
36709                             if(r.status == 1){
36710                             $.fancybox.close();
36711                             $('#domainflash').html(r.msg).removeClass('hidden');
36712                             }*/
36713                            $('#save-zone').button('reset');
36714                        });
36715                    }
36716                    else
36717                    {
36718                        $.post(Storage.getData('app_url') + 'domain/update-record/' + cur_d, $.extend({}, updatednsdata, { uid: $('#updatezone').attr('data-uid') }), function(r){
36719                            /*r = JSON.parse(r);
36720                             if(r.status == 0){
36721                             $('#zone-error').html(r.msg).removeClass('hidden');
36722                             }
36723                             if(r.status == 1){
36724                             $.fancybox.close();
36725                             $('#domainflash').html(r.msg).removeClass('hidden');
36726                             }*/
36727                            $('#save-zone').button('reset');
36728                        });
36729                    }
36730                    //:ALIN
36731
36732                    clearDNSModal();
36733                    $('.modalDns.in').modal('hide');
36734                }
36735                break;
36736        }
36737    })
36738    $(document).on('click', '.delZoneEntry', function(e){
36739      e.preventDefault();
36740
36741      var
36742          del           = $(this),
36743          recordID      = $(this).closest('tr').find('input[name=recordID]').val(),
36744          form          = del.closest('#updatezone'),
36745          csrfConfig    = Storage.getData('csrf_config'),
36746          tokenKey      = csrfConfig['token_key'],
36747          tokenNameKey  = csrfConfig['token_name_key'],
36748          csrfToken     = form.find('[name=csrf_token]').val(),
36749          csrfTokenName = form.find('[name=csrf_token_name]').val(),
36750          updatednsdata = "type="+$(this).closest('tr').find(".zoneType").val()
36751      ;
36752
36753        updatednsdata += '&'+tokenKey+'='+csrfToken+'&'+tokenNameKey+'='+csrfTokenName;
36754
36755        if ($(this).closest('tr').find(".zoneType").val() === 'HTTPRED'){
36756            recordID = $(this).closest('tr').find(".zoneName").val();
36757
36758            $.post(Storage.getData('app_url') + 'domain/delete-record/' + recordID, updatednsdata + '&uid=' + $('#updatezone').attr('data-uid'), function(r){
36759                /*	r = JSON.parse(r);
36760                 if(r.status == 0){
36761                 $('#zone-error').html(r.msg).removeClass('hidden');
36762                 }
36763                 if(r.status == 1){
36764                 $.fancybox.close();
36765                 $('#domainflash').html(r.msg).removeClass('hidden');
36766                 }*/
36767
36768            });
36769        }
36770
36771
36772        del.parent().parent().remove();
36773
36774    });
36775    $(document).on('click', '#save-zone', function(e){
36776        e.preventDefault();
36777
36778        var recordsCount = $("#updatezone").find('table tbody tr').length;
36779        if(recordsCount > 100){
36780            var error =  $.translate('Maximum 100 records allowed!');
36781            $('#zone-error').html(error).removeClass('hidden');
36782            return false;
36783        }
36784
36785        $('#zone-error').addClass('hidden');
36786        $('#save-zone').button('loading');
36787        var errors = '';
36788        var ct = true;
36789        $('#updatezone input').each(function () {
36790            if (!ctype_print_heb($(this).val())) {
36791                ct = false;
36792            };
36793        });
36794        if (!ct) {
36795            errors += $.translate('English Only') + '\n';
36796        }
36797        if(errors !== ''){
36798            $('#zone-error').html(nl2br(errors, true)).removeClass('hidden');
36799            $('#save-zone').button('reset');
36800        } else {
36801            $("#updatezone").find(':input:disabled').prop('disabled', false);
36802            var updatednsdata = $('#updatezone').serialize();
36803            $("#updatezone").find(':input').prop('disabled', true);
36804
36805            $.post(Storage.getData('app_url') + 'domain/update-dns/' + $('#updatezone').attr('data-uid'), updatednsdata, function(r){
36806                r = JSON.parse(r);
36807                if(r.status == 0){
36808                    $('#zone-error').html(r.msg).removeClass('hidden');
36809                }
36810                if(r.status == 1){
36811                    $.fancybox.close();
36812                    $('#domainflash').html(r.msg).removeClass('hidden');
36813                }
36814                $('#save-zone').button('reset');
36815            })
36816        }
36817    })
36818    $(document).on('click', '#dnsChoser a', function (e) {
36819        e.preventDefault();
36820        if (!$(this).parent().hasClass('disabled')) {
36821            $(this).tab('show');
36822        }
36823    });
36824
36825    var isZoneEditorLocked = function () {
36826        var $overlay = $('#zone-editor-disclaimer');
36827        return $overlay.length && $overlay.is(':visible');
36828    };
36829
36830    $(document).on('change', '#zone-editor-agree-check', function () {
36831        $('#zone-editor-agree-btn').prop('disabled', !this.checked);
36832    });
36833
36834    $(document).on('click', '#zone-editor-agree-btn', function (e) {
36835        e.preventDefault();
36836        if (!$('#zone-editor-agree-check').is(':checked')) {
36837            return false;
36838        }
36839        $('.zone-editor-lock-wrap').addClass('is-unlocked');
36840        $('#zone-editor-disclaimer').hide();
36841    });
36842
36843    $(document).on('click', '#addDnsRow button, a.editZoneEntry, a.delZoneEntry, #save-zone', function (e) {
36844        if (isZoneEditorLocked()) {
36845            e.preventDefault();
36846            e.stopImmediatePropagation();
36847            return false;
36848        }
36849    });
36850
36851    // $(document).on('click', '#action-show-terms', function (e) {
36852    //     $.fancybox({
36853    //         href: $(this).attr('href'),
36854    //         type: 'iframe'
36855    //     });
36856
36857    //     e.preventDefault();
36858    // });
36859
36860    $(document).on('click', '#renew-domain #checkCoupon', function (e) {
36861        var cpn = $('#couponCode').val();
36862        $('#cpn-error').addClass('hidden');
36863        //$('#cpnDis').addClass('hidden');
36864        $(this).button('loading');
36865        $('#creditDetails input[type=text]').parent().show();
36866        $('#creditDetails select').parent().show();
36867        $('#creditNumber').val('');
36868        $('#creditExpirationYear option').eq(0).prop('selected', true);
36869        $('#creditExpirationMonth option').eq(0).prop('selected', true);
36870        $('#creditCvv').val('');
36871        $('#creditId').val('');
36872        $.get(Storage.getData('app_url') + 'checkCpn/' + cpn, '', function (r) {
36873            r = parseFloat(r);
36874            if (r <= 0) {
36875                $('#cpn-error').removeClass('hidden');
36876                $('#cpnDis').addClass('hidden');
36877            } else {
36878                $('#cpn-error').addClass('hidden');
36879                var price = $('#renew-domain .UIInfoBox > span > span').html();
36880                var dis = price - r;
36881                if (dis <= 0) {
36882                    dis = 0;
36883                    $('#creditDetails input[type=text]').parent().hide();
36884                    $('#creditDetails select').parent().hide();
36885                    $('#creditNumber').val('378282246310005');
36886                    $('#creditExpirationYear').val(new Date().getFullYear() + 5);
36887                    $('#creditExpirationMonth').val(12);
36888                    $('#creditCvv').val(123);
36889                    $('#creditId').val(123456789);
36890                }
36891                $('.amount').html(price);
36892                $('.sum').html(Number(dis).toFixed(2))
36893                $('#cpnDis').removeClass('hidden');
36894            }
36895            $('#checkCoupon').button('reset');
36896        });
36897        $('#checkCoupon').button('reset');
36898    })
36899    $(document).on('click', '#domain_order #checkCoupon', function (e) {
36900        var cpn = $('#couponCode').val();
36901        var placeholder = '<div class="col-md-6" id="enomPlaceholder" style="height: 200px;"></div>';
36902        $('#cpn-error').addClass('hidden');
36903        //$('#cpnDis').addClass('hidden');
36904        $(this).button('loading');
36905        $.get(Storage.getData('app_url') + 'checkCpn/' + cpn, '', function (r) {
36906            r = parseFloat(r);
36907            $('#creditNumber').val('');
36908            $('#creditExpirationYear option').eq(0).prop('selected', true);
36909            $('#creditExpirationMonth option').eq(0).prop('selected', true);
36910            $('#creditCvv').val('');
36911            $('#creditId').val('');
36912            $('#enomPlaceholder').remove();
36913            $('#creditDetails input[type=text]').parent().show();
36914            $('#creditDetails select').parent().show();
36915            if (r <= 0) {
36916                $('#cpn-error').removeClass('hidden');
36917                $('#cpnDis').addClass('hidden');
36918            } else {
36919                $('#cpn-error').addClass('hidden');
36920                var price = $('#creditCardDetails .UISection span span').html();
36921                var dis = price - r;
36922                if (dis <= 0) {
36923                    dis = 0;
36924                    $('#creditDetails').before(placeholder);
36925                    $('#creditDetails input[type=text]').parent().hide();
36926                    $('#creditDetails select').parent().hide();
36927                    $('#creditNumber').val('378282246310005');
36928                    $('#creditExpirationYear').val(new Date().getFullYear() + 5);
36929                    $('#creditExpirationMonth').val(12);
36930                    $('#creditCvv').val(123);
36931                    $('#creditId').val(123456789);
36932                }
36933
36934                $('#cpnDis .amount').html(price);
36935                $('#cpnDis .sum').html(Number(dis).toFixed(2))
36936                $('#cpnDis').removeClass('hidden');
36937                // $(this).attr("disabled", disable);
36938            }
36939            $('#checkCoupon').button('reset');
36940        });
36941    });
36942
36943    $(document).on('click', '.admin-domain-info', function (e) {
36944        e.preventDefault();
36945
36946        $.showXHRModal($(this).attr('href'), function () {$('.fancybox-overlay.fancybox-overlay-fixed').css("z-index", 15104);}, {'title': 'Domain info'});
36947
36948    });
36949
36950    $(document).on('click', '.transfer-acc', function (e) {
36951        e.preventDefault();
36952        var uid = $(this).parent().parent().data('uid');
36953        $.get(Storage.getData('app_url') + 'domain/transfer-acc/' + uid, function (r) {
36954            $.fancybox.open({
36955                type: 'iframe',
36956                padding: 0,
36957                content: r,
36958                afterShow: function () {
36959
36960                    $('#transfer-acc-domain').click(function (e) {
36961                        e.preventDefault();
36962                        $(this).button('loading');
36963                        var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
36964                        var emailEl = $('#userEmail');
36965                        var email = emailEl.val();
36966                        var errors = '';
36967                        if (!re.test(email) || email === '') {
36968                            emailEl.parent().addClass('has-error');
36969                            errors += $.translate('Email is invalid') + '\n';
36970                        }
36971                        else {
36972                            emailEl.parent().removeClass('has-error');
36973                        }
36974                        if (errors !== '') {
36975                            $('#transfer-acc-errors').html(nl2br(errors, true)).removeClass('hidden');
36976                            $(this).button('reset');
36977                        } else {
36978                            $('#transfer-acc-errors').addClass('hidden');
36979                            $.post($('#transfer-acc').attr('action') + '/' + uid, $('#transfer-acc').serialize(), function (r) {
36980                                if (r.status == 1) {
36981                                    $('#domainflash').html(r.msg).removeClass('hidden');
36982                                    $('#transfer-acc').addClass('hidden');
36983                                    $('tr[data-uid="' + uid + '"]').remove();
36984                                    $.fancybox.close();
36985                                }
36986                                if (r.status == 0) {
36987                                    $('#transfer-acc-errors').html(nl2br(r.msg, true)).removeClass('hidden');
36988                                }
36989                                $('#transfer-acc-domain').button('reset');
36990                            })
36991                        }
36992                    });
36993
36994                    $('#transfer-security-code-confirm').click(function (e) {
36995                        e.preventDefault();
36996                        $('#transfer-security-code-initial').addClass('hidden');
36997                        $('#transfer-security-code-contact').removeClass('hidden');
36998                    });
36999
37000
37001                    $('#transfer-security-code-contact-yes').click(function (e) {
37002                        e.preventDefault();
37003                        $('#line-loader-transfer-security-code').removeClass('hidden');
37004                        var uid = $(this).attr('domain-id');
37005                        $('#transfer-security-code-contact').addClass('hidden');
37006
37007                        var
37008                            button = $(this),
37009                            errorContainer = $('#transfer-acc-errors')
37010                        ;
37011                        $(this).button('loading');
37012
37013                        $.get('/domain/contact-transfer-code-xhr/' + uid, function (r) {
37014                            button.button('reset');
37015
37016                            if (r.status) {
37017                              var msgContainer = $('#transfer-security-code-message-container');
37018
37019                              errorContainer.addClass('hidden');
37020
37021                              msgContainer.find('span').html(r.msg);
37022
37023                              button.hide(function () {
37024                                msgContainer.removeClass('hidden');
37025                                $('#line-loader-transfer-security-code').addClass('hidden');
37026                              });
37027                            } else {
37028                              errorContainer.html(nl2br(r.msg, true)).removeClass('hidden');
37029                              $('#line-loader-transfer-security-code').addClass('hidden');
37030                            }
37031                        });
37032
37033                        // TODO: Send AJAX to mark user wants callback
37034                        // $.post('/domain/mark-callback-request', {domain_id: uid});
37035                        
37036                        // Then get transfer code
37037                        //getTransferCode($(this), uid);
37038                    });
37039
37040                    $('#transfer-security-code-generation').click(function (e) {
37041                        $('#line-loader-transfer-security-code').removeClass('hidden');
37042                        var
37043                            button = $(this),
37044                            uid = button.attr('domain-id'),
37045                            errorContainer = $('#transfer-acc-errors')
37046                        ;
37047                        $('#transfer-security-code-contact').addClass('hidden');
37048                        e.preventDefault();
37049                        $(this).button('loading');
37050
37051                        $.get('/domain/get-transfer-code-xhr/' + uid, function (r) {
37052                            button.button('reset');
37053
37054                            if (r.status) {
37055                              var msgContainer = $('#transfer-security-code-message-container');
37056
37057                              errorContainer.addClass('hidden');
37058
37059                              msgContainer.find('span').html(r.msg);
37060
37061                              button.hide(function () {
37062                                msgContainer.removeClass('hidden');
37063                                $('#line-loader-transfer-security-code').addClass('hidden');
37064                              });
37065                            } else {
37066                              errorContainer.html(nl2br(r.msg, true)).removeClass('hidden');
37067                              $('#line-loader-transfer-security-code').addClass('hidden');
37068                            }
37069                        });
37070                    });
37071
37072
37073                    // Remove previous handlers to prevent double registration
37074                    $(document).off('change', '#lockstateToggle');
37075                    
37076                    $(document).on('change', '#lockstateToggle', function(e) {
37077                        e.preventDefault();
37078                        e.stopImmediatePropagation();
37079                        
37080                        // Check if there is a request in progress
37081                        var $toggle = $(this);
37082                        if ($toggle.data('processing')) {
37083                            return false;
37084                        }
37085                        
37086                        $toggle.data('processing', true);
37087                        $('#line-loader-lockstate').removeClass('hidden');
37088                        $('.lockstateSlider').addClass('hidden');
37089                        $('#DomainLockStatusLabel').addClass('hidden');
37090                        var isLocked = $toggle.is(':checked');
37091                        var label = $('#DomainLockStatusLabel');
37092                        if (isLocked) {
37093                            label.addClass('locked');
37094                            label.removeClass('unlocked');
37095                        } else {
37096                            label.addClass('unlocked');
37097                            label.removeClass('locked');
37098                        }
37099                
37100                        var data = {
37101                            lockstate: isLocked ? 1 : 0
37102                        };
37103                        var uid = $toggle.data('uid');
37104                        var url = Storage.getData('app_url') + 'domain/lockDomain/' + uid;
37105                        var csrfConfig = Storage.getData('csrf_config');
37106                        var form = $toggle.closest('form');
37107                        data[csrfConfig['token_name_key']] = form.find('[name=csrf_token_name]').val();
37108                        data[csrfConfig['token_key']]      = form.find('[name=csrf_token]').val();
37109                
37110                        $.post(url, data, function (r) {
37111                            r = JSON.parse(r);
37112                            $toggle.data('processing', false);
37113                            
37114                            if (r.status == 0) {
37115                                $('#lockstate-errors').html(r.msg).removeClass('hidden');
37116                                $('#line-loader-lockstate').addClass('hidden');
37117                            }
37118                            if (r.status == 1) {
37119                                $('#lockstate-suc').html(r.msg).removeClass('hidden');
37120                                $('#line-loader-lockstate').addClass('hidden');
37121                                
37122                                // update lock button text and title
37123                                var lockButton = $('tr[data-uid="' + uid + '"] .lock.transfer-acc');
37124                                if (isLocked) {
37125                                    lockButton.removeClass('icon-unlock').addClass('icon-lock');
37126                                    lockButton.attr('title', r.msg);
37127                                } else {
37128                                    lockButton.removeClass('icon-lock').addClass('icon-unlock');
37129                                    lockButton.attr('title', r.msg);
37130                                }
37131                            }
37132                        }).fail(function() {
37133                            $toggle.data('processing', false);
37134                            $('#line-loader-lockstate').addClass('hidden');
37135                        });
37136                    });
37137                }
37138            });
37139        })
37140    });
37141    $('#getthis, .option .add_btn').click(function (e) {
37142        e.preventDefault();
37143        var inDomain = $('input[name=check-domain]').val();
37144        if (!stristr(inDomain, '.')) {
37145            inDomain += '.co.il';
37146        }
37147        if ($(this).hasClass('add_btn')) {
37148            var domainparts = inDomain.split('.');
37149            var domain = domainparts[0];
37150            inDomain = domain + $(this).data('tld');
37151        }
37152        // setCookie('domain', inDomain, 1);
37153
37154        $.get(Storage.getData('app_url') + 'domain/pre-info', {'dname': inDomain}, function (data) {
37155            if(data.success) {
37156              window.location.href = data.page;
37157            }
37158        });
37159    });
37160
37161    $(document).on('click', '#invoices,#contacts,#mDomains,#settings', function (e) {
37162        if($(this).attr('id') == 'mDomains' && $(this).hasClass('active')){
37163            return true;
37164        }
37165        e.preventDefault();
37166        $('#invoices,#contacts,#mDomains,#settings').removeClass('active');
37167        $(this).addClass('active');
37168        var id = $(this).attr('id');
37169        var domains = $('#domain-cont');
37170        var contacts = $('#contacts-cont');
37171        var invoices = $('#invoices-cont');
37172		var settings = $('#account-settings-cont');
37173        if (id == 'mDomains') {
37174            domains.removeClass('hidden');
37175            contacts.addClass('hidden');
37176            invoices.addClass('hidden');
37177			settings.addClass('hidden');
37178        }
37179        if (id == 'contacts') {
37180            contacts.removeClass('hidden');
37181            domains.addClass('hidden');
37182            invoices.addClass('hidden');
37183			settings.addClass('hidden');
37184        }
37185        if (id == 'invoices') {
37186            invoices.removeClass('hidden');
37187            domains.addClass('hidden');
37188            contacts.addClass('hidden');
37189			settings.addClass('hidden');
37190        }
37191		if (id == 'settings') {
37192			settings.removeClass('hidden');
37193			domains.addClass('hidden');
37194            invoices.addClass('hidden');
37195			contacts.addClass('hidden');
37196		}
37197    });
37198    $(document).on('click', '.update-contact', function (e) {
37199        e.preventDefault();
37200        var uid = $(this).parent().parent().data('uid');
37201        $.get(Storage.getData('app_url') + 'contacts/update/' + uid, function (r) {
37202            $.fancybox.open({
37203                content: r,
37204                padding: 0,
37205                type: 'iframe',
37206                afterShow: function () {
37207                    $('#saveContact').click(function (e) {
37208                        e.preventDefault();
37209                        var form = $(this).closest('form');
37210                        var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
37211                        var emailEl = form.find('#contactEmail');
37212                        var priPhoneEl = form.find('#contactLanding');
37213                        var streetEl = form.find('#contactStreet');
37214                        var cityEl = form.find('#contactCity');
37215                        var countryEl = form.find('#contactCountry');
37216                        var zipEl = form.find('#contactZip');
37217                        var email = emailEl.val();
37218                        var street = streetEl.val();
37219                        var city = cityEl.val();
37220                        var country = countryEl.val();
37221                        var zip = zipEl.val();
37222                        var phone1 = form.find('#tel1').val();
37223                        var phone2 = form.find('#tel2').val(validatePerf(form.find('#tel2').val())).val();
37224                        var phone3 = form.find('#tel3').val();
37225                        var fax1 = form.find('#fax1').val();
37226                        var fax2 = form.find('#fax2').val(validatePerf(form.find('#fax2').val())).val();
37227                        var fax3 = form.find('#fax3').val();
37228                        priPhoneEl.val(phone3 + ' ' + phone2 + ' ' + phone1);
37229                        form.find('#contactFax').val(fax3 + ' ' + fax2 + ' ' + fax1);
37230                        var priPhone = priPhoneEl.val();
37231                        var errors = '';
37232                        var ct = true;
37233                        $('#contactEdit input').each(function () {
37234                            if (!ctype_print($(this).val())) {
37235                                ct = false;
37236                            }
37237                            ;
37238                        });
37239                        if (!ct) {
37240                            errors += $.translate('English Only') + '\n';
37241                        }
37242                        if (!re.test(email) || email === '') {
37243                            emailEl.parent().addClass('has-error');
37244                            errors += $.translate('Email is invalid') + '\n';
37245                        }
37246                        else {
37247                            emailEl.parent().removeClass('has-error');
37248                        }
37249                        if (priPhone === '' || priPhone.length < 13 || !/[0-9\s]+/.test(priPhone)) {
37250                            priPhoneEl.parent().addClass('has-error');
37251                            errors += $.translate('Primary phone is required') + '\n';
37252                        }
37253                        else {
37254                            priPhoneEl.parent().removeClass('has-error');
37255                        }
37256                        if (street === '' || street.length < 2 || !/[0-9]/.test(street)) {
37257                            streetEl.parent().addClass('has-error');
37258                            errors += $.translate('Street is required') + '\n';
37259                        }
37260                        else {
37261                            streetEl.parent().removeClass('has-error');
37262                        }
37263                        if (city === '' || city.length < 2 || /[0-9]/.test(city)) {
37264                            cityEl.parent().addClass('has-error');
37265                            errors += $.translate('City is required') + '\n';
37266                        }
37267                        else {
37268                            cityEl.parent().removeClass('has-error');
37269                        }
37270                        if (zip === '' || zip.length !== 7) {
37271                            zipEl.parent().addClass('has-error');
37272                            errors += $.translate('Zip is required') + '\n';
37273                        } else if (window.isInvalidZipCode(zip)) {
37274                            zipEl.parent().addClass('has-error');
37275                            errors += $.translate('Zip is invalid') + '\n';
37276                        } else {
37277                            zipEl.parent().removeClass('has-error');
37278                        }
37279                        if (country === '') {
37280                            countryEl.parent().addClass('has-error');
37281                            errors += $.translate('Country is required') + '\n';
37282                        }
37283                        else {
37284                            countryEl.parent().removeClass('has-error');
37285                        }
37286                        if (errors !== '') {
37287                            $('#contact-modal-error').html(nl2br(errors, true)).removeClass('hidden');
37288                        } else {
37289                            $('#contact-modal-error').addClass('hidden');
37290                            $.post($('#contactEdit').attr('action') + '/' + uid, $('#contactEdit').serialize(), function (r) {
37291                                r = JSON.parse(r);
37292                                if (r.status == 1) {
37293                                    $('#contactsflash').html(r.msg).removeClass('hidden');
37294                                    $('#contact-modal-error').addClass('hidden');
37295                                    $.fancybox.close();
37296                                }
37297                                if (r.status == 0) {
37298                                    $('#contact-modal-error').html(nl2br(r.msg, true)).removeClass('hidden');
37299                                }
37300                            })
37301                        }
37302
37303                    })
37304                }
37305            });
37306        });
37307    });
37308    $(document).on('click', '.delete-contact', function (e) {
37309        e.preventDefault();
37310        var con = confirm($.translate('Are you sure?'));
37311        if (con) {
37312            var uid = $(this).parent().parent().data('uid');
37313            $.get(Storage.getData('app_url') + 'contacts/remove/' + uid, function (r) {
37314                r = JSON.parse(r);
37315                if (r.status == 0) {
37316                    window.location = Storage.getData('app_url') + 'user/login';
37317                }
37318                if (r.status == 1) {
37319                    $.get(Storage.getData('app_url') + '/contacts/list', function (data) {
37320                        $('#contacts-cont').html(data);
37321                    })
37322                }
37323                if (r.status == 2) {
37324                    alert(r.msg);
37325                }
37326            });
37327        } else {
37328            return;
37329        }
37330    });
37331    $(document).on('click', '#addContact', function (e) {
37332        e.preventDefault();
37333        $.get(Storage.getData('app_url') + 'contacts/add', function (r) {
37334            $.fancybox.open({
37335                content: r,
37336                padding: 0,
37337                type: 'iframe',
37338                afterShow: function () {
37339                    $('#saveContact').click(function (e) {
37340                        e.preventDefault();
37341                        var form = $(this).closest('form');
37342                        var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
37343                        var emailEl = form.find('#contactEmail');
37344                        var priPhoneEl = form.find('#contactLanding');
37345                        var streetEl = form.find('#contactStreet');
37346                        var cityEl = form.find('#contactCity');
37347                        var countryEl = form.find('#contactCountry');
37348                        var zipEl = form.find('#contactZip');
37349                        var fullNameEl = form.find('#contactFullName');
37350                        var fullName = fullNameEl.val();
37351                        var email = emailEl.val();
37352                        var street = streetEl.val();
37353                        var city = cityEl.val();
37354                        var country = countryEl.val();
37355                        var zip = zipEl.val();
37356                        var phone1 = form.find('#tel1').val();
37357                        var phone2 = form.find('#tel2').val(validatePerf(form.find('#tel2').val())).val();
37358                        var phone3 = form.find('#tel3').val();
37359                        var fax1 = form.find('#fax1').val();
37360                        var fax2 = form.find('#fax2').val(validatePerf(form.find('#fax2').val())).val();
37361                        var fax3 = form.find('#fax3').val();
37362                        priPhoneEl.val(phone3 + ' ' + phone2 + ' ' + phone1);
37363                        form.find('#contactFax').val(fax3 + ' ' + fax2 + ' ' + fax1);
37364                        var priPhone = priPhoneEl.val();
37365                        var errors = '';
37366                        var ct = true;
37367                        form.find('input').each(function () {
37368                            if (!ctype_print($(this).val())) {
37369                                ct = false;
37370                            }
37371                            ;
37372                        });
37373                        if (!ct) {
37374                            errors += $.translate('English Only') + '\n';
37375                        }
37376                        if (fullName === '' || fullName.length < 5 || fullName.split(' ').length < 2) {
37377                            fullNameEl.parent().addClass('has-error');
37378                            errors += $.translate('full name is required') + '\n';
37379                        }
37380                        else {
37381                            fullNameEl.parent().removeClass('has-error');
37382                        }
37383                        if (!re.test(email) || email === '') {
37384                            emailEl.parent().addClass('has-error');
37385                            errors += $.translate('Email is invalid') + '\n';
37386                        }
37387                        else {
37388                            emailEl.parent().removeClass('has-error');
37389                        }
37390                        if (priPhone === '' || priPhone.length < 13 || !/[0-9\s]+/.test(priPhone)) {
37391                            priPhoneEl.parent().addClass('has-error');
37392                            errors += $.translate('Primary phone is required') + '\n';
37393                        }
37394                        else {
37395                            priPhoneEl.parent().removeClass('has-error');
37396                        }
37397                        if (street === '' || street.length < 2 || !/[0-9]/.test(street)) {
37398                            streetEl.parent().addClass('has-error');
37399                            errors += $.translate('Street is required') + '\n';
37400                        }
37401                        else {
37402                            streetEl.parent().removeClass('has-error');
37403                        }
37404                        if (city === '' || city.length < 2 || /[0-9]/.test(city)) {
37405                            cityEl.parent().addClass('has-error');
37406                            errors += $.translate('City is required') + '\n';
37407                        }
37408                        else {
37409                            cityEl.parent().removeClass('has-error');
37410                        }
37411                        if (zip === '' || zip.length !== 7) {
37412                            zipEl.parent().addClass('has-error');
37413                            errors += $.translate('Zip is required') + '\n';
37414                        } else if (window.isInvalidZipCode(zip)) {
37415                            zipEl.parent().addClass('has-error');
37416                            errors += $.translate('Zip is invalid') + '\n';
37417                        } else {
37418                            zipEl.parent().removeClass('has-error');
37419                        }
37420                        if (country === '') {
37421                            countryEl.parent().addClass('has-error');
37422                            errors += $.translate('Country is required') + '\n';
37423                        }
37424                        else {
37425                            countryEl.parent().removeClass('has-error');
37426                        }
37427                        if (errors !== '') {
37428                            form.find('#contact-modal-error').html(nl2br(errors, true)).removeClass('hidden');
37429                        } else {
37430                            form.find('#contact-modal-error').addClass('hidden');
37431                            $.post(form.attr('action'), form.serialize(), function (r) {
37432                                r = JSON.parse(r);
37433                                if (r.status == 1) {
37434                                    //alert(r.msg);
37435                                    $('#contactsflash').html(nl2br(r.msg, true)).removeClass('hidden');
37436                                    form.find('#contact-modal-error').addClass('hidden');
37437                                    $.fancybox.close();
37438                                }
37439                                if (r.status == 0) {
37440                                    form.find('#contact-modal-error').html(nl2br(r.msg, true)).removeClass('hidden');
37441                                }
37442                            })
37443                        }
37444
37445                    })
37446                }
37447            });
37448        });
37449    });
37450    $(document).on('submit', '#user-auth-login form', function (e) {
37451        $('#user-auth-login-submit').button('loading');
37452        e.preventDefault();
37453        $('#upgrade-ntc').addClass('hidden');
37454        $('#login-errors').addClass('hidden');
37455
37456        $.post($(this).getFormSubmitPath(), $(this).serialize(), function (data) {
37457            console.log(data.status);
37458            if (data.status == 0) {
37459                $('#user-auth-login-submit').button('reset');
37460                $('#login-errors').removeClass('hidden').html(data.msg);
37461            }
37462            if (data.status == 1) {
37463                window.location = data.page;
37464                $.localStorage.set('domains_bulk', []);
37465                e.stopPropagation();
37466                return false;
37467            }
37468            if (data.status == 2) {
37469                $('#user-auth-login-submit').button('reset');
37470                $('#upgrade-ntc').removeClass('hidden');
37471            }
37472            if (data.status == 3) {
37473                $('#user-auth-login-submit').button('reset');
37474                $('#user-auth-login-email').addClass('disabled');
37475                $('#user-auth-login-password').addClass('disabled');
37476                $('#user-auth-login-code').prop('disabled', false);
37477
37478                $('#form-user-auth-block').addClass('hidden');
37479                $('#form-user-auth-tfa-block').removeClass('hidden');
37480            }
37481        });
37482    });
37483
37484    // email verify
37485    $(document).on('click', '#form-user-auth-email-verify-resend', function (e) {
37486        e.preventDefault();
37487
37488        $.post(Storage.getData('app_url') + 'user/email/verify/resend', {}, function (response) {
37489            if (response.status == 0) {
37490                $('#email-verify-errors').removeClass('hidden').html(response.msg);
37491            }
37492            if (response.status == 1) {
37493                if(undefined != response.message && undefined != response.message.text && undefined != response.message.title) {
37494                    $.showSuccess(response.message.title, response.message.text);
37495                }
37496
37497                return false;
37498            }
37499        });
37500    });
37501
37502    $(document).on('submit', '#user-email-verify-form', function (e) {
37503        $('#user-email-verify-submit').button('loading');
37504        $('#email-verify-errors').addClass('hidden');
37505        e.preventDefault();
37506
37507        $.post($(this).getFormSubmitPath(), $(this).serialize(), function (data) {
37508            if (data.status == 0) {
37509                $('#user-email-verify-submit').button('reset');
37510                $('#email-verify-errors').removeClass('hidden').html(data.msg);
37511            }
37512            if (data.status == 1) {
37513                window.location = Storage.getData('app_url') + 'user/account';
37514            }
37515        });
37516    });
37517
37518    // redirect from user/account page to search domain page
37519    $(document).on('submit', '#whois.account-page', function(e) {
37520        e.preventDefault();
37521
37522        var inDomain = $('input[name=check-domain]').val();
37523
37524        if('' == inDomain) {
37525            return false;
37526        }
37527        var normalizedDomain = inDomain.trim()
37528        .toLowerCase()
37529        .replace(/^https?:\/\//i, '')  // Remove http:// or https://
37530        .replace(/^www\./i, '')         // Remove www. prefix
37531        .replace(/[^\u0590-\u05FF\w\.\-]/g, '');  // Keep only letters (including Hebrew), numbers, dots, hyphens
37532
37533        // Additional validation: ensure it's not empty after normalization
37534        if('' == normalizedDomain) {
37535            return false;
37536        }
37537        $(this).find('button').button('loading');
37538
37539        window.location.href = "/?check-domain=" + encodeURIComponent(normalizedDomain) + 
37540                          "&csrf_token_name=whois&csrf_token=" + 
37541                          $(this).find('input[name=csrf_token]').val();
37542    });
37543
37544    $(document).on('submit', '#whois:not(.account-page)', whois);
37545    function whois(e) {
37546        e.preventDefault();
37547        $('#check-domain').button('loading');
37548        var inDomain = $('input[name=check-domain]').val();
37549        
37550        // Clean domain: remove protocol, www, paths, ports
37551        inDomain = inDomain.trim();
37552        inDomain = inDomain.replace(/^[a-z]+:\/\//i, ''); // Remove protocol
37553        inDomain = inDomain.replace(/^www\./i, ''); // Remove www
37554        inDomain = inDomain.split('/')[0]; // Remove path
37555        inDomain = inDomain.split('?')[0]; // Remove query string
37556        inDomain = inDomain.split('#')[0]; // Remove hash
37557        inDomain = inDomain.replace(/:\d+$/, ''); // Remove port
37558        inDomain = inDomain.toLowerCase();
37559
37560        window.location.href = "/?check-domain=" + inDomain + "&csrf_token_name=whois&csrf_token=" + $(this).find('input[name=csrf_token]').val();
37561
37562        return false;
37563    }
37564
37565    $(document).on('submit', '#user-auth-password-reset-form', function (e) {
37566        e.preventDefault();
37567        $('#user-auth-password-reset-submit').button('loading');
37568        $('#forgot-errors').addClass('hidden');
37569        $('#forgot-success').addClass('hidden');
37570        $.post($(this).attr('action'), $(this).serialize(), function (data) {
37571            data = JSON.parse(data);
37572            if (data.status === 0) {
37573                $('#forgot-errors').removeClass('hidden').html(data.msg);
37574                $('#user-auth-password-reset-submit').button('reset');
37575            }
37576            if (data.status === 1) {
37577                // todo@alexbuturlakin: Will move "css({'font-size': '15px'})" to less in next commit "enom price and refactoring"
37578                $('#forgot-success').removeClass('hidden').css({'font-size': '15px'}).html(data.msg);
37579                $('#user-auth-password-reset-submit').button('reset');
37580            }
37581        });
37582    });
37583
37584
37585    $(document).on('click', '.option .whoisData', function (e) {
37586        var data = {
37587            domain: cur_domain + $(this).data('tld')
37588        };
37589        var csrfConfig = Storage.getData('csrf_config');
37590        var parent     = $(this).closest('.actions');
37591
37592        data[csrfConfig['token_name_key']] = parent.find('[name=csrf_token_name]').val();
37593        data[csrfConfig['token_key']]      = parent.find('[name=csrf_token]').val();
37594
37595        $.post(Storage.getData('app_url') + 'whois/info', data, function (data) {
37596            e.preventDefault();
37597            data = data.replace(/&/g, '&amp;')
37598                .replace(/>/g, '&gt;')
37599                .replace(/</g, '&lt;')
37600                .replace(/\n/g, '<br>');
37601            $.fancybox({
37602                content: ' <div class="modal-header"><h3>whois</h3></div><div  class="whois_wrap"">' + data + '</div>',
37603                padding: 0,
37604                type: 'iframe',
37605                width: 600
37606            });
37607        });
37608    });
37609
37610
37611    $(document).on('click', 'a#newSearch', function (e) {
37612        e.preventDefault();
37613        $('#alerts_row').addClass('hidden');
37614        $("#ok").addClass('hidden');
37615        $("#error").addClass('hidden ');
37616        $('#re-search-domain').removeClass('hidden');
37617        $('.hpsearatopr').hide();
37618        $('.option .progressWhois').show();
37619        $('.option .avilable').hide();
37620        $('.option .add_btn').hide();
37621        $('.option .whoisData').hide();
37622        $('.option .lblTaken').hide();
37623
37624    });
37625
37626	$(document).on('submit', '#update-settings form', function (e) {
37627        e.preventDefault();
37628		var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
37629        var stringRe = /^[A-Za-z\s][A-Za-z0-9\s]*$/;
37630		var emailEl = $('#registerEmail');
37631        var passEl = $('#registerPassword');
37632        var passConfEl = $('#registerPasswordConfirm');
37633        var fullNameEl = $('#registerFullName');
37634        var priPhoneEl = $('#registerPrimaryPhone');
37635        var streetEl = $('#registerAddressStreet');
37636        var cityEl = $('#registerAddressCity');
37637        var countryEl = $('#registerAddressCountry');
37638        var zipEl = $('#registerAddressZip');
37639        var secondaryPhoneEl = $('#registerSecondaryPhone');
37640		var email = emailEl.val();
37641        var pwd = passEl.val();
37642        var pwdConf = passConfEl.val();
37643        var fullName = fullNameEl.val();
37644        var street = streetEl.val();
37645        var city = cityEl.val();
37646        var country = countryEl.val();
37647        var zip = zipEl.val();
37648        var secondaryPhone = secondaryPhoneEl.val();
37649        var errors = '';
37650        var nsvals = [];
37651		var fax1 = $('#fax1').val();
37652        var fax2 = $('#fax2').val(validatePerf($('#fax2').val())).val();
37653        var fax3 = $('#fax3').val();
37654        var phone1 = $('#tel1').val();
37655        var phone2 = $('#tel2').val(validatePerf($('#tel2').val())).val();
37656        var phone3 = $('#tel3').val();
37657        priPhoneEl.val(phone3 + ' ' + phone2 + ' ' + phone1);
37658		$('#registerFaxNumber').val(fax3 + ' ' + fax2 + ' ' + fax1);
37659        var priPhone = priPhoneEl.val();
37660        var ct = true;
37661        $('#update-settings input').each(function () {
37662            if (!ctype_print($(this).val())) {
37663                ct = false;
37664            }
37665            ;
37666        });
37667        if (!ct) {
37668            errors += $.translate('English Only') + '\n';
37669        }
37670		if (!re.test(email) || email === '') {
37671            emailEl.parent().addClass('has-error');
37672            errors += $.translate('Email is invalid') + '\n';
37673            $('#email_f .UIValidators >span').text('Email is invalid');
37674        }
37675        else {
37676            emailEl.parent().removeClass('has-error');
37677        }
37678        if (fullName === '' || fullName.length < 5 || fullName.split(' ').length < 2) {
37679            fullNameEl.parent().addClass('has-error');
37680            errors += $.translate('full name is required') + '\n';
37681            $('#fullname_f .UIValidators >span').text($.translate('full name is required'));
37682
37683        }
37684        else {
37685            fullNameEl.parent().removeClass('has-error');
37686        }
37687        if (priPhone === '' || priPhone.length < 13 || !/[0-9\s]+/.test(priPhone)) {
37688            priPhoneEl.parent().addClass('has-error');
37689            errors += $.translate('Primary phone is required') + '\n';
37690            $('#phone1_f .UIValidators >span').text($.translate('Primary phone is required'));
37691
37692        }
37693        else {
37694            priPhoneEl.parent().removeClass('has-error');
37695        }
37696        if (window.isInvalidOptionalPhone(secondaryPhone)) {
37697            secondaryPhoneEl.parent().addClass('has-error');
37698            errors += $.translate('Secondary phone is invalid') + '\n';
37699        } else {
37700            secondaryPhoneEl.parent().removeClass('has-error');
37701        }
37702        if (street === '' || street.length < 2 || !/[0-9]/.test(street)) {
37703            streetEl.parent().addClass('has-error');
37704            errors += $.translate('Street is required') + '\n';
37705            $('#addres_f .UIValidators >span').text($.translate('Street is required with house num'));
37706
37707        }
37708        else {
37709            streetEl.parent().removeClass('has-error');
37710        }
37711        if (city === '' || city.length < 2 || /[0-9]/.test(city)) {
37712            cityEl.parent().addClass('has-error');
37713            errors += $.translate('City is required') + '\n';
37714            $('#city_f .UIValidators >span').text($.translate('City is required'));
37715
37716        }
37717        else {
37718            cityEl.parent().removeClass('has-error');
37719        }
37720        if (zip === '' || zip.length !== 7) {
37721            zipEl.parent().addClass('has-error');
37722            errors += $.translate('Zip is required') + '\n';
37723            $('#zip_f .UIValidators >span').text($.translate('Zip is required'));
37724        } else if (window.isInvalidZipCode(zip)) {
37725            zipEl.parent().addClass('has-error');
37726            errors += $.translate('Zip is invalid') + '\n';
37727            $('#zip_f .UIValidators >span').text($.translate('Zip is invalid'));
37728        } else {
37729            zipEl.parent().removeClass('has-error');
37730        }
37731        if (country === '') {
37732            countryEl.parent().addClass('has-error');
37733            errors += $.translate('Country is required') + '\n';
37734        }
37735        else {
37736            countryEl.parent().removeClass('has-error');
37737        }
37738
37739		if(pwd !== ''){
37740			if (pwd.length < 8 /*|| !stringRe.test(pwd)*/) {
37741				passEl.parent().addClass('has-error');
37742				if (false/*!stringRe.test(pwd)*/) {
37743					errors += $.translate('password must contain uppercase lowercase and number characters') + '\n';
37744				} else {
37745					errors += $.translate('password is required') + '\n';
37746					$('#pass_f .UIValidators >span').text($.translate('password is required'));
37747				}
37748			} else {
37749				passEl.parent().removeClass('has-error');
37750			}
37751
37752			if (pwd !== pwdConf) {
37753				passConfEl.parent().addClass('has-error');
37754				passEl.parent().addClass('has-error');
37755				errors += $.translate('passwords does not match') + '\n';
37756				$('#pass_f .UIValidators >span').text($.translate('passwords does not match'));
37757
37758			} else {
37759				passConfEl.parent().removeClass('has-error');
37760				passEl.parent().removeClass('has-error');
37761			}
37762		}
37763        if (errors !== '') {
37764            $('#update-settings-errors').html(nl2br(errors, true)).removeClass('hidden');
37765			window.scrollTo(0, 0);
37766            return false;
37767        }
37768        else {
37769            $('#update-settings-errors').addClass('hidden');
37770            $('#registerSubmit').button('loading');
37771            $.post($(this).attr('action'), $(this).serialize(), function (data) {
37772                data = JSON.parse(data);
37773                if (data.status === 0) {
37774                    $('#update-settings-errors').removeClass('hidden').html(nl2br(data.msg, true));
37775					$('#update-settings-success').addClass('hidden');
37776					window.scrollTo(0, 0);
37777                    $('#registerSubmit').button('reset');
37778                }
37779                if (data.status === 1) {
37780                    if (undefined !== data.redirect) {
37781                        window.location.href = data.redirect;
37782                    }
37783
37784                    $('#update-settings-success').removeClass('hidden').html(nl2br(data.msg, true));
37785					$('#update-settings-errors').addClass('hidden');
37786					window.scrollTo(0, 0);
37787					$('#registerSubmit').button('reset');
37788                }
37789            });
37790        }
37791    });
37792
37793// +St:
37794	function setValuesForInput() {
37795	/*var in_array = $("input[name*='\\[name\\]']");
37796	$.each( in_array, function(indx, obj) {
37797		var str = $(obj).val();
37798		str = str.split('.');
37799		if( str.length > 4 ) { // serv.protocol.[prior].site.dom => serv.prot.site.dom
37800		str_out = str[0] + '.' + str[1];
37801		for(var i=3; i< str.length;i++) str_out += '.' + str[i];
37802		$(obj).val( str_out );
37803		}
37804	});*/
37805	}
37806// -St
37807    $(document).on('click', '.manage', function (e) {
37808        e.preventDefault();
37809        var el = $(this);
37810        if (el.is(':disabled') || el.prop('disabled')) {
37811            return;
37812        }
37813        var uid = el.parent().parent().data('uid');
37814        var url = Storage.getData('app_url') + 'domain/manageDomain/' + uid;
37815        $.getJSON(url, null, function (r) {
37816            if (r.status == 0) {
37817                // alert(r.msg);
37818                //$('#main-content').html(r.msg);
37819                $.fancybox.open({
37820                    content: '<div class="error-fanc">' + r.msg + '</div>',
37821                    padding: 0,
37822                    
37823                });
37824            }
37825            if (r.status == 1) {
37826                $.fancybox.open({
37827                    content: r.msg,
37828                    padding: 0,
37829                    type: 'iframe',
37830                    afterShow: function () {
37831
37832                        $('#ns-reset-default').click(function() {
37833
37834                            var rawNs = $('#default-box-ns').text();
37835                            var defaults;
37836                            try {
37837                                defaults = eval('(' + rawNs + ')');
37838                            } catch(e) {
37839                                console.log("Invalid Default NS");
37840                                return;
37841                            }
37842                            $('#manage-ns-records tbody tr').each(function(i) {
37843
37844                                if (defaults[i]) {
37845                                    $(this).find('input[name$="[ns]"]').val(defaults[i]);
37846                                } else {
37847                                    $(this).find('input[name$="[ns]"]').val('');
37848                                }
37849
37850                                $(this).find('input[name$="[ip]"]').val('');
37851                                $(this).find('input[name$="[ipv6]"]').val('');
37852                            });
37853                            $('#ns-reset-default-after-click').removeClass('hide');
37854                        });
37855
37856                        $('#updatens').submit(function (e) {
37857                            e.preventDefault();
37858                            $('#save-ns').button('loading');
37859                            $.post(url, $(this).serialize(), function (r) {
37860                                r = JSON.parse(r);
37861                                if (r.status == 0) {
37862                                    $.fancybox.close();
37863                                    $('#main-content').html(r.msg);
37864                                    updateUrl(r.title, r.page);
37865
37866                                    setValuesForInput();
37867                                }
37868                                if (r.status == 1) {
37869                                    $('#domainflash').html(r.msg).removeClass('hidden');
37870                                    $.fancybox.close();
37871                                }
37872                                if (r.status == 2) {
37873                                    $('#ns-errors').html(r.msg).removeClass('hidden');
37874                                    $('#save-ns').button('reset');
37875                                }
37876                            })
37877                        });
37878
37879                        $('#manage-ns-dnssec-add-button').click(function(e) {
37880                            e.preventDefault();
37881                            $(this).addClass('hidden');
37882                            $('#manage-ns-dnssec-create-section').removeClass('hidden');
37883                            $('#manage-ns-dnssec-save-button').removeClass('hidden');
37884                            $('#manage-ns-dnssec-cancel-button').removeClass('hidden');
37885                        });
37886
37887                        $('#manage-ns-dnssec-cancel-button').click(function(e) {
37888                            e.preventDefault();
37889                            $(this).addClass('hidden');
37890                            $('#manage-ns-dnssec-create-section').addClass('hidden');
37891                            $('#manage-ns-dnssec-save-button').addClass('hidden');
37892                            $('#manage-ns-dnssec-add-button').removeClass('hidden');
37893                        });
37894
37895                        $('#dnssec-create').submit(function (e) {
37896                            e.preventDefault();
37897                            $('#manage-ns-dnssec-save-button').button('loading');
37898                            $('#manage-ns-dnssec-cancel-button').prop('disabled', 'disabled');
37899
37900                            $.post($(this).attr('action'), $(this).serialize())
37901                              .done(function (response) {
37902                                  $('#manage-ns-dnssec-save-button').button('reset');
37903                                  $('#manage-ns-dnssec-cancel-button').prop('disabled', false);
37904                                  $('#manage-ns-dnssec-errors').html('').addClass('hidden');
37905                                  $('#dnssec-create').resetForm();
37906
37907                                  let emptyRow = $('#manage-ns-dnssec-records .manage-ns-dnssec-record-empty');
37908
37909                                  if (0 !== emptyRow.length) {
37910                                      emptyRow.remove();
37911                                  }
37912
37913                                  $('#manage-ns-dnssec-cancel-button').click();
37914
37915                                  if (0 === $('#manage-ns-dnssec-records > tbody > tr').length) {
37916                                      $('#manage-ns-dnssec-records > tbody').append(response.tableRow);
37917                                  } else {
37918                                      $(response.tableRow).insertBefore('#manage-ns-dnssec-records > tbody > tr:first');
37919                                  }
37920                              })
37921                              .fail(function(response) {
37922                                  if (403 === response.status) {
37923                                      window.location.href = '/user/login';
37924                                  }
37925
37926                                  $('#manage-ns-dnssec-errors').html(response.responseJSON.error).removeClass('hidden');
37927                                  $('#manage-ns-dnssec-save-button').button('reset');
37928                                  $('#manage-ns-dnssec-cancel-button').prop('disabled', false)
37929                              })
37930                        });
37931
37932                        $('#manage-ns-dnssec-records').on('click', '.manage-ns-dnssec-record-delete', function(e) {
37933                            e.preventDefault();
37934
37935                            let link = $(this);
37936
37937                            $.ajax({
37938                                url: link.attr('href'),
37939                                type: 'DELETE',
37940                                success: function(response) {
37941                                    link.parent().parent().remove();
37942                                    $('#manage-ns-dnssec-base-errors').html('').addClass('hidden');
37943
37944                                    if (0 === response.totalRows) {
37945                                        $('#manage-ns-dnssec-records > tbody').append(response.emptyRow);
37946                                    }
37947                                },
37948                                error: function(xhr) {
37949                                    if (403 === xhr.status) {
37950                                        window.location.href = '/user/login';
37951                                    }
37952
37953                                    $('#manage-ns-dnssec-base-errors').html(xhr.responseJSON.error).removeClass('hidden');
37954                                }
37955                            });
37956                        });
37957
37958                    }
37959                });
37960            }
37961			setValuesForInput();
37962        });
37963    });
37964
37965    $(document).on('click', '.enom-raa-resend', function (e) {
37966        e.preventDefault();
37967        var el = $(this);
37968        if (el.is(':disabled') || el.data('busy')) {
37969            return;
37970        }
37971
37972        var uid = el.data('uid') || el.closest('tr').data('uid');
37973        if (!uid) {
37974            return;
37975        }
37976
37977        var url = el.data('url') || (Storage.getData('app_url') + 'domain/enom-raa-resend/' + uid);
37978
37979        el.data('busy', true).prop('disabled', true);
37980
37981        $.ajax({
37982            url: url,
37983            type: 'POST',
37984            dataType: 'json'
37985        }).done(function (r) {
37986            var msg = (r && r.msg) ? r.msg : '';
37987            if (r && r.status == 1) {
37988                $.showSuccess(r.title || $.translate('Success'), msg, false, true);
37989            } else {
37990                $.showError(msg || $.translate('Failed to resend verification email. Please contact support.'));
37991            }
37992        }).fail(function () {
37993            $.showError($.translate('Failed to resend verification email. Please contact support.'));
37994        }).always(function () {
37995            el.data('busy', false).prop('disabled', false);
37996        });
37997    });
37998
37999    $(document).on('click', '#transfer', function (e) {
38000        e.preventDefault();
38001        $.get(Storage.getData('app_url') + 'domain/transferDomain', function (r) {
38002            $.fancybox.open({
38003                content: r,
38004                type: 'iframe',
38005                padding: 0,
38006                afterShow: function () {
38007                    $('.show-tooltip').addTooltip();
38008
38009                    $('.panel-default a').click(function () {
38010                        $('.collapse').collapse('toggle');
38011                    })
38012                    var btn = $('#transfer-domain');
38013                    $('#transfer-domain').click(function (e) {
38014                        var sld = $('#domain-sld').val();
38015                        var tld = $('#domain-tld').val();
38016                        var admin = $('#ownerTransfer').val();
38017                        var tech = $('#techTransfer').val();
38018                        var zone = $('#adminTransfer').val();
38019                        var form = $(this).closest('form');
38020
38021                        btn.button('loading');
38022                        e.preventDefault();
38023
38024                        var csrfConfig = Storage.getData('csrf_config');
38025                        var data = {
38026                            sld: sld,
38027                            tld: tld,
38028                            admin: admin,
38029                            adminIsoc: $('option[value="' + admin + '"]').data('isoc-id'),
38030                            tech: tech,
38031                            techIsoc: $('option[value="' + tech + '"]').data('isoc-id'),
38032                            zone: zone,
38033                            zoneIsoc: $('option[value="' + zone + '"]').data('isoc-id'),
38034                            eppCode: $('#domain-transfer-isoc-epp').val()
38035                        };
38036
38037
38038                        data[csrfConfig['token_name_key']] = form.find('[name=csrf_token_name]').val();
38039                        data[csrfConfig['token_key']]      = form.find('[name=csrf_token]').val();
38040
38041                        $.post(Storage.getData('app_url') + 'domain/transferDomain', data, function (r) {
38042                            r = JSON.parse(r);
38043                            if (r.status == 0) {
38044                                $('#transfer-modal-error').html(r.msg).removeClass('hidden');
38045                                $('button').button('reset');
38046                            }
38047                            if (r.status == 1) {
38048                                $.fancybox.close();
38049                                $('#mDomains').click();
38050                                $('#domainflash').html(r.msg).removeClass('hidden');
38051                            }
38052                        });
38053                    });
38054                    var transferSubmitting = false;
38055                    $('#transfer-enom-domain').click(function (e) {
38056                        e.preventDefault();
38057                        if (transferSubmitting) return;
38058                        $('#transfer-modal-error').addClass('hidden');
38059                        $('#transfer-enom-domain').button('loading');
38060                        var creditReg = /^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|6(?:011|5[0-9]{2})[0-9]{12}|(?:2131|1800|35\d{3})\d{11})$/;
38061                        var creditCardEl = $('#creditNumber');
38062                        var creditYrEl = $('#creditExpirationYear');
38063                        var creditMoEl = $('#creditExpirationMonth');
38064                        var creditCardCvvEl = $('#creditCvv');
38065                        var creditIdEl = $('#creditId');
38066                        var date = new Date();
38067                        var creditCard = creditCardEl.val();
38068                        var creditCardYr = creditYrEl.val();
38069                        var creditCardMo = creditMoEl.val();
38070                        var creditCardCvv = creditCardCvvEl.val();
38071                        var creditCardId = creditIdEl.val();
38072                        var approve_termsEl = $('#approve_terms');
38073                        var approve_terms = approve_termsEl.is(":checked");
38074                        var errors = '';
38075                        if ($('[name="enomDomainTransfer"]').val() == '' || $('[name="enomDomainTransfer"]').val().split('.').length < 2) {
38076                            errors += $.translate('You must enter domain name') + '\n';
38077                        }
38078                        if ($('[name="domainEPPTransfer"]').val() == '' || !enom_ctype_print($('[name="domainEPPTransfer"]').val())) {
38079                            errors += $.translate('You must enter valid EPP code') + '\n';
38080                        }
38081                        var enomOwnerTransferEl = $('#enomOwnerTransfer');
38082                        if (!enomOwnerTransferEl.val() || enomOwnerTransferEl.val() == '') {
38083                            enomOwnerTransferEl.parent().addClass('has-error');
38084                            errors += $.translate('You must select a contact') + '\n';
38085                        } else {
38086                            enomOwnerTransferEl.parent().removeClass('has-error');
38087                        }
38088                        if (!approve_terms) {
38089                            approve_termsEl.parent().addClass('has-error');
38090                            errors += $.translate('Approve Terms is required') + '\n';
38091                        }
38092                        else {
38093                            approve_termsEl.parent().removeClass('has-error');
38094                        }
38095                        if (isNaN(creditCardYr) || parseInt(creditCardYr) < date.getFullYear()) {
38096                            creditYrEl.parent().addClass('has-error');
38097                            errors += $.translate('Expiry Year is invali
38097d');
38098                        }
38099                        else {
38100                            creditYrEl.parent().removeClass('has-error');
38101                        }
38102                        if (isNaN(creditCardMo) || creditCardYr == date.getFullYear() && creditCardMo < date.getMonth()) {
38103                            creditMoEl.parent().addClass('has-error');
38104                            errors += $.translate('Expiry Month is invalid') + '\n';
38105                        }
38106                        else {
38107                            creditMoEl.parent().removeClass('has-error');
38108                        }
38109                        if (isNaN(creditCardCvv) || creditCardCvv.length < 3 || creditCardCvv.length > 4) {
38110                            creditCardCvvEl.parent().addClass('has-error');
38111                            errors += $.translate('cvv is invalid') + '\n';
38112                        }
38113                        else {
38114                            creditCardCvvEl.parent().removeClass('has-error');
38115                        }
38116                        if (isNaN(creditCardId) || creditCardId.length < 9 || creditCardId.length > 9) {
38117                            creditIdEl.parent().addClass('has-error');
38118                            errors += $.translate('id is invalid') + '\n';
38119                        }
38120                        else {
38121                            creditIdEl.parent().removeClass('has-error');
38122                        }
38123                        if (isNaN(creditCard) || creditCard.length < 9 || creditCard.length > 17 || !creditReg.test(creditCard) && creditCard.length > 9 || creditCard[0] === 0) {
38124                            creditCardEl.parent().addClass('has-error');
38125                            errors += $.translate('card is invalid') + '\n';
38126                        }
38127                        else {
38128                            creditCardEl.parent().removeClass('has-error');
38129                        }
38130                        if (errors != '') {
38131                            $('#transfer-modal-error').html(nl2br(errors)).removeClass('hidden');
38132                            $('#transfer-enom-domain').button('reset');
38133                        } else {
38134                            transferSubmitting = true;
38135                            $.post(Storage.getData('app_url') + 'domain/transferEnom', $('#transferForm').serialize(), function (r) {
38136                                r = JSON.parse(r);
38137                                if (r.status == 0) {
38138                                    transferSubmitting = false;
38139                                    $('#transfer-modal-error').html(nl2br(r.msg)).removeClass('hidden');
38140                                    $('#transfer-enom-domain').button('reset');
38141                                }
38142                                if (r.status == 1) {
38143                                    $('#domainflash').html(nl2br(r.msg)).removeClass('hidden');
38144                                    $('#transfer-enom-domain').button('reset');
38145                                    $.fancybox.close();
38146                                }
38147                            }).fail(function () {
38148                                transferSubmitting = false;
38149                                $('#transfer-enom-domain').button('reset');
38150                            });
38151                        }
38152                    })
38153                }
38154            });
38155        });
38156    });
38157    $(document).on('click', '#isLockCheck', function (e) {
38158        e.preventDefault();
38159        var domain = '';
38160
38161        if ($('#collapseEnom').hasClass('in')) {
38162            domain = $('#enomDomainTransfer').val();
38163        }
38164
38165        if ($('#israeliTranCollapse').hasClass('in') && '' !== $('#domain-sld').val()) {
38166            domain = $('#domain-sld').val() + '.' + $('#domain-tld').val();
38167        }
38168
38169        if ('' === domain) {
38170            return;
38171        }
38172
38173        var url = $(this).attr('href');
38174
38175        $('#isLockRes').html('').addClass('hidden');
38176        if (domain == '') {
38177            $('#transfer-modal-error').html($.translate('please fill domain')).removeClass('hidden');
38178            //alert(appLocale['please fill domain']);
38179            return false;
38180        }
38181        $('#transfer-modal-error').addClass('hidden');
38182        $.getJSON(url + domain, function (r) {
38183            if (r.status == 0) {
38184                //alert(r.msg);
38185                $('#transfer-modal-error').html(r.msg).removeClass('hidden');
38186            }
38187            if (r.status == 1) {
38188                $('#isLockRes').html(r.msg).removeClass('hidden');
38189            }
38190        });
38191    });
38192   
38193    /**
38194    $(document).on('click', '.lock', function (e) {
38195        e.preventDefault();
38196        var el = $(this);
38197        var uid = el.parent().parent().data('uid');
38198        var url = Storage.getData('app_url') + 'domain/lockDomain/' + uid;
38199        $.getJSON(url, null, function (r) {
38200            if (r.status == 0) {
38201                $('#main-content').html(r.msg);
38202            }
38203            if (r.status == 1) {
38204                $.fancybox.open({
38205                    content: r.msg,
38206                    padding: 0,
38207                    type: 'iframe',
38208                    afterShow: function () {
38209                        var btn = $('#save-lock');
38210                        $('#updatelock').submit(function (e) {
38211                            e.preventDefault();
38212                            btn.button('loading');
38213
38214                            var data = {
38215                                lockstate: $('input[name="lockstate"]:checked').val()
38216                            };
38217
38218                            var csrfConfig = Storage.getData('csrf_config');
38219
38220                            data[csrfConfig['token_name_key']] = $(this).find('[name=csrf_token_name]').val();
38221                            data[csrfConfig['token_key']]      = $(this).find('[name=csrf_token]').val();
38222
38223                            $.post(url, data, function (r) {
38224                                r = JSON.parse(r);
38225                                if (r.status == 0) {
38226                                    $('#main-content').html(r.msg);
38227                                    $.fancybox.close();
38228                                }
38229                                if (r.status == 1) {
38230                                    alert(r.msg);
38231                                    $.fancybox.close();
38232                                }
38233                            });
38234                        });
38235                    }
38236                });
38237            }
38238        });
38239    });
38240    */
38241    
38242
38243
38244    $(document).on('click', '.renew', function (e) {
38245        e.preventDefault();
38246        var el = $(this);
38247        var uid = el.parent().parent().data('uid');
38248        var url = Storage.getData('app_url') + 'domain/renewDomain/' + uid;
38249        $.getJSON(url, null, function (r) {
38250            if (r.status == 0) {
38251                $('#main-content').html(r.msg);
38252            }
38253            if (r.status == 1) {
38254                $.fancybox.open({
38255                    content: r.msg,
38256                    padding: 0,
38257                    type: 'iframe',
38258                    afterShow: function () {
38259                        $('.show-tooltip').addTooltip();
38260                    },
38261                    beforeClose: function () {
38262                        $('#domain-renew-confirm-pending').modal('hide');
38263                    }
38264                });
38265            }
38266        });
38267    });
38268
38269    $('#main-content.page-domain-renew #renew-domain .cvvhelp').hover(function () {
38270        $(this).find('img').show();
38271    }, function () {
38272        $(this).find('img').hide();
38273    });
38274
38275    var renewSubmitting = false;
38276    $(document).on('click', '#renew-domain #renew', function(e) {
38277        if (renewSubmitting) return;
38278        $(this).button('loading');
38279    });
38280
38281    $(document).on('click', '#domain-renew-confirm-confirm', function() {
38282        $('#domain-renew-confirm-pending').modal('hide');
38283        $('#domain-renew-pending-confirmed').val(1);
38284        $('#renew').trigger('click');
38285    });
38286
38287    $(document).on('click', '#domain-renew-confirm-cancel', function() {
38288        $('#domain-renew-confirm-pending').modal('hide');
38289    });
38290
38291    $(document).on('submit', '#renew-domain', function (e) {
38292        var btn = $('#renew');
38293        e.preventDefault();
38294
38295        // d0ger easy
38296        var creditReg = /^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|6(?:011|5[0-9]{2})[0-9]{12}|(?:2131|1800|35\d{3})\d{11})$/;
38297        var creditCardEl = $('#creditNumber');
38298        var creditYrEl = $('#creditExpirationYear');
38299        var creditMoEl = $('#creditExpirationMonth');
38300        var creditCardCvvEl = $('#creditCvv');
38301        var creditIdEl = $('#creditId');
38302        var domainPeriodEl = $('#domainPeriod');
38303        var date = new Date();
38304        var creditCard = creditCardEl.val();
38305        var creditCardYr = creditYrEl.val();
38306        var creditCardMo = creditMoEl.val();
38307        var creditCardCvv = creditCardCvvEl.val();
38308        var creditCardId = creditIdEl.val();
38309        var domainPeriod = parseInt($('[name=domainPeriod]:checked').val());
38310        var approve_termsEl = $('#approve_terms');
38311        var approve_terms = approve_termsEl.is(":checked");
38312        var errors = '';
38313        if(approve_terms != undefined) {
38314            if (!approve_terms) {
38315                approve_termsEl.parent().addClass('has-error');
38316                errors += $.translate('Approve Terms is required') + '\n';
38317                //$('#zip_f .UIValidators >span').text(appLocale['Approve Terms is required']);
38318            }
38319            else {
38320                approve_termsEl.parent().removeClass('has-error');
38321            }
38322        }
38323
38324        if (isNaN(creditCardYr) || parseInt(creditCardYr) < date.getFullYear()) {
38325            creditYrEl.parent().addClass('has-error');
38326            errors += $.translate('Expiry Year is invalid');
38327        }
38328        else {
38329            creditYrEl.parent().removeClass('has-error');
38330        }
38331        if (isNaN(creditCardMo) || creditCardYr == date.getFullYear() && creditCardMo < date.getMonth()) {
38332            creditMoEl.parent().addClass('has-error');
38333            errors += $.translate('Expiry Month is invalid') + '\n';
38334        }
38335        else {
38336            creditMoEl.parent().removeClass('has-error');
38337        }
38338        if (isNaN(creditCardCvv) || creditCardCvv.length < 3 || creditCardCvv.length > 4) {
38339            creditCardCvvEl.parent().addClass('has-error');
38340            errors += $.translate('cvv is invalid') + '\n';
38341        }
38342        else {
38343            creditCardCvvEl.parent().removeClass('has-error');
38344        }
38345        if (isNaN(creditCardId) || creditCardId.length < 9 || creditCardId.length > 9) {
38346            creditIdEl.parent().addClass('has-error');
38347            errors += $.translate('id is invalid') + '\n';
38348        }
38349        else {
38350            creditIdEl.parent().removeClass('has-error');
38351        }
38352        if (isNaN(creditCard) || creditCard.length < 9 || creditCard.length > 17 || !creditReg.test(creditCard) && creditCard.length > 9 || creditCard[0] === 0) {
38353            creditCardEl.parent().addClass('has-error');
38354            errors += $.translate('card is invalid') + '\n';
38355        }
38356        else {
38357            creditCardEl.parent().removeClass('has-error');
38358        }
38359        if (domainPeriod < 1 && domainPeriod > 5) {
38360            domainPeriodEl.parent().addClass('has-error');
38361            errors += $.translate('Domain Period is invalid') + '\n';
38362        }
38363        else {
38364            domainPeriodEl.parent().removeClass('has-error');
38365        }
38366        if (errors !== '') {
38367            $('#renew-errors').html(nl2br(errors, true)).removeClass('hidden');
38368            btn.button('reset');
38369            return false;
38370        } else {
38371            $('#renew-errors').addClass('hidden');
38372        }
38373        renewSubmitting = true;
38374        var uid = $('#renew-domain').data('uid');
38375        var url = Storage.getData('app_url') + 'domain/renewDomain/' + uid;
38376        var postData = $(this).serialize();
38377
38378        postData['destination'] = '/user/account';
38379
38380        $.ajax({
38381            url:   url,
38382            data:  postData,
38383            type: 'post',
38384            error: function(XMLHttpRequest, textStatus, errorThrown){
38385                renewSubmitting = false;
38386                btn.button('reset');
38387                window.location.href = '/user/login';
38388            },
38389            success: function (r) {
38390                if (r.status == 0) {
38391                    if(undefined != r.premiumPrice) {
38392                        // show warning
38393                        $('#renew-domain-is-premium').removeClass('hidden').html(r.msg);
38394
38395                        // update form
38396                        $('#domain-purchase-is-premium').val(1);
38397
38398                        // update price
38399                        var priceEl = $('#renew-domain').find('span.UIInfoTitle');
38400
38401                        for (var year in r.premiumPrice) {
38402                            priceEl.attr('data-price-{0}'.format(year), r.premiumPrice[year]);
38403                        }
38404
38405                        var period = parseInt($('#renew-domain input[name=domainPeriod]:checked').val());
38406                        var price  = 0;
38407
38408                        // update total price
38409                        for (var i = 1; i < period + 1; i++) {
38410                            var yearPrice = priceEl.attr('data-price-{0}'.format(i));
38411
38412                            if (undefined !== yearPrice) {
38413                                price += parseFloat(yearPrice);
38414                            }
38415                        }
38416
38417                        priceEl.find('span').html(Number(price).toFixed(2));
38418
38419                        var checked = $('#renew-domain input[name=domainPeriod]:checked');
38420                        $('#renew-domain input[name=domainPeriod]:first').trigger('click');
38421
38422                        if (checked.length > 0) {
38423                            checked.trigger('click');
38424                        }
38425
38426                        $('#couponCode').val('');
38427                        $('#cpnDis').addClass('hidden');
38428                    } else if (
38429                      undefined !== r.format
38430                      && undefined !== r.type
38431                      && 'popin' === r.format
38432                      && 'pendingRenew'  === r.type
38433                    ) {
38434                        if (0 !== $('#domain-renew-confirm-pending').length) {
38435                            $('#domain-renew-confirm-pending').modal('show');
38436                        } else {
38437                            $(r.msg).modal('show');
38438                        }
38439                    } else {
38440                        if(typeof undefined === typeof r.destination) {
38441                            $('#renew-errors').html(nl2br(r.msg, true)).removeClass('hidden');
38442                        } else {
38443                            window.location.href = r.destination;
38444                        }
38445                    }
38446
38447                    renewSubmitting = false;
38448                    $('#renew').button('reset');
38449                }
38450
38451                if (r.status == 1) {
38452                    $('#domainflash').html(nl2br(r.msg, true)).removeClass('hidden');
38453                    $.fancybox.close();
38454
38455                    $.fancybox.open({
38456                        content: r.msg,
38457                        padding: 0,
38458                        type: 'iframe',
38459                        afterShow: function () {
38460                            var btn = $('#good_renew');
38461                            btn.click(function(){
38462                                $.fancybox.close();
38463
38464                                if(typeof undefined === typeof r.destination) {
38465                                    window.location.href = window.location.href;
38466                                } else {
38467                                    window.location.href = r.destination;
38468                                }
38469
38470                            });
38471                        },
38472                        afterClose: function () {
38473                            if(typeof undefined === typeof r.destination) {
38474                                window.location.href = window.location.href;
38475                            } else {
38476                                window.location.href = r.destination;
38477                            }
38478                        }
38479                    });
38480                }
38481            }
38482        });
38483    });
38484
38485    /*main menu*/
38486    $('.menu>ul>li').mouseenter(function () {
38487      $('.menu>ul>li').find('.sub-menu').stop().fadeOut();
38488
38489      var el = $(this);
38490
38491      el.addClass('active').find('.sub-menu').fadeIn();
38492
38493      // setTimeout(function() {
38494      //
38495      // }, 300);
38496    });
38497
38498    $('.menu>ul>li').mouseleave(function () {
38499      var el = $(this);
38500      $('.menu>ul>li').find('.sub-menu').stop().hide();
38501
38502      el.removeClass('active').find('.sub-menu').fadeOut();
38503    });
38504
38505    // Mobile Menu Click*
38506    $(document).on('click','#mobileMenu > li > a',function(){
38507        $('.sub-menu').fadeOut();
38508        if($(this).parent().hasClass('active')){
38509            $(this).parent().removeClass('active');
38510        }else{
38511            $(this).parent().addClass('active');
38512            $(this).parent().find('.sub-menu').fadeIn();
38513        }
38514
38515    })
38516
38517
38518    $(".fancybox-video").click(function () {
38519        $.fancybox({
38520            'padding': 0,
38521            'autoScale': false,
38522            'transitionIn': 'none',
38523            'transitionOut': 'none',
38524            'title': this.title,
38525            'width': 640,
38526            'height': 385,
38527            'href': this.href.replace(new RegExp("watch\\?v=", "i"), 'v/'),
38528            'type': 'swf',
38529            'swf': {
38530                'wmode': 'transparent',
38531                'allowfullscreen': 'true'
38532            }
38533        });
38534
38535        return false;
38536    });
38537
38538    $(document).on('change', '#renew-domain input[name=domainPeriod]', function () {
38539        var title       = $('#renew-domain').find('span.UIInfoTitle'),
38540            // price       = parseFloat(title.data('price')),
38541            // secondPrice = parseFloat(title.data('second-price')),
38542            price       = 0,
38543            period      = parseInt($(this).val()),
38544            creDetails  = $('#creditDetails');
38545
38546
38547        $('#creditExpirationYear').find('option').eq(0).prop('selected', true);
38548        $('#creditExpirationMonth').find('option').eq(0).prop('selected', true);
38549        $('#creditCvv').val('');
38550        $('#creditId').val('');
38551        $('#creditNumber').val('');
38552        $('#cpn-error').addClass('hidden');
38553        $('#cpnDis').addClass('hidden');
38554        creDetails.find('input[type=text]').parent().show();
38555        creDetails.find('select').parent().show();
38556        $('#checkCoupon').prop('disabled', false);
38557
38558        // update total price
38559        for (var i = 1; i < period + 1; i++) {
38560            var yearPrice = title.attr('data-price-{0}'.format(i));
38561
38562            if (undefined !== yearPrice) {
38563                price += parseFloat(yearPrice);
38564            }
38565        }
38566
38567        title.find('span').html(Number(price).toFixed(2));
38568    });
38569
38570    $(document).on('keyup', '#enomDomainTransfer', function () {
38571        $('#enomPricing').hide()
38572    });
38573
38574    $(document).on('click', '#enomCalculatePrice', function (e) {
38575        e.preventDefault();
38576        $('#transfer-modal-error').addClass('hidden');
38577        $('#enomPricing').hide();
38578        $('#enomCalculatePrice').button('loading');
38579
38580        var csrfConfig = Storage.getData('csrf_config');
38581        var form       = $(this).closest('form');
38582        var data       = {
38583            enomDomainTransfer: $('#enomDomainTransfer').val()
38584        };
38585
38586
38587        data[csrfConfig['token_name_key']] = form.find('[name=csrf_token_name]').val();
38588        data[csrfConfig['token_key']]      = form.find('[name=csrf_token]').val();
38589
38590        $.post(Storage.getData('app_url') + 'domain/enomcheck', data, function (r) {
38591            r = JSON.parse(r);
38592            if (r.status == 0) {
38593                $('#transfer-modal-error').html(nl2br(r.msg, true)).removeClass('hidden');
38594                $('#enomCalculatePrice').button('reset');
38595            }
38596            if (r.status == 1) {
38597                $('#domainBasePricing .amount').html(r.msg);
38598                $('#enomPricing').show();
38599                $('#enomCalculatePrice').button('reset');
38600                $('.show-tooltip').addTooltip();
38601            }
38602        })
38603    });
38604
38605    $(document).on('click', '#enomPricing #checkCoupon', function (e) {
38606        e.preventDefault();
38607        var cpn = $('#couponCode').val();
38608        $('#cpn-error').addClass('hidden');
38609        //$('#cpnDis').addClass('hidden');
38610        $(this).button('loading');
38611        $('#creditDetails input[type=text]').parent().show();
38612        $('#creditDetails select').parent().show();
38613        $('#creditNumber').val('').trigger('change').trigger('keyup.jccv');
38614        $('#creditExpirationYear option').eq(0).prop('selected', true);
38615        $('#creditExpirationMonth option').eq(0).prop('selected', true);
38616        $('#creditCvv').val('');
38617        $('#creditId').val('');
38618        $.get(Storage.getData('app_url') + 'checkCpn/' + cpn, '', function (r) {
38619            r = parseFloat(r);
38620            if (r <= 0) {
38621                $('#cpn-error').removeClass('hidden');
38622                $('#cpnDis').addClass('hidden');
38623            } else {
38624                $('#cpn-error').addClass('hidden');
38625                var price = $('#domainBasePricing span').html();
38626                var dis = price - r;
38627                if (dis <= 0) {
38628                    dis = 0;
38629                    $('#creditDetails input[type=text]').parent().hide();
38630                    $('#creditDetails select').parent().hide();
38631                    $('#creditNumber').val('378282246310005');
38632                    $('#creditExpirationYear').val(new Date().getFullYear() + 5);
38633                    $('#creditExpirationMonth').val(12);
38634                    $('#creditCvv').val(123);
38635                    $('#creditId').val(123456789);
38636                }
38637                $('.amount').html(price);
38638                $('.sum').html(Number(dis).toFixed(2))
38639                $('#cpnDis').removeClass('hidden');
38640            }
38641            $('#checkCoupon').button('reset');
38642        });
38643        $('#checkCoupon').button('reset');
38644    });
38645    $(document).on('click', '#search', function (e) {
38646        e.preventDefault();
38647        var q = $.getQueryParameters();
38648        var sq = $('#sq').val();
38649        var baseUrl = document.location.href.replace(window.location.search, '?');
38650        q.q = sq;
38651        if (sq == '') {
38652            delete q.q;
38653        }
38654        document.location.replace(baseUrl + $.param(q));
38655    });
38656
38657    // this code was inlined in main.php file
38658    // cc card validation callback
38659    if($('#creditNumber.validate').length) {
38660        $('#creditNumber.validate').validateCreditCard(function (result) {
38661            var input = $(this);
38662            var type  = null == result.card_type ? 'type-none' : 'type-' + result.card_type.name;
38663            var cvv   = input.closest('form').find('#creditCvv.validate');
38664
38665            // set classes
38666            input.removeClassPrefix('type-');
38667            input.addClass(type);
38668            result.valid ? input.addClass('valid') : input.removeClass('valid');
38669
38670            // set cvv length
38671            if(cvv.length > 0) {
38672                var maxLen = null != result.card_type && 'amex' == result.card_type.name ? 4 : 3;
38673                cvv.attr('maxlength', maxLen);
38674            }
38675        });
38676    }
38677
38678    $(document).on('click', '#admin-domain-sent-owner-verify-email', function (e) {
38679        e.preventDefault();
38680
38681        var el = $(this);
38682
38683        $.ajax({
38684            url: el.attr('href'),
38685            type: 'POST',
38686            data: {
38687                'email': $('#ownerEmail').val()
38688            },
38689            success: function (response) {
38690                if (0 == response.status) {
38691                    $('#admin-domain-sent-owner-verify-email-errors').html(nl2br(response.msg, true)).removeClass('hidden');
38692                }
38693
38694                if (1 == response.status) {
38695
38696                    console.log('OPA');
38697                    console.log('OPA');
38698                    console.log(el.attr('data-destination'));
38699                    console.log(el.data('destination'));
38700
38701                    window.location.href = el.attr('data-destination');
38702                }
38703            },
38704            error: function (xhr) {
38705                if (403 === xhr.status) {
38706                    window.location.href = '/user/login';
38707                }
38708
38709                $('#admin-domain-sent-owner-verify-email-errors').html(xhr.responseJSON.error).removeClass('hidden');
38710            }
38711        });
38712    });
38713
38714    const $dropdown_support = $("#supportMenu-dropDown");
38715	const $icon_support = $('#supportMenu i');
38716	$('#supportMenu').on('click', function () {
38717		if ($dropdown_support.is(':visible')) {
38718			$dropdown_support.slideUp(150);
38719			$icon_support.removeClass('fa-chevron-up').addClass('fa-chevron-down');
38720		}else{
38721			$dropdown_support.slideDown(150);
38722			$icon_support.removeClass('fa-chevron-down').addClass('fa-chevron-up');
38723		}
38724		$("#manageMenu-dropDown").slideUp(150);
38725		$('#manageMenu i').removeClass('fa-chevron-up').addClass('fa-chevron-down');
38726
38727	});
38728	
38729	const $dropdown_manage = $("#manageMenu-dropDown");
38730	const $icon_manage = $('#manageMenu i');
38731	$('#manageMenu').on('click', function () {
38732		if ($dropdown_manage.is(':visible')) {
38733			$dropdown_manage.slideUp(150);
38734			$icon_manage.removeClass('fa-chevron-up').addClass('fa-chevron-down');
38735		}else{
38736			$dropdown_manage.slideDown(150);
38737			$icon_manage.removeClass('fa-chevron-down').addClass('fa-chevron-up');
38738		}
38739		$("#supportMenu-dropDown").slideUp(150);
38740		$('#supportMenu i').removeClass('fa-chevron-up').addClass('fa-chevron-down');
38741	});
38742
38743    $(document).on('click', function (e) {
38744        // אם הלחיצה לא הייתה בתוך #supportMenu או #supportMenu-dropDown
38745        if (!$(e.target).closest('#supportMenu, #supportMenu-dropDown').length) {
38746            $("#supportMenu-dropDown").slideUp(150);
38747            $('#supportMenu i').removeClass('fa-chevron-up').addClass('fa-chevron-down');
38748        }
38749
38750        // אם הלחיצה לא הייתה בתוך #manageMenu או #manageMenu-dropDown
38751        if (!$(e.target).closest('#manageMenu, #manageMenu-dropDown').length) {
38752            $("#manageMenu-dropDown").slideUp(150);
38753            $('#manageMenu i').removeClass('fa-chevron-up').addClass('fa-chevron-down');
38754        }
38755    });
38756
38757    // tooltips
38758    $('.show-tooltip').addTooltip();
38759
38760    function isValidIPv4(ip) {
38761        return /^((25[0-5]|2[0-4][0-9]|1\d{2}|[1-9]?\d)\.){3}(25[0-5]|2[0-4][0-9]|1\d{2}|[1-9]?\d)$/.test(ip);
38762    }
38763    function isValidIPv6(ip) {
38764        return /^(([0-9a-fA-F]{1,4}):){7}([0-9a-fA-F]{1,4})$/.test(ip);
38765    }
38766    function isValidSubdomain(sub, allowUnderscore = false) {
38767        if (!sub) return true; // ריק זה תקף אם אופציונלי
38768        if (sub === '' || sub === '*' || sub === '@') return true; // allow just * or just @
38769        const labels = sub.split('.');
38770
38771        return labels.every(label => {
38772            if (!label || label.length > 63) return false;
38773            if (label.startsWith('-') || label.endsWith('-')) return false;
38774
38775            const pattern = allowUnderscore
38776                ? /^[\p{L}\p{N}_-]+$/u   // מתיר גם _
38777                : /^[\p{L}\p{N}-]+$/u;   // לא מתיר _
38778
38779            return pattern.test(label);
38780        });
38781    }
38782
38783
38784    function isValidFullDomain(domain, allowUnderscore = false) {
38785        if (!domain) return false;
38786
38787        domain = domain.trim();
38788        domain = domain.replace(/\.$/, '');
38789
38790        const labels = domain.split('.');
38791
38792        // דרישה לשם דומיין מלא (לפחות 2 תוויות: סאב+TLD)
38793        if (labels.length < 2) return false;
38794
38795        // אפשר גם לבדוק שאורך כולל < 255 תווים אם רוצים
38796
38797        return labels.every(label => {
38798            if (!label || label.length > 63) return false;
38799            if (label.startsWith('-') || label.endsWith('-')) return false;
38800
38801            const pattern = allowUnderscore
38802                ? /^[\p{L}\p{N}_-]+$/u
38803                : /^[\p{L}\p{N}-]+$/u;
38804
38805            return pattern.test(label);
38806        });
38807    }
38808
38809    function isValidURL(url) {
38810        try {
38811            const parsed = new URL(url);
38812
38813            // בדיקה שהפרוטוקול חוקי (http/https בלבד לדוגמה)
38814            if (!['http:', 'https:'].includes(parsed.protocol)) {
38815                return false;
38816            }
38817
38818            // ודא שה־hostname כולל לפחות דומיין אחד (ולא רק "http://")
38819            if (!parsed.hostname || parsed.hostname.length < 1) {
38820                return false;
38821            }
38822
38823            return true;
38824        } catch (e) {
38825            return false;
38826        }
38827    }
38828
38829    function sanitizeSearchValue(value) {
38830        if (!value) {
38831            return '';
38832        }
38833
38834        return String(value)
38835            .replace(/[\u200E\u200F\u202A-\u202E\u2066-\u2069\u200B-\u200D\uFEFF\u00AD]/g, '')
38836            .replace(/[\u0000-\u001F\u007F]/g, '')
38837            .replace(/\u00A0/g, ' ')
38838            .trim();
38839    }
38840
38841    function cleanQueryParamInUrl(paramName, input) {
38842        if (!window.URL || !window.URLSearchParams) {
38843            return;
38844        }
38845
38846        var currentUrl = new URL(window.location.href);
38847        var currentValue = currentUrl.searchParams.get(paramName);
38848
38849        if (currentValue === null) {
38850            return;
38851        }
38852
38853        var cleanValue = sanitizeSearchValue(currentValue);
38854
38855        if (cleanValue !== currentValue) {
38856            if (cleanValue) {
38857                currentUrl.searchParams.set(paramName, cleanValue);
38858            } else {
38859                currentUrl.searchParams.delete(paramName);
38860            }
38861
38862            window.history.replaceState({}, '', currentUrl.toString());
38863        }
38864
38865        if (input) {
38866            input.value = cleanValue;
38867        }
38868    }
38869
38870    function bindSearchSanitizer(form, options) {
38871        if (!form) {
38872            return;
38873        }
38874
38875        options = options || {};
38876
38877        var queryParamName = options.queryParamName || 'q';
38878        var inputSelector = options.inputSelector || 'input[name="' + queryParamName + '"]';
38879        var input = form.querySelector(inputSelector);
38880
38881        cleanQueryParamInUrl(queryParamName, input);
38882
38883        if (!input) {
38884            return;
38885        }
38886
38887        form.addEventListener('submit', function () {
38888            input.value = sanitizeSearchValue(input.value);
38889        });
38890    }
38891
38892    // Reusable API for other pages/forms.
38893    window.SearchSanitizer = window.SearchSanitizer || {};
38894    window.SearchSanitizer.sanitize = sanitizeSearchValue;
38895    window.SearchSanitizer.bindForm = bindSearchSanitizer;
38896    window.SearchSanitizer.cleanUrlParam = cleanQueryParamInUrl;
38897
38898    (function initSearchSanitizers() {
38899        // Current admin customers search form.
38900        bindSearchSanitizer(document.getElementById('filter_table_s'));
38901        bindSearchSanitizer(document.getElementById('filter_table_s'), {
38902            queryParamName: 'u',
38903            inputSelector: 'input[name="u"]'
38904        });
38905
38906        // Future forms can opt-in by adding class + data attributes.
38907        $('.js-search-sanitize-form').each(function () {
38908            var form = this;
38909            bindSearchSanitizer(form, {
38910                queryParamName: form.getAttribute('data-query-param') || 'q',
38911                inputSelector: form.getAttribute('data-query-input') || undefined
38912            });
38913        });
38914    })();
38915
38916    // Cookie name is promo_popup_dismissed_<id>
38917    (function promoPopupInit() {
38918        var wrap = document.getElementById('promo-popup-wrap');
38919        if (!wrap) return;
38920        var cookieName = wrap.getAttribute('data-cookie-name');
38921        var cookieDays = parseInt(wrap.getAttribute('data-cookie-days'), 10) || 7;
38922
38923        function getCookie(name) {
38924            var m = document.cookie.match(new RegExp('(?:^|; )' + name.replace(/([.*+?^${}()|[\]\\])/g, '\\$1') + '=([^;]*)'));
38925            return m ? decodeURIComponent(m[1]) : null;
38926        }
38927        function setCookie(name, value, days) {
38928            var d = new Date();
38929            d.setTime(d.getTime() + days * 24 * 60 * 60 * 1000);
38930            document.cookie = name + '=' + encodeURIComponent(value) + ';path=/;expires=' + d.toUTCString() + ';SameSite=Lax';
38931        }
38932
38933        if (getCookie(cookieName)) {
38934            if (wrap.parentNode) wrap.parentNode.removeChild(wrap);
38935            return;
38936        }
38937
38938        wrap.style.display = '';
38939        document.body.classList.add('promo-popup-open');
38940
38941        var closeBtn = wrap.querySelector('.promo-popup-close');
38942        var overlay = wrap.querySelector('.promo-popup-overlay');
38943
38944        function closePopup() {
38945            setCookie(cookieName, '1', cookieDays);
38946            wrap.style.display = 'none';
38947            document.body.classList.remove('promo-popup-open');
38948        }
38949
38950        if (closeBtn) closeBtn.addEventListener('click', closePopup);
38951        if (overlay) overlay.addEventListener('click', closePopup);
38952    })();
38953
38954});
38955
38956/**
38957 * This file is part of the "box" project.
38958 *
38959 * (c) Alex Buturlakin [email protected]
38960 */
38961
38962;(function($) {
38963  $(document).ready(function() {
38964
38965    // user log
38966    var userSearchButton = $('#form-admin-log-search').find('button'),
38967        userSearchSelect = $('#admin-log-user-search'),
38968        filterTypeSelect   = $('#admin-log-type'),
38969        filterStatusSelect = $('#admin-log-status'),
38970        filterClearButton  = $('#form-admin-log-filter-clear'),
38971        filterButton       = $('#form-admin-log-filter').find('button');
38972
38973    filterTypeSelect.select2({
38974      placeholder: 'Select Type',
38975      width: '100%'
38976    });
38977
38978    filterStatusSelect.select2({
38979      placeholder: 'Select Status',
38980      width: '100%'
38981    });
38982
38983    filterButton.click(function() {
38984
38985      var t = filterTypeSelect.val(),
38986          s = filterStatusSelect.val(),
38987          u = window.location.href;
38988
38989      if(t && '' != t) {
38990        u = $.updateUrlParam(u, 'type', t);
38991      }
38992
38993      if(s && '' != s) {
38994        u = $.updateUrlParam(u, 's', s);
38995      }
38996
38997      window.location.href = u;
38998
38999      return false;
39000    });
39001
39002    filterClearButton.click(function() {
39003      var u =  window.location.href;
39004
39005      u = $.removeUrlParam(u, 's');
39006      u = $.removeUrlParam(u, 'type');
39007
39008      window.location.href = u;
39009
39010      return false;
39011    });
39012
39013    $('.debug-log-view').click(function () {
39014      var el = $(this);
39015
39016      el.addClass('view');
39017    });
39018
39019    $('.debug-log-view-single').click(function() {
39020      $(this).addClass('view');
39021    });
39022
39023    // open full log data in modal on click (user-log "Data" column)
39024    $(document).on('click', '.js-log-data', function (e) {
39025      var $target = $(this);
39026      var text = $target.text();
39027
39028      var $backdrop = $('<div class="log-data-modal-backdrop"></div>');
39029      var $modal = $('<pre class="log-data-modal"></pre>').text(text);
39030
39031      $backdrop.on('click', function () {
39032        $modal.remove();
39033        $backdrop.remove();
39034      });
39035
39036      $('body').append($backdrop).append($modal);
39037    });
39038
39039    userSearchSelect.select2({
39040      width: '100%',
39041      // dir: "rtl",
39042      containerCssClass: 'admin-control-search',
39043
39044      ajax: {
39045        delay: 250,
39046        url: '/admin/user-log/search',
39047        placeholder: 'This is my placeholder',
39048        allowClear: true,
39049        data: function(params) {
39050          let term = params.term;
39051          // Convert non-ASCII domains to punycode
39052          if (term && /[^\x00-\x7F]/.test(term)) {
39053            try {
39054              term = new URL('http://' + term).hostname;
39055            } catch(e) {}
39056          }
39057          return {q: term};
39058        },
39059        processResults: function (data, params) {
39060          // parse the results into the format expected by Select2
39061          // since we are using custom formatting functions we do not need to
39062          // alter the remote JSON data, except to indicate that infinite
39063          // scrolling can be used
39064          params.page = params.page || 1;
39065
39066          var formattedData = [];
39067
39068          $.each(data, function(subject, elements) {
39069            if(Object.keys(elements).length > 0) {
39070              var children = [];
39071              var type     = subject;
39072
39073              if('users' == subject) {
39074                type = 'u';
39075              }
39076
39077              if('contacts' == subject) {
39078                type = 'c';
39079              }
39080
39081              if('domains' == subject) {
39082                type = 'd';
39083              }
39084
39085              $.each(elements, function(id, name) {
39086                children.push({id: id, text: name, group: subject, type: type});
39087              });
39088
39089              formattedData.push({id: subject, text: $.ucfirst(subject), children: children});
39090            }
39091          });
39092
39093          return {
39094            results: formattedData
39095            // pagination: {
39096            //   more: (params.page * 30) < data.total_count
39097            // }
39098          };
39099        },
39100        escapeMarkup: function (markup) { return markup; }, // let our custom formatter work
39101        minimumInputLength: 3
39102      }
39103    }).on('select2:select', function(e) {
39104      userSearchButton.prop('disabled', false);
39105    });
39106
39107    userSearchButton.click(function() {
39108      var data = userSearchSelect.select2('data');
39109
39110      if(0 == data.length) {
39111        $(this.prop('disabled', true));
39112
39113        return false;
39114      }
39115
39116      var selected = data[0];
39117
39118      // redirect
39119      window.location.href = Storage.getData('app_url') + 'admin/user-log?' + selected.type + '=' + selected.id;
39120      return false;
39121    });
39122
39123
39124    $(document).on('click', '.admin-op-domain-update-status', function (e) {
39125      e.preventDefault();
39126      var status = $(this).attr('data-status');
39127      var con = confirm('Are you sure to change domain status to ' + status + '?');
39128
39129      if (con) {
39130        $.ajax({
39131          url: $(this).attr('href'),
39132          type: 'POST',
39133          data: {
39134            'status': status,
39135          },
39136          success: function () {
39137            alert('Well done! Status was updated successfully.');
39138            $('#admin-domain-op-errors').html('').addClass('hidden');
39139          },
39140          error: function (xhr) {
39141            if (403 === xhr.status) {
39142              window.location.href = '/user/login';
39143            }
39144
39145            $('#admin-domain-op-errors').html(xhr.responseJSON.msg).removeClass('hidden');
39146          }
39147        });
39148      }
39149    });
39150
39151    $(document).on('click', '.admin-op-domain-delete', function (e) {
39152      e.preventDefault();
39153      var status = $(this).attr('data-status');
39154      var con = confirm('Are you sure to delete selected domain?');
39155
39156      if (con) {
39157        $.ajax({
39158          url: $(this).attr('href'),
39159          type: 'POST',
39160          data: {
39161            'status': status,
39162          },
39163          success: function () {
39164            alert('Well done! Domain was deleted successfully.');
39165            $('#admin-domain-op-errors').html('').addClass('hidden');
39166            window.location.reload();
39167          },
39168          error: function (xhr) {
39169            if (403 === xhr.status) {
39170              window.location.href = '/user/login';
39171            }
39172
39173            $('#admin-domain-op-errors').html(xhr.responseJSON.msg).removeClass('hidden');
39174          }
39175        });
39176      }
39177    });
39178
39179
39180    // section for verify-view.php
39181    var admin_dverify_form = $("#admin-dverify-form");
39182    admin_dverify_form.find(":input[type=text]").prop("disabled", true);
39183    admin_dverify_form.find(":input[type=radio]").prop("disabled", true);
39184    admin_dverify_form.find(":input[type=submit]").prop("disabled", true);
39185
39186    var pr_input = admin_dverify_form.find(":input[name='name']");
39187    var org_input = admin_dverify_form.find(":input[name='organization_name']");
39188    var orgid_input = admin_dverify_form.find(":input[name='organization_number']");
39189    var admin_dverify_form_org = admin_dverify_form.attr("org");
39190
39191    var admin_dverify_edit_btn = $("#admin-dverify-edit-button");
39192    
39193    // disable or enable fields by owner type related to current owner type
39194    $(admin_dverify_edit_btn).click(function(event){
39195        event.preventDefault();
39196        admin_dverify_form.find(":input").prop("disabled", false);
39197        admin_dverify_edit_btn.prop("disabled", true);
39198        if(admin_dverify_form_org){
39199            org_input.prop("disabled", false);
39200            orgid_input.prop("disabled", false);
39201            pr_input.prop("disabled", true);
39202            //pr_input.val(null);
39203        }else{
39204            org_input.prop("disabled", true);
39205            orgid_input.prop("disabled", true);
39206            pr_input.prop("disabled", false);
39207            org_input.val(null);
39208            orgid_input.val(null);  
39209        }
39210    });
39211
39212    //disable form on click outside
39213    $("#admin-verify-edit-table").click(function(event){
39214        if (!$(event.target).closest("#admin-dverify-form").length) {
39215            admin_dverify_form.find(":input").prop("disabled", true);
39216            admin_dverify_edit_btn.prop("disabled", false);
39217        }
39218    });
39219
39220    // disable or enable fields by owner type of radio button
39221    admin_dverify_form.on("change", "input[name='owner-type']", function () {
39222
39223        if($(this).val() == "private"){
39224            if(confirm("Are you sure you want to change the holder to a private entity?")){
39225                org_input.prop("disabled", true);
39226                orgid_input.prop("disabled", true);
39227                pr_input.prop("disabled", false);
39228                org_input.val(null);
39229                orgid_input.val(null);
39230            }else{
39231                $("#owner-org").prop("checked", true);
39232            }
39233            
39234        }else{
39235            if(confirm("Are you sure you want to change the holder to a organization entity?")){
39236                org_input.prop("disabled", false);
39237                orgid_input.prop("disabled", false);
39238                org_input.prop("required", true);
39239                orgid_input.prop("required", true);
39240                pr_input.prop("disabled", true);
39241            }else{
39242                $("#owner-pr").prop("checked", true);
39243            }
39244        }
39245    });
39246
39247    // fill org input to owener name
39248    org_input.on("input", function() {
39249        let value = $(this).val();
39250        pr_input.val(value);
39251    });
39252
39253
39254    // reject verify
39255    $("#admin-domain-reject-verify").click(function(event){
39256        event.preventDefault();
39257        $("#admin-domain-reject-verify-reason").removeClass("hidden");
39258        var reason = $("#admin-domain-reject-verify-reason").val();
39259        if(!reason || reason.trim() == ""){
39260          alert("Please enter a reason for rejection");
39261            return;
39262        }
39263        
39264        var target = $(this).data("url-target");
39265        $(this).prop("disabled", true);
39266        $.ajax({
39267            url: target,
39268            type: 'POST',
39269            data: {
39270                'reason': reason
39271            },
39272            success: function(response){
39273              window.location.href = response.redirect;
39274            },
39275            error: function(xhr){ 
39276                $('#admin-domain-reject-verify-reason').replaceWith('<div class="alert alert-danger">' + xhr.responseJSON.msg + '</div>');
39277                $(this).prop("disabled", false);
39278            }
39279        });
39280    });
39281
39282    // approve verify
39283    $("#admin-domain-approve-verify").click(function(event){
39284        event.preventDefault();
39285        var target = $(this).data("url-target");
39286        $(this).prop("disabled", true);
39287        $.ajax({
39288            url: target,
39289            type: 'POST',
39290            success: function(response){
39291              window.location.href = response.redirect;
39292            },
39293            error: function(xhr){ 
39294                $('#admin-domain-approve-verify').replaceWith('<div class="alert alert-danger">' + xhr.responseJSON.msg + '</div>');
39295                $(this).prop("disabled", false);
39296            }
39297        });
39298    });
39299  });
39300})(jQuery);
39301//# sourceMappingURL=bundle.js.map

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.