/* Minification failed. Returning unminified contents.
(22961,30-31): run-time error JS1013: Syntax error in regular expression: ;
 */
/*! jQuery UI - v1.13.2 - 2022-07-14
* http://jqueryui.com
* Includes: widget.js, position.js, data.js, disable-selection.js, effect.js, effects/effect-blind.js, effects/effect-bounce.js, effects/effect-clip.js, effects/effect-drop.js, effects/effect-explode.js, effects/effect-fade.js, effects/effect-fold.js, effects/effect-highlight.js, effects/effect-puff.js, effects/effect-pulsate.js, effects/effect-scale.js, effects/effect-shake.js, effects/effect-size.js, effects/effect-slide.js, effects/effect-transfer.js, focusable.js, form-reset-mixin.js, jquery-patch.js, keycode.js, labels.js, scroll-parent.js, tabbable.js, unique-id.js, widgets/accordion.js, widgets/autocomplete.js, widgets/button.js, widgets/checkboxradio.js, widgets/controlgroup.js, widgets/datepicker.js, widgets/dialog.js, widgets/draggable.js, widgets/droppable.js, widgets/menu.js, widgets/mouse.js, widgets/progressbar.js, widgets/resizable.js, widgets/selectable.js, widgets/selectmenu.js, widgets/slider.js, widgets/sortable.js, widgets/spinner.js, widgets/tabs.js, widgets/tooltip.js
* Copyright jQuery Foundation and other contributors; Licensed MIT */

( function( factory ) {
	"use strict";
	
	if ( typeof define === "function" && define.amd ) {

		// AMD. Register as an anonymous module.
		define( [ "jquery" ], factory );
	} else {

		// Browser globals
		factory( jQuery );
	}
} )( function( $ ) {
"use strict";

$.ui = $.ui || {};

var version = $.ui.version = "1.13.2";


/*!
 * jQuery UI Widget 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Widget
//>>group: Core
//>>description: Provides a factory for creating stateful widgets with a common API.
//>>docs: http://api.jqueryui.com/jQuery.widget/
//>>demos: http://jqueryui.com/widget/


var widgetUuid = 0;
var widgetHasOwnProperty = Array.prototype.hasOwnProperty;
var widgetSlice = Array.prototype.slice;

$.cleanData = ( function( orig ) {
	return function( elems ) {
		var events, elem, i;
		for ( i = 0; ( elem = elems[ i ] ) != null; i++ ) {

			// Only trigger remove when necessary to save time
			events = $._data( elem, "events" );
			if ( events && events.remove ) {
				$( elem ).triggerHandler( "remove" );
			}
		}
		orig( elems );
	};
} )( $.cleanData );

$.widget = function( name, base, prototype ) {
	var existingConstructor, constructor, basePrototype;

	// ProxiedPrototype allows the provided prototype to remain unmodified
	// so that it can be used as a mixin for multiple widgets (#8876)
	var proxiedPrototype = {};

	var namespace = name.split( "." )[ 0 ];
	name = name.split( "." )[ 1 ];
	var fullName = namespace + "-" + name;

	if ( !prototype ) {
		prototype = base;
		base = $.Widget;
	}

	if ( Array.isArray( prototype ) ) {
		prototype = $.extend.apply( null, [ {} ].concat( prototype ) );
	}

	// Create selector for plugin
	$.expr.pseudos[ fullName.toLowerCase() ] = function( elem ) {
		return !!$.data( elem, fullName );
	};

	$[ namespace ] = $[ namespace ] || {};
	existingConstructor = $[ namespace ][ name ];
	constructor = $[ namespace ][ name ] = function( options, element ) {

		// Allow instantiation without "new" keyword
		if ( !this || !this._createWidget ) {
			return new constructor( options, element );
		}

		// Allow instantiation without initializing for simple inheritance
		// must use "new" keyword (the code above always passes args)
		if ( arguments.length ) {
			this._createWidget( options, element );
		}
	};

	// Extend with the existing constructor to carry over any static properties
	$.extend( constructor, existingConstructor, {
		version: prototype.version,

		// Copy the object used to create the prototype in case we need to
		// redefine the widget later
		_proto: $.extend( {}, prototype ),

		// Track widgets that inherit from this widget in case this widget is
		// redefined after a widget inherits from it
		_childConstructors: []
	} );

	basePrototype = new base();

	// We need to make the options hash a property directly on the new instance
	// otherwise we'll modify the options hash on the prototype that we're
	// inheriting from
	basePrototype.options = $.widget.extend( {}, basePrototype.options );
	$.each( prototype, function( prop, value ) {
		if ( typeof value !== "function" ) {
			proxiedPrototype[ prop ] = value;
			return;
		}
		proxiedPrototype[ prop ] = ( function() {
			function _super() {
				return base.prototype[ prop ].apply( this, arguments );
			}

			function _superApply( args ) {
				return base.prototype[ prop ].apply( this, args );
			}

			return function() {
				var __super = this._super;
				var __superApply = this._superApply;
				var returnValue;

				this._super = _super;
				this._superApply = _superApply;

				returnValue = value.apply( this, arguments );

				this._super = __super;
				this._superApply = __superApply;

				return returnValue;
			};
		} )();
	} );
	constructor.prototype = $.widget.extend( basePrototype, {

		// TODO: remove support for widgetEventPrefix
		// always use the name + a colon as the prefix, e.g., draggable:start
		// don't prefix for widgets that aren't DOM-based
		widgetEventPrefix: existingConstructor ? ( basePrototype.widgetEventPrefix || name ) : name
	}, proxiedPrototype, {
		constructor: constructor,
		namespace: namespace,
		widgetName: name,
		widgetFullName: fullName
	} );

	// If this widget is being redefined then we need to find all widgets that
	// are inheriting from it and redefine all of them so that they inherit from
	// the new version of this widget. We're essentially trying to replace one
	// level in the prototype chain.
	if ( existingConstructor ) {
		$.each( existingConstructor._childConstructors, function( i, child ) {
			var childPrototype = child.prototype;

			// Redefine the child widget using the same prototype that was
			// originally used, but inherit from the new version of the base
			$.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor,
				child._proto );
		} );

		// Remove the list of existing child constructors from the old constructor
		// so the old child constructors can be garbage collected
		delete existingConstructor._childConstructors;
	} else {
		base._childConstructors.push( constructor );
	}

	$.widget.bridge( name, constructor );

	return constructor;
};

$.widget.extend = function( target ) {
	var input = widgetSlice.call( arguments, 1 );
	var inputIndex = 0;
	var inputLength = input.length;
	var key;
	var value;

	for ( ; inputIndex < inputLength; inputIndex++ ) {
		for ( key in input[ inputIndex ] ) {
			value = input[ inputIndex ][ key ];
			if ( widgetHasOwnProperty.call( input[ inputIndex ], key ) && value !== undefined ) {

				// Clone objects
				if ( $.isPlainObject( value ) ) {
					target[ key ] = $.isPlainObject( target[ key ] ) ?
						$.widget.extend( {}, target[ key ], value ) :

						// Don't extend strings, arrays, etc. with objects
						$.widget.extend( {}, value );

				// Copy everything else by reference
				} else {
					target[ key ] = value;
				}
			}
		}
	}
	return target;
};

$.widget.bridge = function( name, object ) {
	var fullName = object.prototype.widgetFullName || name;
	$.fn[ name ] = function( options ) {
		var isMethodCall = typeof options === "string";
		var args = widgetSlice.call( arguments, 1 );
		var returnValue = this;

		if ( isMethodCall ) {

			// If this is an empty collection, we need to have the instance method
			// return undefined instead of the jQuery instance
			if ( !this.length && options === "instance" ) {
				returnValue = undefined;
			} else {
				this.each( function() {
					var methodValue;
					var instance = $.data( this, fullName );

					if ( options === "instance" ) {
						returnValue = instance;
						return false;
					}

					if ( !instance ) {
						return $.error( "cannot call methods on " + name +
							" prior to initialization; " +
							"attempted to call method '" + options + "'" );
					}

					if ( typeof instance[ options ] !== "function" ||
						options.charAt( 0 ) === "_" ) {
						return $.error( "no such method '" + options + "' for " + name +
							" widget instance" );
					}

					methodValue = instance[ options ].apply( instance, args );

					if ( methodValue !== instance && methodValue !== undefined ) {
						returnValue = methodValue && methodValue.jquery ?
							returnValue.pushStack( methodValue.get() ) :
							methodValue;
						return false;
					}
				} );
			}
		} else {

			// Allow multiple hashes to be passed on init
			if ( args.length ) {
				options = $.widget.extend.apply( null, [ options ].concat( args ) );
			}

			this.each( function() {
				var instance = $.data( this, fullName );
				if ( instance ) {
					instance.option( options || {} );
					if ( instance._init ) {
						instance._init();
					}
				} else {
					$.data( this, fullName, new object( options, this ) );
				}
			} );
		}

		return returnValue;
	};
};

$.Widget = function( /* options, element */ ) {};
$.Widget._childConstructors = [];

$.Widget.prototype = {
	widgetName: "widget",
	widgetEventPrefix: "",
	defaultElement: "<div>",

	options: {
		classes: {},
		disabled: false,

		// Callbacks
		create: null
	},

	_createWidget: function( options, element ) {
		element = $( element || this.defaultElement || this )[ 0 ];
		this.element = $( element );
		this.uuid = widgetUuid++;
		this.eventNamespace = "." + this.widgetName + this.uuid;

		this.bindings = $();
		this.hoverable = $();
		this.focusable = $();
		this.classesElementLookup = {};

		if ( element !== this ) {
			$.data( element, this.widgetFullName, this );
			this._on( true, this.element, {
				remove: function( event ) {
					if ( event.target === element ) {
						this.destroy();
					}
				}
			} );
			this.document = $( element.style ?

				// Element within the document
				element.ownerDocument :

				// Element is window or document
				element.document || element );
			this.window = $( this.document[ 0 ].defaultView || this.document[ 0 ].parentWindow );
		}

		this.options = $.widget.extend( {},
			this.options,
			this._getCreateOptions(),
			options );

		this._create();

		if ( this.options.disabled ) {
			this._setOptionDisabled( this.options.disabled );
		}

		this._trigger( "create", null, this._getCreateEventData() );
		this._init();
	},

	_getCreateOptions: function() {
		return {};
	},

	_getCreateEventData: $.noop,

	_create: $.noop,

	_init: $.noop,

	destroy: function() {
		var that = this;

		this._destroy();
		$.each( this.classesElementLookup, function( key, value ) {
			that._removeClass( value, key );
		} );

		// We can probably remove the unbind calls in 2.0
		// all event bindings should go through this._on()
		this.element
			.off( this.eventNamespace )
			.removeData( this.widgetFullName );
		this.widget()
			.off( this.eventNamespace )
			.removeAttr( "aria-disabled" );

		// Clean up events and states
		this.bindings.off( this.eventNamespace );
	},

	_destroy: $.noop,

	widget: function() {
		return this.element;
	},

	option: function( key, value ) {
		var options = key;
		var parts;
		var curOption;
		var i;

		if ( arguments.length === 0 ) {

			// Don't return a reference to the internal hash
			return $.widget.extend( {}, this.options );
		}

		if ( typeof key === "string" ) {

			// Handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
			options = {};
			parts = key.split( "." );
			key = parts.shift();
			if ( parts.length ) {
				curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
				for ( i = 0; i < parts.length - 1; i++ ) {
					curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
					curOption = curOption[ parts[ i ] ];
				}
				key = parts.pop();
				if ( arguments.length === 1 ) {
					return curOption[ key ] === undefined ? null : curOption[ key ];
				}
				curOption[ key ] = value;
			} else {
				if ( arguments.length === 1 ) {
					return this.options[ key ] === undefined ? null : this.options[ key ];
				}
				options[ key ] = value;
			}
		}

		this._setOptions( options );

		return this;
	},

	_setOptions: function( options ) {
		var key;

		for ( key in options ) {
			this._setOption( key, options[ key ] );
		}

		return this;
	},

	_setOption: function( key, value ) {
		if ( key === "classes" ) {
			this._setOptionClasses( value );
		}

		this.options[ key ] = value;

		if ( key === "disabled" ) {
			this._setOptionDisabled( value );
		}

		return this;
	},

	_setOptionClasses: function( value ) {
		var classKey, elements, currentElements;

		for ( classKey in value ) {
			currentElements = this.classesElementLookup[ classKey ];
			if ( value[ classKey ] === this.options.classes[ classKey ] ||
					!currentElements ||
					!currentElements.length ) {
				continue;
			}

			// We are doing this to create a new jQuery object because the _removeClass() call
			// on the next line is going to destroy the reference to the current elements being
			// tracked. We need to save a copy of this collection so that we can add the new classes
			// below.
			elements = $( currentElements.get() );
			this._removeClass( currentElements, classKey );

			// We don't use _addClass() here, because that uses this.options.classes
			// for generating the string of classes. We want to use the value passed in from
			// _setOption(), this is the new value of the classes option which was passed to
			// _setOption(). We pass this value directly to _classes().
			elements.addClass( this._classes( {
				element: elements,
				keys: classKey,
				classes: value,
				add: true
			} ) );
		}
	},

	_setOptionDisabled: function( value ) {
		this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null, !!value );

		// If the widget is becoming disabled, then nothing is interactive
		if ( value ) {
			this._removeClass( this.hoverable, null, "ui-state-hover" );
			this._removeClass( this.focusable, null, "ui-state-focus" );
		}
	},

	enable: function() {
		return this._setOptions( { disabled: false } );
	},

	disable: function() {
		return this._setOptions( { disabled: true } );
	},

	_classes: function( options ) {
		var full = [];
		var that = this;

		options = $.extend( {
			element: this.element,
			classes: this.options.classes || {}
		}, options );

		function bindRemoveEvent() {
			var nodesToBind = [];

			options.element.each( function( _, element ) {
				var isTracked = $.map( that.classesElementLookup, function( elements ) {
					return elements;
				} )
					.some( function( elements ) {
						return elements.is( element );
					} );

				if ( !isTracked ) {
					nodesToBind.push( element );
				}
			} );

			that._on( $( nodesToBind ), {
				remove: "_untrackClassesElement"
			} );
		}

		function processClassString( classes, checkOption ) {
			var current, i;
			for ( i = 0; i < classes.length; i++ ) {
				current = that.classesElementLookup[ classes[ i ] ] || $();
				if ( options.add ) {
					bindRemoveEvent();
					current = $( $.uniqueSort( current.get().concat( options.element.get() ) ) );
				} else {
					current = $( current.not( options.element ).get() );
				}
				that.classesElementLookup[ classes[ i ] ] = current;
				full.push( classes[ i ] );
				if ( checkOption && options.classes[ classes[ i ] ] ) {
					full.push( options.classes[ classes[ i ] ] );
				}
			}
		}

		if ( options.keys ) {
			processClassString( options.keys.match( /\S+/g ) || [], true );
		}
		if ( options.extra ) {
			processClassString( options.extra.match( /\S+/g ) || [] );
		}

		return full.join( " " );
	},

	_untrackClassesElement: function( event ) {
		var that = this;
		$.each( that.classesElementLookup, function( key, value ) {
			if ( $.inArray( event.target, value ) !== -1 ) {
				that.classesElementLookup[ key ] = $( value.not( event.target ).get() );
			}
		} );

		this._off( $( event.target ) );
	},

	_removeClass: function( element, keys, extra ) {
		return this._toggleClass( element, keys, extra, false );
	},

	_addClass: function( element, keys, extra ) {
		return this._toggleClass( element, keys, extra, true );
	},

	_toggleClass: function( element, keys, extra, add ) {
		add = ( typeof add === "boolean" ) ? add : extra;
		var shift = ( typeof element === "string" || element === null ),
			options = {
				extra: shift ? keys : extra,
				keys: shift ? element : keys,
				element: shift ? this.element : element,
				add: add
			};
		options.element.toggleClass( this._classes( options ), add );
		return this;
	},

	_on: function( suppressDisabledCheck, element, handlers ) {
		var delegateElement;
		var instance = this;

		// No suppressDisabledCheck flag, shuffle arguments
		if ( typeof suppressDisabledCheck !== "boolean" ) {
			handlers = element;
			element = suppressDisabledCheck;
			suppressDisabledCheck = false;
		}

		// No element argument, shuffle and use this.element
		if ( !handlers ) {
			handlers = element;
			element = this.element;
			delegateElement = this.widget();
		} else {
			element = delegateElement = $( element );
			this.bindings = this.bindings.add( element );
		}

		$.each( handlers, function( event, handler ) {
			function handlerProxy() {

				// Allow widgets to customize the disabled handling
				// - disabled as an array instead of boolean
				// - disabled class as method for disabling individual parts
				if ( !suppressDisabledCheck &&
						( instance.options.disabled === true ||
						$( this ).hasClass( "ui-state-disabled" ) ) ) {
					return;
				}
				return ( typeof handler === "string" ? instance[ handler ] : handler )
					.apply( instance, arguments );
			}

			// Copy the guid so direct unbinding works
			if ( typeof handler !== "string" ) {
				handlerProxy.guid = handler.guid =
					handler.guid || handlerProxy.guid || $.guid++;
			}

			var match = event.match( /^([\w:-]*)\s*(.*)$/ );
			var eventName = match[ 1 ] + instance.eventNamespace;
			var selector = match[ 2 ];

			if ( selector ) {
				delegateElement.on( eventName, selector, handlerProxy );
			} else {
				element.on( eventName, handlerProxy );
			}
		} );
	},

	_off: function( element, eventName ) {
		eventName = ( eventName || "" ).split( " " ).join( this.eventNamespace + " " ) +
			this.eventNamespace;
		element.off( eventName );

		// Clear the stack to avoid memory leaks (#10056)
		this.bindings = $( this.bindings.not( element ).get() );
		this.focusable = $( this.focusable.not( element ).get() );
		this.hoverable = $( this.hoverable.not( element ).get() );
	},

	_delay: function( handler, delay ) {
		function handlerProxy() {
			return ( typeof handler === "string" ? instance[ handler ] : handler )
				.apply( instance, arguments );
		}
		var instance = this;
		return setTimeout( handlerProxy, delay || 0 );
	},

	_hoverable: function( element ) {
		this.hoverable = this.hoverable.add( element );
		this._on( element, {
			mouseenter: function( event ) {
				this._addClass( $( event.currentTarget ), null, "ui-state-hover" );
			},
			mouseleave: function( event ) {
				this._removeClass( $( event.currentTarget ), null, "ui-state-hover" );
			}
		} );
	},

	_focusable: function( element ) {
		this.focusable = this.focusable.add( element );
		this._on( element, {
			focusin: function( event ) {
				this._addClass( $( event.currentTarget ), null, "ui-state-focus" );
			},
			focusout: function( event ) {
				this._removeClass( $( event.currentTarget ), null, "ui-state-focus" );
			}
		} );
	},

	_trigger: function( type, event, data ) {
		var prop, orig;
		var callback = this.options[ type ];

		data = data || {};
		event = $.Event( event );
		event.type = ( type === this.widgetEventPrefix ?
			type :
			this.widgetEventPrefix + type ).toLowerCase();

		// The original event may come from any element
		// so we need to reset the target on the new event
		event.target = this.element[ 0 ];

		// Copy original event properties over to the new event
		orig = event.originalEvent;
		if ( orig ) {
			for ( prop in orig ) {
				if ( !( prop in event ) ) {
					event[ prop ] = orig[ prop ];
				}
			}
		}

		this.element.trigger( event, data );
		return !( typeof callback === "function" &&
			callback.apply( this.element[ 0 ], [ event ].concat( data ) ) === false ||
			event.isDefaultPrevented() );
	}
};

$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
	$.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
		if ( typeof options === "string" ) {
			options = { effect: options };
		}

		var hasOptions;
		var effectName = !options ?
			method :
			options === true || typeof options === "number" ?
				defaultEffect :
				options.effect || defaultEffect;

		options = options || {};
		if ( typeof options === "number" ) {
			options = { duration: options };
		} else if ( options === true ) {
			options = {};
		}

		hasOptions = !$.isEmptyObject( options );
		options.complete = callback;

		if ( options.delay ) {
			element.delay( options.delay );
		}

		if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
			element[ method ]( options );
		} else if ( effectName !== method && element[ effectName ] ) {
			element[ effectName ]( options.duration, options.easing, callback );
		} else {
			element.queue( function( next ) {
				$( this )[ method ]();
				if ( callback ) {
					callback.call( element[ 0 ] );
				}
				next();
			} );
		}
	};
} );

var widget = $.widget;


/*!
 * jQuery UI Position 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 *
 * http://api.jqueryui.com/position/
 */

//>>label: Position
//>>group: Core
//>>description: Positions elements relative to other elements.
//>>docs: http://api.jqueryui.com/position/
//>>demos: http://jqueryui.com/position/


( function() {
var cachedScrollbarWidth,
	max = Math.max,
	abs = Math.abs,
	rhorizontal = /left|center|right/,
	rvertical = /top|center|bottom/,
	roffset = /[\+\-]\d+(\.[\d]+)?%?/,
	rposition = /^\w+/,
	rpercent = /%$/,
	_position = $.fn.position;

function getOffsets( offsets, width, height ) {
	return [
		parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
		parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
	];
}

function parseCss( element, property ) {
	return parseInt( $.css( element, property ), 10 ) || 0;
}

function isWindow( obj ) {
	return obj != null && obj === obj.window;
}

function getDimensions( elem ) {
	var raw = elem[ 0 ];
	if ( raw.nodeType === 9 ) {
		return {
			width: elem.width(),
			height: elem.height(),
			offset: { top: 0, left: 0 }
		};
	}
	if ( isWindow( raw ) ) {
		return {
			width: elem.width(),
			height: elem.height(),
			offset: { top: elem.scrollTop(), left: elem.scrollLeft() }
		};
	}
	if ( raw.preventDefault ) {
		return {
			width: 0,
			height: 0,
			offset: { top: raw.pageY, left: raw.pageX }
		};
	}
	return {
		width: elem.outerWidth(),
		height: elem.outerHeight(),
		offset: elem.offset()
	};
}

$.position = {
	scrollbarWidth: function() {
		if ( cachedScrollbarWidth !== undefined ) {
			return cachedScrollbarWidth;
		}
		var w1, w2,
			div = $( "<div style=" +
				"'display:block;position:absolute;width:200px;height:200px;overflow:hidden;'>" +
				"<div style='height:300px;width:auto;'></div></div>" ),
			innerDiv = div.children()[ 0 ];

		$( "body" ).append( div );
		w1 = innerDiv.offsetWidth;
		div.css( "overflow", "scroll" );

		w2 = innerDiv.offsetWidth;

		if ( w1 === w2 ) {
			w2 = div[ 0 ].clientWidth;
		}

		div.remove();

		return ( cachedScrollbarWidth = w1 - w2 );
	},
	getScrollInfo: function( within ) {
		var overflowX = within.isWindow || within.isDocument ? "" :
				within.element.css( "overflow-x" ),
			overflowY = within.isWindow || within.isDocument ? "" :
				within.element.css( "overflow-y" ),
			hasOverflowX = overflowX === "scroll" ||
				( overflowX === "auto" && within.width < within.element[ 0 ].scrollWidth ),
			hasOverflowY = overflowY === "scroll" ||
				( overflowY === "auto" && within.height < within.element[ 0 ].scrollHeight );
		return {
			width: hasOverflowY ? $.position.scrollbarWidth() : 0,
			height: hasOverflowX ? $.position.scrollbarWidth() : 0
		};
	},
	getWithinInfo: function( element ) {
		var withinElement = $( element || window ),
			isElemWindow = isWindow( withinElement[ 0 ] ),
			isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9,
			hasOffset = !isElemWindow && !isDocument;
		return {
			element: withinElement,
			isWindow: isElemWindow,
			isDocument: isDocument,
			offset: hasOffset ? $( element ).offset() : { left: 0, top: 0 },
			scrollLeft: withinElement.scrollLeft(),
			scrollTop: withinElement.scrollTop(),
			width: withinElement.outerWidth(),
			height: withinElement.outerHeight()
		};
	}
};

$.fn.position = function( options ) {
	if ( !options || !options.of ) {
		return _position.apply( this, arguments );
	}

	// Make a copy, we don't want to modify arguments
	options = $.extend( {}, options );

	var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions,

		// Make sure string options are treated as CSS selectors
		target = typeof options.of === "string" ?
			$( document ).find( options.of ) :
			$( options.of ),

		within = $.position.getWithinInfo( options.within ),
		scrollInfo = $.position.getScrollInfo( within ),
		collision = ( options.collision || "flip" ).split( " " ),
		offsets = {};

	dimensions = getDimensions( target );
	if ( target[ 0 ].preventDefault ) {

		// Force left top to allow flipping
		options.at = "left top";
	}
	targetWidth = dimensions.width;
	targetHeight = dimensions.height;
	targetOffset = dimensions.offset;

	// Clone to reuse original targetOffset later
	basePosition = $.extend( {}, targetOffset );

	// Force my and at to have valid horizontal and vertical positions
	// if a value is missing or invalid, it will be converted to center
	$.each( [ "my", "at" ], function() {
		var pos = ( options[ this ] || "" ).split( " " ),
			horizontalOffset,
			verticalOffset;

		if ( pos.length === 1 ) {
			pos = rhorizontal.test( pos[ 0 ] ) ?
				pos.concat( [ "center" ] ) :
				rvertical.test( pos[ 0 ] ) ?
					[ "center" ].concat( pos ) :
					[ "center", "center" ];
		}
		pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
		pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";

		// Calculate offsets
		horizontalOffset = roffset.exec( pos[ 0 ] );
		verticalOffset = roffset.exec( pos[ 1 ] );
		offsets[ this ] = [
			horizontalOffset ? horizontalOffset[ 0 ] : 0,
			verticalOffset ? verticalOffset[ 0 ] : 0
		];

		// Reduce to just the positions without the offsets
		options[ this ] = [
			rposition.exec( pos[ 0 ] )[ 0 ],
			rposition.exec( pos[ 1 ] )[ 0 ]
		];
	} );

	// Normalize collision option
	if ( collision.length === 1 ) {
		collision[ 1 ] = collision[ 0 ];
	}

	if ( options.at[ 0 ] === "right" ) {
		basePosition.left += targetWidth;
	} else if ( options.at[ 0 ] === "center" ) {
		basePosition.left += targetWidth / 2;
	}

	if ( options.at[ 1 ] === "bottom" ) {
		basePosition.top += targetHeight;
	} else if ( options.at[ 1 ] === "center" ) {
		basePosition.top += targetHeight / 2;
	}

	atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
	basePosition.left += atOffset[ 0 ];
	basePosition.top += atOffset[ 1 ];

	return this.each( function() {
		var collisionPosition, using,
			elem = $( this ),
			elemWidth = elem.outerWidth(),
			elemHeight = elem.outerHeight(),
			marginLeft = parseCss( this, "marginLeft" ),
			marginTop = parseCss( this, "marginTop" ),
			collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) +
				scrollInfo.width,
			collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) +
				scrollInfo.height,
			position = $.extend( {}, basePosition ),
			myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );

		if ( options.my[ 0 ] === "right" ) {
			position.left -= elemWidth;
		} else if ( options.my[ 0 ] === "center" ) {
			position.left -= elemWidth / 2;
		}

		if ( options.my[ 1 ] === "bottom" ) {
			position.top -= elemHeight;
		} else if ( options.my[ 1 ] === "center" ) {
			position.top -= elemHeight / 2;
		}

		position.left += myOffset[ 0 ];
		position.top += myOffset[ 1 ];

		collisionPosition = {
			marginLeft: marginLeft,
			marginTop: marginTop
		};

		$.each( [ "left", "top" ], function( i, dir ) {
			if ( $.ui.position[ collision[ i ] ] ) {
				$.ui.position[ collision[ i ] ][ dir ]( position, {
					targetWidth: targetWidth,
					targetHeight: targetHeight,
					elemWidth: elemWidth,
					elemHeight: elemHeight,
					collisionPosition: collisionPosition,
					collisionWidth: collisionWidth,
					collisionHeight: collisionHeight,
					offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
					my: options.my,
					at: options.at,
					within: within,
					elem: elem
				} );
			}
		} );

		if ( options.using ) {

			// Adds feedback as second argument to using callback, if present
			using = function( props ) {
				var left = targetOffset.left - position.left,
					right = left + targetWidth - elemWidth,
					top = targetOffset.top - position.top,
					bottom = top + targetHeight - elemHeight,
					feedback = {
						target: {
							element: target,
							left: targetOffset.left,
							top: targetOffset.top,
							width: targetWidth,
							height: targetHeight
						},
						element: {
							element: elem,
							left: position.left,
							top: position.top,
							width: elemWidth,
							height: elemHeight
						},
						horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
						vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
					};
				if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
					feedback.horizontal = "center";
				}
				if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
					feedback.vertical = "middle";
				}
				if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
					feedback.important = "horizontal";
				} else {
					feedback.important = "vertical";
				}
				options.using.call( this, props, feedback );
			};
		}

		elem.offset( $.extend( position, { using: using } ) );
	} );
};

$.ui.position = {
	fit: {
		left: function( position, data ) {
			var within = data.within,
				withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
				outerWidth = within.width,
				collisionPosLeft = position.left - data.collisionPosition.marginLeft,
				overLeft = withinOffset - collisionPosLeft,
				overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
				newOverRight;

			// Element is wider than within
			if ( data.collisionWidth > outerWidth ) {

				// Element is initially over the left side of within
				if ( overLeft > 0 && overRight <= 0 ) {
					newOverRight = position.left + overLeft + data.collisionWidth - outerWidth -
						withinOffset;
					position.left += overLeft - newOverRight;

				// Element is initially over right side of within
				} else if ( overRight > 0 && overLeft <= 0 ) {
					position.left = withinOffset;

				// Element is initially over both left and right sides of within
				} else {
					if ( overLeft > overRight ) {
						position.left = withinOffset + outerWidth - data.collisionWidth;
					} else {
						position.left = withinOffset;
					}
				}

			// Too far left -> align with left edge
			} else if ( overLeft > 0 ) {
				position.left += overLeft;

			// Too far right -> align with right edge
			} else if ( overRight > 0 ) {
				position.left -= overRight;

			// Adjust based on position and margin
			} else {
				position.left = max( position.left - collisionPosLeft, position.left );
			}
		},
		top: function( position, data ) {
			var within = data.within,
				withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
				outerHeight = data.within.height,
				collisionPosTop = position.top - data.collisionPosition.marginTop,
				overTop = withinOffset - collisionPosTop,
				overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
				newOverBottom;

			// Element is taller than within
			if ( data.collisionHeight > outerHeight ) {

				// Element is initially over the top of within
				if ( overTop > 0 && overBottom <= 0 ) {
					newOverBottom = position.top + overTop + data.collisionHeight - outerHeight -
						withinOffset;
					position.top += overTop - newOverBottom;

				// Element is initially over bottom of within
				} else if ( overBottom > 0 && overTop <= 0 ) {
					position.top = withinOffset;

				// Element is initially over both top and bottom of within
				} else {
					if ( overTop > overBottom ) {
						position.top = withinOffset + outerHeight - data.collisionHeight;
					} else {
						position.top = withinOffset;
					}
				}

			// Too far up -> align with top
			} else if ( overTop > 0 ) {
				position.top += overTop;

			// Too far down -> align with bottom edge
			} else if ( overBottom > 0 ) {
				position.top -= overBottom;

			// Adjust based on position and margin
			} else {
				position.top = max( position.top - collisionPosTop, position.top );
			}
		}
	},
	flip: {
		left: function( position, data ) {
			var within = data.within,
				withinOffset = within.offset.left + within.scrollLeft,
				outerWidth = within.width,
				offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
				collisionPosLeft = position.left - data.collisionPosition.marginLeft,
				overLeft = collisionPosLeft - offsetLeft,
				overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
				myOffset = data.my[ 0 ] === "left" ?
					-data.elemWidth :
					data.my[ 0 ] === "right" ?
						data.elemWidth :
						0,
				atOffset = data.at[ 0 ] === "left" ?
					data.targetWidth :
					data.at[ 0 ] === "right" ?
						-data.targetWidth :
						0,
				offset = -2 * data.offset[ 0 ],
				newOverRight,
				newOverLeft;

			if ( overLeft < 0 ) {
				newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth -
					outerWidth - withinOffset;
				if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
					position.left += myOffset + atOffset + offset;
				}
			} else if ( overRight > 0 ) {
				newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset +
					atOffset + offset - offsetLeft;
				if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
					position.left += myOffset + atOffset + offset;
				}
			}
		},
		top: function( position, data ) {
			var within = data.within,
				withinOffset = within.offset.top + within.scrollTop,
				outerHeight = within.height,
				offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
				collisionPosTop = position.top - data.collisionPosition.marginTop,
				overTop = collisionPosTop - offsetTop,
				overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
				top = data.my[ 1 ] === "top",
				myOffset = top ?
					-data.elemHeight :
					data.my[ 1 ] === "bottom" ?
						data.elemHeight :
						0,
				atOffset = data.at[ 1 ] === "top" ?
					data.targetHeight :
					data.at[ 1 ] === "bottom" ?
						-data.targetHeight :
						0,
				offset = -2 * data.offset[ 1 ],
				newOverTop,
				newOverBottom;
			if ( overTop < 0 ) {
				newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight -
					outerHeight - withinOffset;
				if ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) {
					position.top += myOffset + atOffset + offset;
				}
			} else if ( overBottom > 0 ) {
				newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset +
					offset - offsetTop;
				if ( newOverTop > 0 || abs( newOverTop ) < overBottom ) {
					position.top += myOffset + atOffset + offset;
				}
			}
		}
	},
	flipfit: {
		left: function() {
			$.ui.position.flip.left.apply( this, arguments );
			$.ui.position.fit.left.apply( this, arguments );
		},
		top: function() {
			$.ui.position.flip.top.apply( this, arguments );
			$.ui.position.fit.top.apply( this, arguments );
		}
	}
};

} )();

var position = $.ui.position;


/*!
 * jQuery UI :data 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: :data Selector
//>>group: Core
//>>description: Selects elements which have data stored under the specified key.
//>>docs: http://api.jqueryui.com/data-selector/


var data = $.extend( $.expr.pseudos, {
	data: $.expr.createPseudo ?
		$.expr.createPseudo( function( dataName ) {
			return function( elem ) {
				return !!$.data( elem, dataName );
			};
		} ) :

		// Support: jQuery <1.8
		function( elem, i, match ) {
			return !!$.data( elem, match[ 3 ] );
		}
} );

/*!
 * jQuery UI Disable Selection 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: disableSelection
//>>group: Core
//>>description: Disable selection of text content within the set of matched elements.
//>>docs: http://api.jqueryui.com/disableSelection/

// This file is deprecated

var disableSelection = $.fn.extend( {
	disableSelection: ( function() {
		var eventType = "onselectstart" in document.createElement( "div" ) ?
			"selectstart" :
			"mousedown";

		return function() {
			return this.on( eventType + ".ui-disableSelection", function( event ) {
				event.preventDefault();
			} );
		};
	} )(),

	enableSelection: function() {
		return this.off( ".ui-disableSelection" );
	}
} );



// Create a local jQuery because jQuery Color relies on it and the
// global may not exist with AMD and a custom build (#10199).
// This module is a noop if used as a regular AMD module.
// eslint-disable-next-line no-unused-vars
var jQuery = $;


/*!
 * jQuery Color Animations v2.2.0
 * https://github.com/jquery/jquery-color
 *
 * Copyright OpenJS Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 *
 * Date: Sun May 10 09:02:36 2020 +0200
 */



	var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor " +
		"borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",

	class2type = {},
	toString = class2type.toString,

	// plusequals test for += 100 -= 100
	rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,

	// a set of RE's that can match strings and generate color tuples.
	stringParsers = [ {
			re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
			parse: function( execResult ) {
				return [
					execResult[ 1 ],
					execResult[ 2 ],
					execResult[ 3 ],
					execResult[ 4 ]
				];
			}
		}, {
			re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
			parse: function( execResult ) {
				return [
					execResult[ 1 ] * 2.55,
					execResult[ 2 ] * 2.55,
					execResult[ 3 ] * 2.55,
					execResult[ 4 ]
				];
			}
		}, {

			// this regex ignores A-F because it's compared against an already lowercased string
			re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})?/,
			parse: function( execResult ) {
				return [
					parseInt( execResult[ 1 ], 16 ),
					parseInt( execResult[ 2 ], 16 ),
					parseInt( execResult[ 3 ], 16 ),
					execResult[ 4 ] ?
						( parseInt( execResult[ 4 ], 16 ) / 255 ).toFixed( 2 ) :
						1
				];
			}
		}, {

			// this regex ignores A-F because it's compared against an already lowercased string
			re: /#([a-f0-9])([a-f0-9])([a-f0-9])([a-f0-9])?/,
			parse: function( execResult ) {
				return [
					parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),
					parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),
					parseInt( execResult[ 3 ] + execResult[ 3 ], 16 ),
					execResult[ 4 ] ?
						( parseInt( execResult[ 4 ] + execResult[ 4 ], 16 ) / 255 )
							.toFixed( 2 ) :
						1
				];
			}
		}, {
			re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
			space: "hsla",
			parse: function( execResult ) {
				return [
					execResult[ 1 ],
					execResult[ 2 ] / 100,
					execResult[ 3 ] / 100,
					execResult[ 4 ]
				];
			}
		} ],

	// jQuery.Color( )
	color = jQuery.Color = function( color, green, blue, alpha ) {
		return new jQuery.Color.fn.parse( color, green, blue, alpha );
	},
	spaces = {
		rgba: {
			props: {
				red: {
					idx: 0,
					type: "byte"
				},
				green: {
					idx: 1,
					type: "byte"
				},
				blue: {
					idx: 2,
					type: "byte"
				}
			}
		},

		hsla: {
			props: {
				hue: {
					idx: 0,
					type: "degrees"
				},
				saturation: {
					idx: 1,
					type: "percent"
				},
				lightness: {
					idx: 2,
					type: "percent"
				}
			}
		}
	},
	propTypes = {
		"byte": {
			floor: true,
			max: 255
		},
		"percent": {
			max: 1
		},
		"degrees": {
			mod: 360,
			floor: true
		}
	},
	support = color.support = {},

	// element for support tests
	supportElem = jQuery( "<p>" )[ 0 ],

	// colors = jQuery.Color.names
	colors,

	// local aliases of functions called often
	each = jQuery.each;

// determine rgba support immediately
supportElem.style.cssText = "background-color:rgba(1,1,1,.5)";
support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1;

// define cache name and alpha properties
// for rgba and hsla spaces
each( spaces, function( spaceName, space ) {
	space.cache = "_" + spaceName;
	space.props.alpha = {
		idx: 3,
		type: "percent",
		def: 1
	};
} );

// Populate the class2type map
jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ),
	function( _i, name ) {
		class2type[ "[object " + name + "]" ] = name.toLowerCase();
	} );

function getType( obj ) {
	if ( obj == null ) {
		return obj + "";
	}

	return typeof obj === "object" ?
		class2type[ toString.call( obj ) ] || "object" :
		typeof obj;
}

function clamp( value, prop, allowEmpty ) {
	var type = propTypes[ prop.type ] || {};

	if ( value == null ) {
		return ( allowEmpty || !prop.def ) ? null : prop.def;
	}

	// ~~ is an short way of doing floor for positive numbers
	value = type.floor ? ~~value : parseFloat( value );

	// IE will pass in empty strings as value for alpha,
	// which will hit this case
	if ( isNaN( value ) ) {
		return prop.def;
	}

	if ( type.mod ) {

		// we add mod before modding to make sure that negatives values
		// get converted properly: -10 -> 350
		return ( value + type.mod ) % type.mod;
	}

	// for now all property types without mod have min and max
	return Math.min( type.max, Math.max( 0, value ) );
}

function stringParse( string ) {
	var inst = color(),
		rgba = inst._rgba = [];

	string = string.toLowerCase();

	each( stringParsers, function( _i, parser ) {
		var parsed,
			match = parser.re.exec( string ),
			values = match && parser.parse( match ),
			spaceName = parser.space || "rgba";

		if ( values ) {
			parsed = inst[ spaceName ]( values );

			// if this was an rgba parse the assignment might happen twice
			// oh well....
			inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ];
			rgba = inst._rgba = parsed._rgba;

			// exit each( stringParsers ) here because we matched
			return false;
		}
	} );

	// Found a stringParser that handled it
	if ( rgba.length ) {

		// if this came from a parsed string, force "transparent" when alpha is 0
		// chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
		if ( rgba.join() === "0,0,0,0" ) {
			jQuery.extend( rgba, colors.transparent );
		}
		return inst;
	}

	// named colors
	return colors[ string ];
}

color.fn = jQuery.extend( color.prototype, {
	parse: function( red, green, blue, alpha ) {
		if ( red === undefined ) {
			this._rgba = [ null, null, null, null ];
			return this;
		}
		if ( red.jquery || red.nodeType ) {
			red = jQuery( red ).css( green );
			green = undefined;
		}

		var inst = this,
			type = getType( red ),
			rgba = this._rgba = [];

		// more than 1 argument specified - assume ( red, green, blue, alpha )
		if ( green !== undefined ) {
			red = [ red, green, blue, alpha ];
			type = "array";
		}

		if ( type === "string" ) {
			return this.parse( stringParse( red ) || colors._default );
		}

		if ( type === "array" ) {
			each( spaces.rgba.props, function( _key, prop ) {
				rgba[ prop.idx ] = clamp( red[ prop.idx ], prop );
			} );
			return this;
		}

		if ( type === "object" ) {
			if ( red instanceof color ) {
				each( spaces, function( _spaceName, space ) {
					if ( red[ space.cache ] ) {
						inst[ space.cache ] = red[ space.cache ].slice();
					}
				} );
			} else {
				each( spaces, function( _spaceName, space ) {
					var cache = space.cache;
					each( space.props, function( key, prop ) {

						// if the cache doesn't exist, and we know how to convert
						if ( !inst[ cache ] && space.to ) {

							// if the value was null, we don't need to copy it
							// if the key was alpha, we don't need to copy it either
							if ( key === "alpha" || red[ key ] == null ) {
								return;
							}
							inst[ cache ] = space.to( inst._rgba );
						}

						// this is the only case where we allow nulls for ALL properties.
						// call clamp with alwaysAllowEmpty
						inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );
					} );

					// everything defined but alpha?
					if ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) {

						// use the default of 1
						if ( inst[ cache ][ 3 ] == null ) {
							inst[ cache ][ 3 ] = 1;
						}

						if ( space.from ) {
							inst._rgba = space.from( inst[ cache ] );
						}
					}
				} );
			}
			return this;
		}
	},
	is: function( compare ) {
		var is = color( compare ),
			same = true,
			inst = this;

		each( spaces, function( _, space ) {
			var localCache,
				isCache = is[ space.cache ];
			if ( isCache ) {
				localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || [];
				each( space.props, function( _, prop ) {
					if ( isCache[ prop.idx ] != null ) {
						same = ( isCache[ prop.idx ] === localCache[ prop.idx ] );
						return same;
					}
				} );
			}
			return same;
		} );
		return same;
	},
	_space: function() {
		var used = [],
			inst = this;
		each( spaces, function( spaceName, space ) {
			if ( inst[ space.cache ] ) {
				used.push( spaceName );
			}
		} );
		return used.pop();
	},
	transition: function( other, distance ) {
		var end = color( other ),
			spaceName = end._space(),
			space = spaces[ spaceName ],
			startColor = this.alpha() === 0 ? color( "transparent" ) : this,
			start = startColor[ space.cache ] || space.to( startColor._rgba ),
			result = start.slice();

		end = end[ space.cache ];
		each( space.props, function( _key, prop ) {
			var index = prop.idx,
				startValue = start[ index ],
				endValue = end[ index ],
				type = propTypes[ prop.type ] || {};

			// if null, don't override start value
			if ( endValue === null ) {
				return;
			}

			// if null - use end
			if ( startValue === null ) {
				result[ index ] = endValue;
			} else {
				if ( type.mod ) {
					if ( endValue - startValue > type.mod / 2 ) {
						startValue += type.mod;
					} else if ( startValue - endValue > type.mod / 2 ) {
						startValue -= type.mod;
					}
				}
				result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop );
			}
		} );
		return this[ spaceName ]( result );
	},
	blend: function( opaque ) {

		// if we are already opaque - return ourself
		if ( this._rgba[ 3 ] === 1 ) {
			return this;
		}

		var rgb = this._rgba.slice(),
			a = rgb.pop(),
			blend = color( opaque )._rgba;

		return color( jQuery.map( rgb, function( v, i ) {
			return ( 1 - a ) * blend[ i ] + a * v;
		} ) );
	},
	toRgbaString: function() {
		var prefix = "rgba(",
			rgba = jQuery.map( this._rgba, function( v, i ) {
				if ( v != null ) {
					return v;
				}
				return i > 2 ? 1 : 0;
			} );

		if ( rgba[ 3 ] === 1 ) {
			rgba.pop();
			prefix = "rgb(";
		}

		return prefix + rgba.join() + ")";
	},
	toHslaString: function() {
		var prefix = "hsla(",
			hsla = jQuery.map( this.hsla(), function( v, i ) {
				if ( v == null ) {
					v = i > 2 ? 1 : 0;
				}

				// catch 1 and 2
				if ( i && i < 3 ) {
					v = Math.round( v * 100 ) + "%";
				}
				return v;
			} );

		if ( hsla[ 3 ] === 1 ) {
			hsla.pop();
			prefix = "hsl(";
		}
		return prefix + hsla.join() + ")";
	},
	toHexString: function( includeAlpha ) {
		var rgba = this._rgba.slice(),
			alpha = rgba.pop();

		if ( includeAlpha ) {
			rgba.push( ~~( alpha * 255 ) );
		}

		return "#" + jQuery.map( rgba, function( v ) {

			// default to 0 when nulls exist
			v = ( v || 0 ).toString( 16 );
			return v.length === 1 ? "0" + v : v;
		} ).join( "" );
	},
	toString: function() {
		return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString();
	}
} );
color.fn.parse.prototype = color.fn;

// hsla conversions adapted from:
// https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021

function hue2rgb( p, q, h ) {
	h = ( h + 1 ) % 1;
	if ( h * 6 < 1 ) {
		return p + ( q - p ) * h * 6;
	}
	if ( h * 2 < 1 ) {
		return q;
	}
	if ( h * 3 < 2 ) {
		return p + ( q - p ) * ( ( 2 / 3 ) - h ) * 6;
	}
	return p;
}

spaces.hsla.to = function( rgba ) {
	if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {
		return [ null, null, null, rgba[ 3 ] ];
	}
	var r = rgba[ 0 ] / 255,
		g = rgba[ 1 ] / 255,
		b = rgba[ 2 ] / 255,
		a = rgba[ 3 ],
		max = Math.max( r, g, b ),
		min = Math.min( r, g, b ),
		diff = max - min,
		add = max + min,
		l = add * 0.5,
		h, s;

	if ( min === max ) {
		h = 0;
	} else if ( r === max ) {
		h = ( 60 * ( g - b ) / diff ) + 360;
	} else if ( g === max ) {
		h = ( 60 * ( b - r ) / diff ) + 120;
	} else {
		h = ( 60 * ( r - g ) / diff ) + 240;
	}

	// chroma (diff) == 0 means greyscale which, by definition, saturation = 0%
	// otherwise, saturation is based on the ratio of chroma (diff) to lightness (add)
	if ( diff === 0 ) {
		s = 0;
	} else if ( l <= 0.5 ) {
		s = diff / add;
	} else {
		s = diff / ( 2 - add );
	}
	return [ Math.round( h ) % 360, s, l, a == null ? 1 : a ];
};

spaces.hsla.from = function( hsla ) {
	if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {
		return [ null, null, null, hsla[ 3 ] ];
	}
	var h = hsla[ 0 ] / 360,
		s = hsla[ 1 ],
		l = hsla[ 2 ],
		a = hsla[ 3 ],
		q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
		p = 2 * l - q;

	return [
		Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
		Math.round( hue2rgb( p, q, h ) * 255 ),
		Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
		a
	];
};


each( spaces, function( spaceName, space ) {
	var props = space.props,
		cache = space.cache,
		to = space.to,
		from = space.from;

	// makes rgba() and hsla()
	color.fn[ spaceName ] = function( value ) {

		// generate a cache for this space if it doesn't exist
		if ( to && !this[ cache ] ) {
			this[ cache ] = to( this._rgba );
		}
		if ( value === undefined ) {
			return this[ cache ].slice();
		}

		var ret,
			type = getType( value ),
			arr = ( type === "array" || type === "object" ) ? value : arguments,
			local = this[ cache ].slice();

		each( props, function( key, prop ) {
			var val = arr[ type === "object" ? key : prop.idx ];
			if ( val == null ) {
				val = local[ prop.idx ];
			}
			local[ prop.idx ] = clamp( val, prop );
		} );

		if ( from ) {
			ret = color( from( local ) );
			ret[ cache ] = local;
			return ret;
		} else {
			return color( local );
		}
	};

	// makes red() green() blue() alpha() hue() saturation() lightness()
	each( props, function( key, prop ) {

		// alpha is included in more than one space
		if ( color.fn[ key ] ) {
			return;
		}
		color.fn[ key ] = function( value ) {
			var local, cur, match, fn,
				vtype = getType( value );

			if ( key === "alpha" ) {
				fn = this._hsla ? "hsla" : "rgba";
			} else {
				fn = spaceName;
			}
			local = this[ fn ]();
			cur = local[ prop.idx ];

			if ( vtype === "undefined" ) {
				return cur;
			}

			if ( vtype === "function" ) {
				value = value.call( this, cur );
				vtype = getType( value );
			}
			if ( value == null && prop.empty ) {
				return this;
			}
			if ( vtype === "string" ) {
				match = rplusequals.exec( value );
				if ( match ) {
					value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 );
				}
			}
			local[ prop.idx ] = value;
			return this[ fn ]( local );
		};
	} );
} );

// add cssHook and .fx.step function for each named hook.
// accept a space separated string of properties
color.hook = function( hook ) {
	var hooks = hook.split( " " );
	each( hooks, function( _i, hook ) {
		jQuery.cssHooks[ hook ] = {
			set: function( elem, value ) {
				var parsed, curElem,
					backgroundColor = "";

				if ( value !== "transparent" && ( getType( value ) !== "string" || ( parsed = stringParse( value ) ) ) ) {
					value = color( parsed || value );
					if ( !support.rgba && value._rgba[ 3 ] !== 1 ) {
						curElem = hook === "backgroundColor" ? elem.parentNode : elem;
						while (
							( backgroundColor === "" || backgroundColor === "transparent" ) &&
							curElem && curElem.style
						) {
							try {
								backgroundColor = jQuery.css( curElem, "backgroundColor" );
								curElem = curElem.parentNode;
							} catch ( e ) {
							}
						}

						value = value.blend( backgroundColor && backgroundColor !== "transparent" ?
							backgroundColor :
							"_default" );
					}

					value = value.toRgbaString();
				}
				try {
					elem.style[ hook ] = value;
				} catch ( e ) {

					// wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit'
				}
			}
		};
		jQuery.fx.step[ hook ] = function( fx ) {
			if ( !fx.colorInit ) {
				fx.start = color( fx.elem, hook );
				fx.end = color( fx.end );
				fx.colorInit = true;
			}
			jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );
		};
	} );

};

color.hook( stepHooks );

jQuery.cssHooks.borderColor = {
	expand: function( value ) {
		var expanded = {};

		each( [ "Top", "Right", "Bottom", "Left" ], function( _i, part ) {
			expanded[ "border" + part + "Color" ] = value;
		} );
		return expanded;
	}
};

// Basic color names only.
// Usage of any of the other color names requires adding yourself or including
// jquery.color.svg-names.js.
colors = jQuery.Color.names = {

	// 4.1. Basic color keywords
	aqua: "#00ffff",
	black: "#000000",
	blue: "#0000ff",
	fuchsia: "#ff00ff",
	gray: "#808080",
	green: "#008000",
	lime: "#00ff00",
	maroon: "#800000",
	navy: "#000080",
	olive: "#808000",
	purple: "#800080",
	red: "#ff0000",
	silver: "#c0c0c0",
	teal: "#008080",
	white: "#ffffff",
	yellow: "#ffff00",

	// 4.2.3. "transparent" color keyword
	transparent: [ null, null, null, 0 ],

	_default: "#ffffff"
};


/*!
 * jQuery UI Effects 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Effects Core
//>>group: Effects
/* eslint-disable max-len */
//>>description: Extends the internal jQuery effects. Includes morphing and easing. Required by all other effects.
/* eslint-enable max-len */
//>>docs: http://api.jqueryui.com/category/effects-core/
//>>demos: http://jqueryui.com/effect/


var dataSpace = "ui-effects-",
	dataSpaceStyle = "ui-effects-style",
	dataSpaceAnimated = "ui-effects-animated";

$.effects = {
	effect: {}
};

/******************************************************************************/
/****************************** CLASS ANIMATIONS ******************************/
/******************************************************************************/
( function() {

var classAnimationActions = [ "add", "remove", "toggle" ],
	shorthandStyles = {
		border: 1,
		borderBottom: 1,
		borderColor: 1,
		borderLeft: 1,
		borderRight: 1,
		borderTop: 1,
		borderWidth: 1,
		margin: 1,
		padding: 1
	};

$.each(
	[ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ],
	function( _, prop ) {
		$.fx.step[ prop ] = function( fx ) {
			if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) {
				jQuery.style( fx.elem, prop, fx.end );
				fx.setAttr = true;
			}
		};
	}
);

function camelCase( string ) {
	return string.replace( /-([\da-z])/gi, function( all, letter ) {
		return letter.toUpperCase();
	} );
}

function getElementStyles( elem ) {
	var key, len,
		style = elem.ownerDocument.defaultView ?
			elem.ownerDocument.defaultView.getComputedStyle( elem, null ) :
			elem.currentStyle,
		styles = {};

	if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) {
		len = style.length;
		while ( len-- ) {
			key = style[ len ];
			if ( typeof style[ key ] === "string" ) {
				styles[ camelCase( key ) ] = style[ key ];
			}
		}

	// Support: Opera, IE <9
	} else {
		for ( key in style ) {
			if ( typeof style[ key ] === "string" ) {
				styles[ key ] = style[ key ];
			}
		}
	}

	return styles;
}

function styleDifference( oldStyle, newStyle ) {
	var diff = {},
		name, value;

	for ( name in newStyle ) {
		value = newStyle[ name ];
		if ( oldStyle[ name ] !== value ) {
			if ( !shorthandStyles[ name ] ) {
				if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) {
					diff[ name ] = value;
				}
			}
		}
	}

	return diff;
}

// Support: jQuery <1.8
if ( !$.fn.addBack ) {
	$.fn.addBack = function( selector ) {
		return this.add( selector == null ?
			this.prevObject : this.prevObject.filter( selector )
		);
	};
}

$.effects.animateClass = function( value, duration, easing, callback ) {
	var o = $.speed( duration, easing, callback );

	return this.queue( function() {
		var animated = $( this ),
			baseClass = animated.attr( "class" ) || "",
			applyClassChange,
			allAnimations = o.children ? animated.find( "*" ).addBack() : animated;

		// Map the animated objects to store the original styles.
		allAnimations = allAnimations.map( function() {
			var el = $( this );
			return {
				el: el,
				start: getElementStyles( this )
			};
		} );

		// Apply class change
		applyClassChange = function() {
			$.each( classAnimationActions, function( i, action ) {
				if ( value[ action ] ) {
					animated[ action + "Class" ]( value[ action ] );
				}
			} );
		};
		applyClassChange();

		// Map all animated objects again - calculate new styles and diff
		allAnimations = allAnimations.map( function() {
			this.end = getElementStyles( this.el[ 0 ] );
			this.diff = styleDifference( this.start, this.end );
			return this;
		} );

		// Apply original class
		animated.attr( "class", baseClass );

		// Map all animated objects again - this time collecting a promise
		allAnimations = allAnimations.map( function() {
			var styleInfo = this,
				dfd = $.Deferred(),
				opts = $.extend( {}, o, {
					queue: false,
					complete: function() {
						dfd.resolve( styleInfo );
					}
				} );

			this.el.animate( this.diff, opts );
			return dfd.promise();
		} );

		// Once all animations have completed:
		$.when.apply( $, allAnimations.get() ).done( function() {

			// Set the final class
			applyClassChange();

			// For each animated element,
			// clear all css properties that were animated
			$.each( arguments, function() {
				var el = this.el;
				$.each( this.diff, function( key ) {
					el.css( key, "" );
				} );
			} );

			// This is guarnteed to be there if you use jQuery.speed()
			// it also handles dequeuing the next anim...
			o.complete.call( animated[ 0 ] );
		} );
	} );
};

$.fn.extend( {
	addClass: ( function( orig ) {
		return function( classNames, speed, easing, callback ) {
			return speed ?
				$.effects.animateClass.call( this,
					{ add: classNames }, speed, easing, callback ) :
				orig.apply( this, arguments );
		};
	} )( $.fn.addClass ),

	removeClass: ( function( orig ) {
		return function( classNames, speed, easing, callback ) {
			return arguments.length > 1 ?
				$.effects.animateClass.call( this,
					{ remove: classNames }, speed, easing, callback ) :
				orig.apply( this, arguments );
		};
	} )( $.fn.removeClass ),

	toggleClass: ( function( orig ) {
		return function( classNames, force, speed, easing, callback ) {
			if ( typeof force === "boolean" || force === undefined ) {
				if ( !speed ) {

					// Without speed parameter
					return orig.apply( this, arguments );
				} else {
					return $.effects.animateClass.call( this,
						( force ? { add: classNames } : { remove: classNames } ),
						speed, easing, callback );
				}
			} else {

				// Without force parameter
				return $.effects.animateClass.call( this,
					{ toggle: classNames }, force, speed, easing );
			}
		};
	} )( $.fn.toggleClass ),

	switchClass: function( remove, add, speed, easing, callback ) {
		return $.effects.animateClass.call( this, {
			add: add,
			remove: remove
		}, speed, easing, callback );
	}
} );

} )();

/******************************************************************************/
/*********************************** EFFECTS **********************************/
/******************************************************************************/

( function() {

if ( $.expr && $.expr.pseudos && $.expr.pseudos.animated ) {
	$.expr.pseudos.animated = ( function( orig ) {
		return function( elem ) {
			return !!$( elem ).data( dataSpaceAnimated ) || orig( elem );
		};
	} )( $.expr.pseudos.animated );
}

if ( $.uiBackCompat !== false ) {
	$.extend( $.effects, {

		// Saves a set of properties in a data storage
		save: function( element, set ) {
			var i = 0, length = set.length;
			for ( ; i < length; i++ ) {
				if ( set[ i ] !== null ) {
					element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] );
				}
			}
		},

		// Restores a set of previously saved properties from a data storage
		restore: function( element, set ) {
			var val, i = 0, length = set.length;
			for ( ; i < length; i++ ) {
				if ( set[ i ] !== null ) {
					val = element.data( dataSpace + set[ i ] );
					element.css( set[ i ], val );
				}
			}
		},

		setMode: function( el, mode ) {
			if ( mode === "toggle" ) {
				mode = el.is( ":hidden" ) ? "show" : "hide";
			}
			return mode;
		},

		// Wraps the element around a wrapper that copies position properties
		createWrapper: function( element ) {

			// If the element is already wrapped, return it
			if ( element.parent().is( ".ui-effects-wrapper" ) ) {
				return element.parent();
			}

			// Wrap the element
			var props = {
					width: element.outerWidth( true ),
					height: element.outerHeight( true ),
					"float": element.css( "float" )
				},
				wrapper = $( "<div></div>" )
					.addClass( "ui-effects-wrapper" )
					.css( {
						fontSize: "100%",
						background: "transparent",
						border: "none",
						margin: 0,
						padding: 0
					} ),

				// Store the size in case width/height are defined in % - Fixes #5245
				size = {
					width: element.width(),
					height: element.height()
				},
				active = document.activeElement;

			// Support: Firefox
			// Firefox incorrectly exposes anonymous content
			// https://bugzilla.mozilla.org/show_bug.cgi?id=561664
			try {
				// eslint-disable-next-line no-unused-expressions
				active.id;
			} catch ( e ) {
				active = document.body;
			}

			element.wrap( wrapper );

			// Fixes #7595 - Elements lose focus when wrapped.
			if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
				$( active ).trigger( "focus" );
			}

			// Hotfix for jQuery 1.4 since some change in wrap() seems to actually
			// lose the reference to the wrapped element
			wrapper = element.parent();

			// Transfer positioning properties to the wrapper
			if ( element.css( "position" ) === "static" ) {
				wrapper.css( { position: "relative" } );
				element.css( { position: "relative" } );
			} else {
				$.extend( props, {
					position: element.css( "position" ),
					zIndex: element.css( "z-index" )
				} );
				$.each( [ "top", "left", "bottom", "right" ], function( i, pos ) {
					props[ pos ] = element.css( pos );
					if ( isNaN( parseInt( props[ pos ], 10 ) ) ) {
						props[ pos ] = "auto";
					}
				} );
				element.css( {
					position: "relative",
					top: 0,
					left: 0,
					right: "auto",
					bottom: "auto"
				} );
			}
			element.css( size );

			return wrapper.css( props ).show();
		},

		removeWrapper: function( element ) {
			var active = document.activeElement;

			if ( element.parent().is( ".ui-effects-wrapper" ) ) {
				element.parent().replaceWith( element );

				// Fixes #7595 - Elements lose focus when wrapped.
				if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
					$( active ).trigger( "focus" );
				}
			}

			return element;
		}
	} );
}

$.extend( $.effects, {
	version: "1.13.2",

	define: function( name, mode, effect ) {
		if ( !effect ) {
			effect = mode;
			mode = "effect";
		}

		$.effects.effect[ name ] = effect;
		$.effects.effect[ name ].mode = mode;

		return effect;
	},

	scaledDimensions: function( element, percent, direction ) {
		if ( percent === 0 ) {
			return {
				height: 0,
				width: 0,
				outerHeight: 0,
				outerWidth: 0
			};
		}

		var x = direction !== "horizontal" ? ( ( percent || 100 ) / 100 ) : 1,
			y = direction !== "vertical" ? ( ( percent || 100 ) / 100 ) : 1;

		return {
			height: element.height() * y,
			width: element.width() * x,
			outerHeight: element.outerHeight() * y,
			outerWidth: element.outerWidth() * x
		};

	},

	clipToBox: function( animation ) {
		return {
			width: animation.clip.right - animation.clip.left,
			height: animation.clip.bottom - animation.clip.top,
			left: animation.clip.left,
			top: animation.clip.top
		};
	},

	// Injects recently queued functions to be first in line (after "inprogress")
	unshift: function( element, queueLength, count ) {
		var queue = element.queue();

		if ( queueLength > 1 ) {
			queue.splice.apply( queue,
				[ 1, 0 ].concat( queue.splice( queueLength, count ) ) );
		}
		element.dequeue();
	},

	saveStyle: function( element ) {
		element.data( dataSpaceStyle, element[ 0 ].style.cssText );
	},

	restoreStyle: function( element ) {
		element[ 0 ].style.cssText = element.data( dataSpaceStyle ) || "";
		element.removeData( dataSpaceStyle );
	},

	mode: function( element, mode ) {
		var hidden = element.is( ":hidden" );

		if ( mode === "toggle" ) {
			mode = hidden ? "show" : "hide";
		}
		if ( hidden ? mode === "hide" : mode === "show" ) {
			mode = "none";
		}
		return mode;
	},

	// Translates a [top,left] array into a baseline value
	getBaseline: function( origin, original ) {
		var y, x;

		switch ( origin[ 0 ] ) {
		case "top":
			y = 0;
			break;
		case "middle":
			y = 0.5;
			break;
		case "bottom":
			y = 1;
			break;
		default:
			y = origin[ 0 ] / original.height;
		}

		switch ( origin[ 1 ] ) {
		case "left":
			x = 0;
			break;
		case "center":
			x = 0.5;
			break;
		case "right":
			x = 1;
			break;
		default:
			x = origin[ 1 ] / original.width;
		}

		return {
			x: x,
			y: y
		};
	},

	// Creates a placeholder element so that the original element can be made absolute
	createPlaceholder: function( element ) {
		var placeholder,
			cssPosition = element.css( "position" ),
			position = element.position();

		// Lock in margins first to account for form elements, which
		// will change margin if you explicitly set height
		// see: http://jsfiddle.net/JZSMt/3/ https://bugs.webkit.org/show_bug.cgi?id=107380
		// Support: Safari
		element.css( {
			marginTop: element.css( "marginTop" ),
			marginBottom: element.css( "marginBottom" ),
			marginLeft: element.css( "marginLeft" ),
			marginRight: element.css( "marginRight" )
		} )
		.outerWidth( element.outerWidth() )
		.outerHeight( element.outerHeight() );

		if ( /^(static|relative)/.test( cssPosition ) ) {
			cssPosition = "absolute";

			placeholder = $( "<" + element[ 0 ].nodeName + ">" ).insertAfter( element ).css( {

				// Convert inline to inline block to account for inline elements
				// that turn to inline block based on content (like img)
				display: /^(inline|ruby)/.test( element.css( "display" ) ) ?
					"inline-block" :
					"block",
				visibility: "hidden",

				// Margins need to be set to account for margin collapse
				marginTop: element.css( "marginTop" ),
				marginBottom: element.css( "marginBottom" ),
				marginLeft: element.css( "marginLeft" ),
				marginRight: element.css( "marginRight" ),
				"float": element.css( "float" )
			} )
			.outerWidth( element.outerWidth() )
			.outerHeight( element.outerHeight() )
			.addClass( "ui-effects-placeholder" );

			element.data( dataSpace + "placeholder", placeholder );
		}

		element.css( {
			position: cssPosition,
			left: position.left,
			top: position.top
		} );

		return placeholder;
	},

	removePlaceholder: function( element ) {
		var dataKey = dataSpace + "placeholder",
				placeholder = element.data( dataKey );

		if ( placeholder ) {
			placeholder.remove();
			element.removeData( dataKey );
		}
	},

	// Removes a placeholder if it exists and restores
	// properties that were modified during placeholder creation
	cleanUp: function( element ) {
		$.effects.restoreStyle( element );
		$.effects.removePlaceholder( element );
	},

	setTransition: function( element, list, factor, value ) {
		value = value || {};
		$.each( list, function( i, x ) {
			var unit = element.cssUnit( x );
			if ( unit[ 0 ] > 0 ) {
				value[ x ] = unit[ 0 ] * factor + unit[ 1 ];
			}
		} );
		return value;
	}
} );

// Return an effect options object for the given parameters:
function _normalizeArguments( effect, options, speed, callback ) {

	// Allow passing all options as the first parameter
	if ( $.isPlainObject( effect ) ) {
		options = effect;
		effect = effect.effect;
	}

	// Convert to an object
	effect = { effect: effect };

	// Catch (effect, null, ...)
	if ( options == null ) {
		options = {};
	}

	// Catch (effect, callback)
	if ( typeof options === "function" ) {
		callback = options;
		speed = null;
		options = {};
	}

	// Catch (effect, speed, ?)
	if ( typeof options === "number" || $.fx.speeds[ options ] ) {
		callback = speed;
		speed = options;
		options = {};
	}

	// Catch (effect, options, callback)
	if ( typeof speed === "function" ) {
		callback = speed;
		speed = null;
	}

	// Add options to effect
	if ( options ) {
		$.extend( effect, options );
	}

	speed = speed || options.duration;
	effect.duration = $.fx.off ? 0 :
		typeof speed === "number" ? speed :
		speed in $.fx.speeds ? $.fx.speeds[ speed ] :
		$.fx.speeds._default;

	effect.complete = callback || options.complete;

	return effect;
}

function standardAnimationOption( option ) {

	// Valid standard speeds (nothing, number, named speed)
	if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) {
		return true;
	}

	// Invalid strings - treat as "normal" speed
	if ( typeof option === "string" && !$.effects.effect[ option ] ) {
		return true;
	}

	// Complete callback
	if ( typeof option === "function" ) {
		return true;
	}

	// Options hash (but not naming an effect)
	if ( typeof option === "object" && !option.effect ) {
		return true;
	}

	// Didn't match any standard API
	return false;
}

$.fn.extend( {
	effect: function( /* effect, options, speed, callback */ ) {
		var args = _normalizeArguments.apply( this, arguments ),
			effectMethod = $.effects.effect[ args.effect ],
			defaultMode = effectMethod.mode,
			queue = args.queue,
			queueName = queue || "fx",
			complete = args.complete,
			mode = args.mode,
			modes = [],
			prefilter = function( next ) {
				var el = $( this ),
					normalizedMode = $.effects.mode( el, mode ) || defaultMode;

				// Sentinel for duck-punching the :animated pseudo-selector
				el.data( dataSpaceAnimated, true );

				// Save effect mode for later use,
				// we can't just call $.effects.mode again later,
				// as the .show() below destroys the initial state
				modes.push( normalizedMode );

				// See $.uiBackCompat inside of run() for removal of defaultMode in 1.14
				if ( defaultMode && ( normalizedMode === "show" ||
						( normalizedMode === defaultMode && normalizedMode === "hide" ) ) ) {
					el.show();
				}

				if ( !defaultMode || normalizedMode !== "none" ) {
					$.effects.saveStyle( el );
				}

				if ( typeof next === "function" ) {
					next();
				}
			};

		if ( $.fx.off || !effectMethod ) {

			// Delegate to the original method (e.g., .show()) if possible
			if ( mode ) {
				return this[ mode ]( args.duration, complete );
			} else {
				return this.each( function() {
					if ( complete ) {
						complete.call( this );
					}
				} );
			}
		}

		function run( next ) {
			var elem = $( this );

			function cleanup() {
				elem.removeData( dataSpaceAnimated );

				$.effects.cleanUp( elem );

				if ( args.mode === "hide" ) {
					elem.hide();
				}

				done();
			}

			function done() {
				if ( typeof complete === "function" ) {
					complete.call( elem[ 0 ] );
				}

				if ( typeof next === "function" ) {
					next();
				}
			}

			// Override mode option on a per element basis,
			// as toggle can be either show or hide depending on element state
			args.mode = modes.shift();

			if ( $.uiBackCompat !== false && !defaultMode ) {
				if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) {

					// Call the core method to track "olddisplay" properly
					elem[ mode ]();
					done();
				} else {
					effectMethod.call( elem[ 0 ], args, done );
				}
			} else {
				if ( args.mode === "none" ) {

					// Call the core method to track "olddisplay" properly
					elem[ mode ]();
					done();
				} else {
					effectMethod.call( elem[ 0 ], args, cleanup );
				}
			}
		}

		// Run prefilter on all elements first to ensure that
		// any showing or hiding happens before placeholder creation,
		// which ensures that any layout changes are correctly captured.
		return queue === false ?
			this.each( prefilter ).each( run ) :
			this.queue( queueName, prefilter ).queue( queueName, run );
	},

	show: ( function( orig ) {
		return function( option ) {
			if ( standardAnimationOption( option ) ) {
				return orig.apply( this, arguments );
			} else {
				var args = _normalizeArguments.apply( this, arguments );
				args.mode = "show";
				return this.effect.call( this, args );
			}
		};
	} )( $.fn.show ),

	hide: ( function( orig ) {
		return function( option ) {
			if ( standardAnimationOption( option ) ) {
				return orig.apply( this, arguments );
			} else {
				var args = _normalizeArguments.apply( this, arguments );
				args.mode = "hide";
				return this.effect.call( this, args );
			}
		};
	} )( $.fn.hide ),

	toggle: ( function( orig ) {
		return function( option ) {
			if ( standardAnimationOption( option ) || typeof option === "boolean" ) {
				return orig.apply( this, arguments );
			} else {
				var args = _normalizeArguments.apply( this, arguments );
				args.mode = "toggle";
				return this.effect.call( this, args );
			}
		};
	} )( $.fn.toggle ),

	cssUnit: function( key ) {
		var style = this.css( key ),
			val = [];

		$.each( [ "em", "px", "%", "pt" ], function( i, unit ) {
			if ( style.indexOf( unit ) > 0 ) {
				val = [ parseFloat( style ), unit ];
			}
		} );
		return val;
	},

	cssClip: function( clipObj ) {
		if ( clipObj ) {
			return this.css( "clip", "rect(" + clipObj.top + "px " + clipObj.right + "px " +
				clipObj.bottom + "px " + clipObj.left + "px)" );
		}
		return parseClip( this.css( "clip" ), this );
	},

	transfer: function( options, done ) {
		var element = $( this ),
			target = $( options.to ),
			targetFixed = target.css( "position" ) === "fixed",
			body = $( "body" ),
			fixTop = targetFixed ? body.scrollTop() : 0,
			fixLeft = targetFixed ? body.scrollLeft() : 0,
			endPosition = target.offset(),
			animation = {
				top: endPosition.top - fixTop,
				left: endPosition.left - fixLeft,
				height: target.innerHeight(),
				width: target.innerWidth()
			},
			startPosition = element.offset(),
			transfer = $( "<div class='ui-effects-transfer'></div>" );

		transfer
			.appendTo( "body" )
			.addClass( options.className )
			.css( {
				top: startPosition.top - fixTop,
				left: startPosition.left - fixLeft,
				height: element.innerHeight(),
				width: element.innerWidth(),
				position: targetFixed ? "fixed" : "absolute"
			} )
			.animate( animation, options.duration, options.easing, function() {
				transfer.remove();
				if ( typeof done === "function" ) {
					done();
				}
			} );
	}
} );

function parseClip( str, element ) {
		var outerWidth = element.outerWidth(),
			outerHeight = element.outerHeight(),
			clipRegex = /^rect\((-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto)\)$/,
			values = clipRegex.exec( str ) || [ "", 0, outerWidth, outerHeight, 0 ];

		return {
			top: parseFloat( values[ 1 ] ) || 0,
			right: values[ 2 ] === "auto" ? outerWidth : parseFloat( values[ 2 ] ),
			bottom: values[ 3 ] === "auto" ? outerHeight : parseFloat( values[ 3 ] ),
			left: parseFloat( values[ 4 ] ) || 0
		};
}

$.fx.step.clip = function( fx ) {
	if ( !fx.clipInit ) {
		fx.start = $( fx.elem ).cssClip();
		if ( typeof fx.end === "string" ) {
			fx.end = parseClip( fx.end, fx.elem );
		}
		fx.clipInit = true;
	}

	$( fx.elem ).cssClip( {
		top: fx.pos * ( fx.end.top - fx.start.top ) + fx.start.top,
		right: fx.pos * ( fx.end.right - fx.start.right ) + fx.start.right,
		bottom: fx.pos * ( fx.end.bottom - fx.start.bottom ) + fx.start.bottom,
		left: fx.pos * ( fx.end.left - fx.start.left ) + fx.start.left
	} );
};

} )();

/******************************************************************************/
/*********************************** EASING ***********************************/
/******************************************************************************/

( function() {

// Based on easing equations from Robert Penner (http://www.robertpenner.com/easing)

var baseEasings = {};

$.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) {
	baseEasings[ name ] = function( p ) {
		return Math.pow( p, i + 2 );
	};
} );

$.extend( baseEasings, {
	Sine: function( p ) {
		return 1 - Math.cos( p * Math.PI / 2 );
	},
	Circ: function( p ) {
		return 1 - Math.sqrt( 1 - p * p );
	},
	Elastic: function( p ) {
		return p === 0 || p === 1 ? p :
			-Math.pow( 2, 8 * ( p - 1 ) ) * Math.sin( ( ( p - 1 ) * 80 - 7.5 ) * Math.PI / 15 );
	},
	Back: function( p ) {
		return p * p * ( 3 * p - 2 );
	},
	Bounce: function( p ) {
		var pow2,
			bounce = 4;

		while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {}
		return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 );
	}
} );

$.each( baseEasings, function( name, easeIn ) {
	$.easing[ "easeIn" + name ] = easeIn;
	$.easing[ "easeOut" + name ] = function( p ) {
		return 1 - easeIn( 1 - p );
	};
	$.easing[ "easeInOut" + name ] = function( p ) {
		return p < 0.5 ?
			easeIn( p * 2 ) / 2 :
			1 - easeIn( p * -2 + 2 ) / 2;
	};
} );

} )();

var effect = $.effects;


/*!
 * jQuery UI Effects Blind 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Blind Effect
//>>group: Effects
//>>description: Blinds the element.
//>>docs: http://api.jqueryui.com/blind-effect/
//>>demos: http://jqueryui.com/effect/


var effectsEffectBlind = $.effects.define( "blind", "hide", function( options, done ) {
	var map = {
			up: [ "bottom", "top" ],
			vertical: [ "bottom", "top" ],
			down: [ "top", "bottom" ],
			left: [ "right", "left" ],
			horizontal: [ "right", "left" ],
			right: [ "left", "right" ]
		},
		element = $( this ),
		direction = options.direction || "up",
		start = element.cssClip(),
		animate = { clip: $.extend( {}, start ) },
		placeholder = $.effects.createPlaceholder( element );

	animate.clip[ map[ direction ][ 0 ] ] = animate.clip[ map[ direction ][ 1 ] ];

	if ( options.mode === "show" ) {
		element.cssClip( animate.clip );
		if ( placeholder ) {
			placeholder.css( $.effects.clipToBox( animate ) );
		}

		animate.clip = start;
	}

	if ( placeholder ) {
		placeholder.animate( $.effects.clipToBox( animate ), options.duration, options.easing );
	}

	element.animate( animate, {
		queue: false,
		duration: options.duration,
		easing: options.easing,
		complete: done
	} );
} );


/*!
 * jQuery UI Effects Bounce 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Bounce Effect
//>>group: Effects
//>>description: Bounces an element horizontally or vertically n times.
//>>docs: http://api.jqueryui.com/bounce-effect/
//>>demos: http://jqueryui.com/effect/


var effectsEffectBounce = $.effects.define( "bounce", function( options, done ) {
	var upAnim, downAnim, refValue,
		element = $( this ),

		// Defaults:
		mode = options.mode,
		hide = mode === "hide",
		show = mode === "show",
		direction = options.direction || "up",
		distance = options.distance,
		times = options.times || 5,

		// Number of internal animations
		anims = times * 2 + ( show || hide ? 1 : 0 ),
		speed = options.duration / anims,
		easing = options.easing,

		// Utility:
		ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
		motion = ( direction === "up" || direction === "left" ),
		i = 0,

		queuelen = element.queue().length;

	$.effects.createPlaceholder( element );

	refValue = element.css( ref );

	// Default distance for the BIGGEST bounce is the outer Distance / 3
	if ( !distance ) {
		distance = element[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3;
	}

	if ( show ) {
		downAnim = { opacity: 1 };
		downAnim[ ref ] = refValue;

		// If we are showing, force opacity 0 and set the initial position
		// then do the "first" animation
		element
			.css( "opacity", 0 )
			.css( ref, motion ? -distance * 2 : distance * 2 )
			.animate( downAnim, speed, easing );
	}

	// Start at the smallest distance if we are hiding
	if ( hide ) {
		distance = distance / Math.pow( 2, times - 1 );
	}

	downAnim = {};
	downAnim[ ref ] = refValue;

	// Bounces up/down/left/right then back to 0 -- times * 2 animations happen here
	for ( ; i < times; i++ ) {
		upAnim = {};
		upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;

		element
			.animate( upAnim, speed, easing )
			.animate( downAnim, speed, easing );

		distance = hide ? distance * 2 : distance / 2;
	}

	// Last Bounce when Hiding
	if ( hide ) {
		upAnim = { opacity: 0 };
		upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;

		element.animate( upAnim, speed, easing );
	}

	element.queue( done );

	$.effects.unshift( element, queuelen, anims + 1 );
} );


/*!
 * jQuery UI Effects Clip 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Clip Effect
//>>group: Effects
//>>description: Clips the element on and off like an old TV.
//>>docs: http://api.jqueryui.com/clip-effect/
//>>demos: http://jqueryui.com/effect/


var effectsEffectClip = $.effects.define( "clip", "hide", function( options, done ) {
	var start,
		animate = {},
		element = $( this ),
		direction = options.direction || "vertical",
		both = direction === "both",
		horizontal = both || direction === "horizontal",
		vertical = both || direction === "vertical";

	start = element.cssClip();
	animate.clip = {
		top: vertical ? ( start.bottom - start.top ) / 2 : start.top,
		right: horizontal ? ( start.right - start.left ) / 2 : start.right,
		bottom: vertical ? ( start.bottom - start.top ) / 2 : start.bottom,
		left: horizontal ? ( start.right - start.left ) / 2 : start.left
	};

	$.effects.createPlaceholder( element );

	if ( options.mode === "show" ) {
		element.cssClip( animate.clip );
		animate.clip = start;
	}

	element.animate( animate, {
		queue: false,
		duration: options.duration,
		easing: options.easing,
		complete: done
	} );

} );


/*!
 * jQuery UI Effects Drop 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Drop Effect
//>>group: Effects
//>>description: Moves an element in one direction and hides it at the same time.
//>>docs: http://api.jqueryui.com/drop-effect/
//>>demos: http://jqueryui.com/effect/


var effectsEffectDrop = $.effects.define( "drop", "hide", function( options, done ) {

	var distance,
		element = $( this ),
		mode = options.mode,
		show = mode === "show",
		direction = options.direction || "left",
		ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
		motion = ( direction === "up" || direction === "left" ) ? "-=" : "+=",
		oppositeMotion = ( motion === "+=" ) ? "-=" : "+=",
		animation = {
			opacity: 0
		};

	$.effects.createPlaceholder( element );

	distance = options.distance ||
		element[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ) / 2;

	animation[ ref ] = motion + distance;

	if ( show ) {
		element.css( animation );

		animation[ ref ] = oppositeMotion + distance;
		animation.opacity = 1;
	}

	// Animate
	element.animate( animation, {
		queue: false,
		duration: options.duration,
		easing: options.easing,
		complete: done
	} );
} );


/*!
 * jQuery UI Effects Explode 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Explode Effect
//>>group: Effects
/* eslint-disable max-len */
//>>description: Explodes an element in all directions into n pieces. Implodes an element to its original wholeness.
/* eslint-enable max-len */
//>>docs: http://api.jqueryui.com/explode-effect/
//>>demos: http://jqueryui.com/effect/


var effectsEffectExplode = $.effects.define( "explode", "hide", function( options, done ) {

	var i, j, left, top, mx, my,
		rows = options.pieces ? Math.round( Math.sqrt( options.pieces ) ) : 3,
		cells = rows,
		element = $( this ),
		mode = options.mode,
		show = mode === "show",

		// Show and then visibility:hidden the element before calculating offset
		offset = element.show().css( "visibility", "hidden" ).offset(),

		// Width and height of a piece
		width = Math.ceil( element.outerWidth() / cells ),
		height = Math.ceil( element.outerHeight() / rows ),
		pieces = [];

	// Children animate complete:
	function childComplete() {
		pieces.push( this );
		if ( pieces.length === rows * cells ) {
			animComplete();
		}
	}

	// Clone the element for each row and cell.
	for ( i = 0; i < rows; i++ ) { // ===>
		top = offset.top + i * height;
		my = i - ( rows - 1 ) / 2;

		for ( j = 0; j < cells; j++ ) { // |||
			left = offset.left + j * width;
			mx = j - ( cells - 1 ) / 2;

			// Create a clone of the now hidden main element that will be absolute positioned
			// within a wrapper div off the -left and -top equal to size of our pieces
			element
				.clone()
				.appendTo( "body" )
				.wrap( "<div></div>" )
				.css( {
					position: "absolute",
					visibility: "visible",
					left: -j * width,
					top: -i * height
				} )

				// Select the wrapper - make it overflow: hidden and absolute positioned based on
				// where the original was located +left and +top equal to the size of pieces
				.parent()
					.addClass( "ui-effects-explode" )
					.css( {
						position: "absolute",
						overflow: "hidden",
						width: width,
						height: height,
						left: left + ( show ? mx * width : 0 ),
						top: top + ( show ? my * height : 0 ),
						opacity: show ? 0 : 1
					} )
					.animate( {
						left: left + ( show ? 0 : mx * width ),
						top: top + ( show ? 0 : my * height ),
						opacity: show ? 1 : 0
					}, options.duration || 500, options.easing, childComplete );
		}
	}

	function animComplete() {
		element.css( {
			visibility: "visible"
		} );
		$( pieces ).remove();
		done();
	}
} );


/*!
 * jQuery UI Effects Fade 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Fade Effect
//>>group: Effects
//>>description: Fades the element.
//>>docs: http://api.jqueryui.com/fade-effect/
//>>demos: http://jqueryui.com/effect/


var effectsEffectFade = $.effects.define( "fade", "toggle", function( options, done ) {
	var show = options.mode === "show";

	$( this )
		.css( "opacity", show ? 0 : 1 )
		.animate( {
			opacity: show ? 1 : 0
		}, {
			queue: false,
			duration: options.duration,
			easing: options.easing,
			complete: done
		} );
} );


/*!
 * jQuery UI Effects Fold 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Fold Effect
//>>group: Effects
//>>description: Folds an element first horizontally and then vertically.
//>>docs: http://api.jqueryui.com/fold-effect/
//>>demos: http://jqueryui.com/effect/


var effectsEffectFold = $.effects.define( "fold", "hide", function( options, done ) {

	// Create element
	var element = $( this ),
		mode = options.mode,
		show = mode === "show",
		hide = mode === "hide",
		size = options.size || 15,
		percent = /([0-9]+)%/.exec( size ),
		horizFirst = !!options.horizFirst,
		ref = horizFirst ? [ "right", "bottom" ] : [ "bottom", "right" ],
		duration = options.duration / 2,

		placeholder = $.effects.createPlaceholder( element ),

		start = element.cssClip(),
		animation1 = { clip: $.extend( {}, start ) },
		animation2 = { clip: $.extend( {}, start ) },

		distance = [ start[ ref[ 0 ] ], start[ ref[ 1 ] ] ],

		queuelen = element.queue().length;

	if ( percent ) {
		size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ];
	}
	animation1.clip[ ref[ 0 ] ] = size;
	animation2.clip[ ref[ 0 ] ] = size;
	animation2.clip[ ref[ 1 ] ] = 0;

	if ( show ) {
		element.cssClip( animation2.clip );
		if ( placeholder ) {
			placeholder.css( $.effects.clipToBox( animation2 ) );
		}

		animation2.clip = start;
	}

	// Animate
	element
		.queue( function( next ) {
			if ( placeholder ) {
				placeholder
					.animate( $.effects.clipToBox( animation1 ), duration, options.easing )
					.animate( $.effects.clipToBox( animation2 ), duration, options.easing );
			}

			next();
		} )
		.animate( animation1, duration, options.easing )
		.animate( animation2, duration, options.easing )
		.queue( done );

	$.effects.unshift( element, queuelen, 4 );
} );


/*!
 * jQuery UI Effects Highlight 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Highlight Effect
//>>group: Effects
//>>description: Highlights the background of an element in a defined color for a custom duration.
//>>docs: http://api.jqueryui.com/highlight-effect/
//>>demos: http://jqueryui.com/effect/


var effectsEffectHighlight = $.effects.define( "highlight", "show", function( options, done ) {
	var element = $( this ),
		animation = {
			backgroundColor: element.css( "backgroundColor" )
		};

	if ( options.mode === "hide" ) {
		animation.opacity = 0;
	}

	$.effects.saveStyle( element );

	element
		.css( {
			backgroundImage: "none",
			backgroundColor: options.color || "#ffff99"
		} )
		.animate( animation, {
			queue: false,
			duration: options.duration,
			easing: options.easing,
			complete: done
		} );
} );


/*!
 * jQuery UI Effects Size 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Size Effect
//>>group: Effects
//>>description: Resize an element to a specified width and height.
//>>docs: http://api.jqueryui.com/size-effect/
//>>demos: http://jqueryui.com/effect/


var effectsEffectSize = $.effects.define( "size", function( options, done ) {

	// Create element
	var baseline, factor, temp,
		element = $( this ),

		// Copy for children
		cProps = [ "fontSize" ],
		vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ],
		hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ],

		// Set options
		mode = options.mode,
		restore = mode !== "effect",
		scale = options.scale || "both",
		origin = options.origin || [ "middle", "center" ],
		position = element.css( "position" ),
		pos = element.position(),
		original = $.effects.scaledDimensions( element ),
		from = options.from || original,
		to = options.to || $.effects.scaledDimensions( element, 0 );

	$.effects.createPlaceholder( element );

	if ( mode === "show" ) {
		temp = from;
		from = to;
		to = temp;
	}

	// Set scaling factor
	factor = {
		from: {
			y: from.height / original.height,
			x: from.width / original.width
		},
		to: {
			y: to.height / original.height,
			x: to.width / original.width
		}
	};

	// Scale the css box
	if ( scale === "box" || scale === "both" ) {

		// Vertical props scaling
		if ( factor.from.y !== factor.to.y ) {
			from = $.effects.setTransition( element, vProps, factor.from.y, from );
			to = $.effects.setTransition( element, vProps, factor.to.y, to );
		}

		// Horizontal props scaling
		if ( factor.from.x !== factor.to.x ) {
			from = $.effects.setTransition( element, hProps, factor.from.x, from );
			to = $.effects.setTransition( element, hProps, factor.to.x, to );
		}
	}

	// Scale the content
	if ( scale === "content" || scale === "both" ) {

		// Vertical props scaling
		if ( factor.from.y !== factor.to.y ) {
			from = $.effects.setTransition( element, cProps, factor.from.y, from );
			to = $.effects.setTransition( element, cProps, factor.to.y, to );
		}
	}

	// Adjust the position properties based on the provided origin points
	if ( origin ) {
		baseline = $.effects.getBaseline( origin, original );
		from.top = ( original.outerHeight - from.outerHeight ) * baseline.y + pos.top;
		from.left = ( original.outerWidth - from.outerWidth ) * baseline.x + pos.left;
		to.top = ( original.outerHeight - to.outerHeight ) * baseline.y + pos.top;
		to.left = ( original.outerWidth - to.outerWidth ) * baseline.x + pos.left;
	}
	delete from.outerHeight;
	delete from.outerWidth;
	element.css( from );

	// Animate the children if desired
	if ( scale === "content" || scale === "both" ) {

		vProps = vProps.concat( [ "marginTop", "marginBottom" ] ).concat( cProps );
		hProps = hProps.concat( [ "marginLeft", "marginRight" ] );

		// Only animate children with width attributes specified
		// TODO: is this right? should we include anything with css width specified as well
		element.find( "*[width]" ).each( function() {
			var child = $( this ),
				childOriginal = $.effects.scaledDimensions( child ),
				childFrom = {
					height: childOriginal.height * factor.from.y,
					width: childOriginal.width * factor.from.x,
					outerHeight: childOriginal.outerHeight * factor.from.y,
					outerWidth: childOriginal.outerWidth * factor.from.x
				},
				childTo = {
					height: childOriginal.height * factor.to.y,
					width: childOriginal.width * factor.to.x,
					outerHeight: childOriginal.height * factor.to.y,
					outerWidth: childOriginal.width * factor.to.x
				};

			// Vertical props scaling
			if ( factor.from.y !== factor.to.y ) {
				childFrom = $.effects.setTransition( child, vProps, factor.from.y, childFrom );
				childTo = $.effects.setTransition( child, vProps, factor.to.y, childTo );
			}

			// Horizontal props scaling
			if ( factor.from.x !== factor.to.x ) {
				childFrom = $.effects.setTransition( child, hProps, factor.from.x, childFrom );
				childTo = $.effects.setTransition( child, hProps, factor.to.x, childTo );
			}

			if ( restore ) {
				$.effects.saveStyle( child );
			}

			// Animate children
			child.css( childFrom );
			child.animate( childTo, options.duration, options.easing, function() {

				// Restore children
				if ( restore ) {
					$.effects.restoreStyle( child );
				}
			} );
		} );
	}

	// Animate
	element.animate( to, {
		queue: false,
		duration: options.duration,
		easing: options.easing,
		complete: function() {

			var offset = element.offset();

			if ( to.opacity === 0 ) {
				element.css( "opacity", from.opacity );
			}

			if ( !restore ) {
				element
					.css( "position", position === "static" ? "relative" : position )
					.offset( offset );

				// Need to save style here so that automatic style restoration
				// doesn't restore to the original styles from before the animation.
				$.effects.saveStyle( element );
			}

			done();
		}
	} );

} );


/*!
 * jQuery UI Effects Scale 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Scale Effect
//>>group: Effects
//>>description: Grows or shrinks an element and its content.
//>>docs: http://api.jqueryui.com/scale-effect/
//>>demos: http://jqueryui.com/effect/


var effectsEffectScale = $.effects.define( "scale", function( options, done ) {

	// Create element
	var el = $( this ),
		mode = options.mode,
		percent = parseInt( options.percent, 10 ) ||
			( parseInt( options.percent, 10 ) === 0 ? 0 : ( mode !== "effect" ? 0 : 100 ) ),

		newOptions = $.extend( true, {
			from: $.effects.scaledDimensions( el ),
			to: $.effects.scaledDimensions( el, percent, options.direction || "both" ),
			origin: options.origin || [ "middle", "center" ]
		}, options );

	// Fade option to support puff
	if ( options.fade ) {
		newOptions.from.opacity = 1;
		newOptions.to.opacity = 0;
	}

	$.effects.effect.size.call( this, newOptions, done );
} );


/*!
 * jQuery UI Effects Puff 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Puff Effect
//>>group: Effects
//>>description: Creates a puff effect by scaling the element up and hiding it at the same time.
//>>docs: http://api.jqueryui.com/puff-effect/
//>>demos: http://jqueryui.com/effect/


var effectsEffectPuff = $.effects.define( "puff", "hide", function( options, done ) {
	var newOptions = $.extend( true, {}, options, {
		fade: true,
		percent: parseInt( options.percent, 10 ) || 150
	} );

	$.effects.effect.scale.call( this, newOptions, done );
} );


/*!
 * jQuery UI Effects Pulsate 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Pulsate Effect
//>>group: Effects
//>>description: Pulsates an element n times by changing the opacity to zero and back.
//>>docs: http://api.jqueryui.com/pulsate-effect/
//>>demos: http://jqueryui.com/effect/


var effectsEffectPulsate = $.effects.define( "pulsate", "show", function( options, done ) {
	var element = $( this ),
		mode = options.mode,
		show = mode === "show",
		hide = mode === "hide",
		showhide = show || hide,

		// Showing or hiding leaves off the "last" animation
		anims = ( ( options.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ),
		duration = options.duration / anims,
		animateTo = 0,
		i = 1,
		queuelen = element.queue().length;

	if ( show || !element.is( ":visible" ) ) {
		element.css( "opacity", 0 ).show();
		animateTo = 1;
	}

	// Anims - 1 opacity "toggles"
	for ( ; i < anims; i++ ) {
		element.animate( { opacity: animateTo }, duration, options.easing );
		animateTo = 1 - animateTo;
	}

	element.animate( { opacity: animateTo }, duration, options.easing );

	element.queue( done );

	$.effects.unshift( element, queuelen, anims + 1 );
} );


/*!
 * jQuery UI Effects Shake 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Shake Effect
//>>group: Effects
//>>description: Shakes an element horizontally or vertically n times.
//>>docs: http://api.jqueryui.com/shake-effect/
//>>demos: http://jqueryui.com/effect/


var effectsEffectShake = $.effects.define( "shake", function( options, done ) {

	var i = 1,
		element = $( this ),
		direction = options.direction || "left",
		distance = options.distance || 20,
		times = options.times || 3,
		anims = times * 2 + 1,
		speed = Math.round( options.duration / anims ),
		ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
		positiveMotion = ( direction === "up" || direction === "left" ),
		animation = {},
		animation1 = {},
		animation2 = {},

		queuelen = element.queue().length;

	$.effects.createPlaceholder( element );

	// Animation
	animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance;
	animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2;
	animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2;

	// Animate
	element.animate( animation, speed, options.easing );

	// Shakes
	for ( ; i < times; i++ ) {
		element
			.animate( animation1, speed, options.easing )
			.animate( animation2, speed, options.easing );
	}

	element
		.animate( animation1, speed, options.easing )
		.animate( animation, speed / 2, options.easing )
		.queue( done );

	$.effects.unshift( element, queuelen, anims + 1 );
} );


/*!
 * jQuery UI Effects Slide 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Slide Effect
//>>group: Effects
//>>description: Slides an element in and out of the viewport.
//>>docs: http://api.jqueryui.com/slide-effect/
//>>demos: http://jqueryui.com/effect/


var effectsEffectSlide = $.effects.define( "slide", "show", function( options, done ) {
	var startClip, startRef,
		element = $( this ),
		map = {
			up: [ "bottom", "top" ],
			down: [ "top", "bottom" ],
			left: [ "right", "left" ],
			right: [ "left", "right" ]
		},
		mode = options.mode,
		direction = options.direction || "left",
		ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
		positiveMotion = ( direction === "up" || direction === "left" ),
		distance = options.distance ||
			element[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ),
		animation = {};

	$.effects.createPlaceholder( element );

	startClip = element.cssClip();
	startRef = element.position()[ ref ];

	// Define hide animation
	animation[ ref ] = ( positiveMotion ? -1 : 1 ) * distance + startRef;
	animation.clip = element.cssClip();
	animation.clip[ map[ direction ][ 1 ] ] = animation.clip[ map[ direction ][ 0 ] ];

	// Reverse the animation if we're showing
	if ( mode === "show" ) {
		element.cssClip( animation.clip );
		element.css( ref, animation[ ref ] );
		animation.clip = startClip;
		animation[ ref ] = startRef;
	}

	// Actually animate
	element.animate( animation, {
		queue: false,
		duration: options.duration,
		easing: options.easing,
		complete: done
	} );
} );


/*!
 * jQuery UI Effects Transfer 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Transfer Effect
//>>group: Effects
//>>description: Displays a transfer effect from one element to another.
//>>docs: http://api.jqueryui.com/transfer-effect/
//>>demos: http://jqueryui.com/effect/


var effect;
if ( $.uiBackCompat !== false ) {
	effect = $.effects.define( "transfer", function( options, done ) {
		$( this ).transfer( options, done );
	} );
}
var effectsEffectTransfer = effect;


/*!
 * jQuery UI Focusable 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: :focusable Selector
//>>group: Core
//>>description: Selects elements which can be focused.
//>>docs: http://api.jqueryui.com/focusable-selector/


// Selectors
$.ui.focusable = function( element, hasTabindex ) {
	var map, mapName, img, focusableIfVisible, fieldset,
		nodeName = element.nodeName.toLowerCase();

	if ( "area" === nodeName ) {
		map = element.parentNode;
		mapName = map.name;
		if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
			return false;
		}
		img = $( "img[usemap='#" + mapName + "']" );
		return img.length > 0 && img.is( ":visible" );
	}

	if ( /^(input|select|textarea|button|object)$/.test( nodeName ) ) {
		focusableIfVisible = !element.disabled;

		if ( focusableIfVisible ) {

			// Form controls within a disabled fieldset are disabled.
			// However, controls within the fieldset's legend do not get disabled.
			// Since controls generally aren't placed inside legends, we skip
			// this portion of the check.
			fieldset = $( element ).closest( "fieldset" )[ 0 ];
			if ( fieldset ) {
				focusableIfVisible = !fieldset.disabled;
			}
		}
	} else if ( "a" === nodeName ) {
		focusableIfVisible = element.href || hasTabindex;
	} else {
		focusableIfVisible = hasTabindex;
	}

	return focusableIfVisible && $( element ).is( ":visible" ) && visible( $( element ) );
};

// Support: IE 8 only
// IE 8 doesn't resolve inherit to visible/hidden for computed values
function visible( element ) {
	var visibility = element.css( "visibility" );
	while ( visibility === "inherit" ) {
		element = element.parent();
		visibility = element.css( "visibility" );
	}
	return visibility === "visible";
}

$.extend( $.expr.pseudos, {
	focusable: function( element ) {
		return $.ui.focusable( element, $.attr( element, "tabindex" ) != null );
	}
} );

var focusable = $.ui.focusable;



// Support: IE8 Only
// IE8 does not support the form attribute and when it is supplied. It overwrites the form prop
// with a string, so we need to find the proper form.
var form = $.fn._form = function() {
	return typeof this[ 0 ].form === "string" ? this.closest( "form" ) : $( this[ 0 ].form );
};


/*!
 * jQuery UI Form Reset Mixin 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Form Reset Mixin
//>>group: Core
//>>description: Refresh input widgets when their form is reset
//>>docs: http://api.jqueryui.com/form-reset-mixin/


var formResetMixin = $.ui.formResetMixin = {
	_formResetHandler: function() {
		var form = $( this );

		// Wait for the form reset to actually happen before refreshing
		setTimeout( function() {
			var instances = form.data( "ui-form-reset-instances" );
			$.each( instances, function() {
				this.refresh();
			} );
		} );
	},

	_bindFormResetHandler: function() {
		this.form = this.element._form();
		if ( !this.form.length ) {
			return;
		}

		var instances = this.form.data( "ui-form-reset-instances" ) || [];
		if ( !instances.length ) {

			// We don't use _on() here because we use a single event handler per form
			this.form.on( "reset.ui-form-reset", this._formResetHandler );
		}
		instances.push( this );
		this.form.data( "ui-form-reset-instances", instances );
	},

	_unbindFormResetHandler: function() {
		if ( !this.form.length ) {
			return;
		}

		var instances = this.form.data( "ui-form-reset-instances" );
		instances.splice( $.inArray( this, instances ), 1 );
		if ( instances.length ) {
			this.form.data( "ui-form-reset-instances", instances );
		} else {
			this.form
				.removeData( "ui-form-reset-instances" )
				.off( "reset.ui-form-reset" );
		}
	}
};


/*!
 * jQuery UI Support for jQuery core 1.8.x and newer 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 *
 */

//>>label: jQuery 1.8+ Support
//>>group: Core
//>>description: Support version 1.8.x and newer of jQuery core


// Support: jQuery 1.9.x or older
// $.expr[ ":" ] is deprecated.
if ( !$.expr.pseudos ) {
	$.expr.pseudos = $.expr[ ":" ];
}

// Support: jQuery 1.11.x or older
// $.unique has been renamed to $.uniqueSort
if ( !$.uniqueSort ) {
	$.uniqueSort = $.unique;
}

// Support: jQuery 2.2.x or older.
// This method has been defined in jQuery 3.0.0.
// Code from https://github.com/jquery/jquery/blob/e539bac79e666bba95bba86d690b4e609dca2286/src/selector/escapeSelector.js
if ( !$.escapeSelector ) {

	// CSS string/identifier serialization
	// https://drafts.csswg.org/cssom/#common-serializing-idioms
	var rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g;

	var fcssescape = function( ch, asCodePoint ) {
		if ( asCodePoint ) {

			// U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER
			if ( ch === "\0" ) {
				return "\uFFFD";
			}

			// Control characters and (dependent upon position) numbers get escaped as code points
			return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " ";
		}

		// Other potentially-special ASCII characters get backslash-escaped
		return "\\" + ch;
	};

	$.escapeSelector = function( sel ) {
		return ( sel + "" ).replace( rcssescape, fcssescape );
	};
}

// Support: jQuery 3.4.x or older
// These methods have been defined in jQuery 3.5.0.
if ( !$.fn.even || !$.fn.odd ) {
	$.fn.extend( {
		even: function() {
			return this.filter( function( i ) {
				return i % 2 === 0;
			} );
		},
		odd: function() {
			return this.filter( function( i ) {
				return i % 2 === 1;
			} );
		}
	} );
}

;
/*!
 * jQuery UI Keycode 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Keycode
//>>group: Core
//>>description: Provide keycodes as keynames
//>>docs: http://api.jqueryui.com/jQuery.ui.keyCode/


var keycode = $.ui.keyCode = {
	BACKSPACE: 8,
	COMMA: 188,
	DELETE: 46,
	DOWN: 40,
	END: 35,
	ENTER: 13,
	ESCAPE: 27,
	HOME: 36,
	LEFT: 37,
	PAGE_DOWN: 34,
	PAGE_UP: 33,
	PERIOD: 190,
	RIGHT: 39,
	SPACE: 32,
	TAB: 9,
	UP: 38
};


/*!
 * jQuery UI Labels 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: labels
//>>group: Core
//>>description: Find all the labels associated with a given input
//>>docs: http://api.jqueryui.com/labels/


var labels = $.fn.labels = function() {
	var ancestor, selector, id, labels, ancestors;

	if ( !this.length ) {
		return this.pushStack( [] );
	}

	// Check control.labels first
	if ( this[ 0 ].labels && this[ 0 ].labels.length ) {
		return this.pushStack( this[ 0 ].labels );
	}

	// Support: IE <= 11, FF <= 37, Android <= 2.3 only
	// Above browsers do not support control.labels. Everything below is to support them
	// as well as document fragments. control.labels does not work on document fragments
	labels = this.eq( 0 ).parents( "label" );

	// Look for the label based on the id
	id = this.attr( "id" );
	if ( id ) {

		// We don't search against the document in case the element
		// is disconnected from the DOM
		ancestor = this.eq( 0 ).parents().last();

		// Get a full set of top level ancestors
		ancestors = ancestor.add( ancestor.length ? ancestor.siblings() : this.siblings() );

		// Create a selector for the label based on the id
		selector = "label[for='" + $.escapeSelector( id ) + "']";

		labels = labels.add( ancestors.find( selector ).addBack( selector ) );

	}

	// Return whatever we have found for labels
	return this.pushStack( labels );
};


/*!
 * jQuery UI Scroll Parent 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: scrollParent
//>>group: Core
//>>description: Get the closest ancestor element that is scrollable.
//>>docs: http://api.jqueryui.com/scrollParent/


var scrollParent = $.fn.scrollParent = function( includeHidden ) {
	var position = this.css( "position" ),
		excludeStaticParent = position === "absolute",
		overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/,
		scrollParent = this.parents().filter( function() {
			var parent = $( this );
			if ( excludeStaticParent && parent.css( "position" ) === "static" ) {
				return false;
			}
			return overflowRegex.test( parent.css( "overflow" ) + parent.css( "overflow-y" ) +
				parent.css( "overflow-x" ) );
		} ).eq( 0 );

	return position === "fixed" || !scrollParent.length ?
		$( this[ 0 ].ownerDocument || document ) :
		scrollParent;
};


/*!
 * jQuery UI Tabbable 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: :tabbable Selector
//>>group: Core
//>>description: Selects elements which can be tabbed to.
//>>docs: http://api.jqueryui.com/tabbable-selector/


var tabbable = $.extend( $.expr.pseudos, {
	tabbable: function( element ) {
		var tabIndex = $.attr( element, "tabindex" ),
			hasTabindex = tabIndex != null;
		return ( !hasTabindex || tabIndex >= 0 ) && $.ui.focusable( element, hasTabindex );
	}
} );


/*!
 * jQuery UI Unique ID 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: uniqueId
//>>group: Core
//>>description: Functions to generate and remove uniqueId's
//>>docs: http://api.jqueryui.com/uniqueId/


var uniqueId = $.fn.extend( {
	uniqueId: ( function() {
		var uuid = 0;

		return function() {
			return this.each( function() {
				if ( !this.id ) {
					this.id = "ui-id-" + ( ++uuid );
				}
			} );
		};
	} )(),

	removeUniqueId: function() {
		return this.each( function() {
			if ( /^ui-id-\d+$/.test( this.id ) ) {
				$( this ).removeAttr( "id" );
			}
		} );
	}
} );


/*!
 * jQuery UI Accordion 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Accordion
//>>group: Widgets
/* eslint-disable max-len */
//>>description: Displays collapsible content panels for presenting information in a limited amount of space.
/* eslint-enable max-len */
//>>docs: http://api.jqueryui.com/accordion/
//>>demos: http://jqueryui.com/accordion/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/accordion.css
//>>css.theme: ../../themes/base/theme.css


var widgetsAccordion = $.widget( "ui.accordion", {
	version: "1.13.2",
	options: {
		active: 0,
		animate: {},
		classes: {
			"ui-accordion-header": "ui-corner-top",
			"ui-accordion-header-collapsed": "ui-corner-all",
			"ui-accordion-content": "ui-corner-bottom"
		},
		collapsible: false,
		event: "click",
		header: function( elem ) {
			return elem.find( "> li > :first-child" ).add( elem.find( "> :not(li)" ).even() );
		},
		heightStyle: "auto",
		icons: {
			activeHeader: "ui-icon-triangle-1-s",
			header: "ui-icon-triangle-1-e"
		},

		// Callbacks
		activate: null,
		beforeActivate: null
	},

	hideProps: {
		borderTopWidth: "hide",
		borderBottomWidth: "hide",
		paddingTop: "hide",
		paddingBottom: "hide",
		height: "hide"
	},

	showProps: {
		borderTopWidth: "show",
		borderBottomWidth: "show",
		paddingTop: "show",
		paddingBottom: "show",
		height: "show"
	},

	_create: function() {
		var options = this.options;

		this.prevShow = this.prevHide = $();
		this._addClass( "ui-accordion", "ui-widget ui-helper-reset" );
		this.element.attr( "role", "tablist" );

		// Don't allow collapsible: false and active: false / null
		if ( !options.collapsible && ( options.active === false || options.active == null ) ) {
			options.active = 0;
		}

		this._processPanels();

		// handle negative values
		if ( options.active < 0 ) {
			options.active += this.headers.length;
		}
		this._refresh();
	},

	_getCreateEventData: function() {
		return {
			header: this.active,
			panel: !this.active.length ? $() : this.active.next()
		};
	},

	_createIcons: function() {
		var icon, children,
			icons = this.options.icons;

		if ( icons ) {
			icon = $( "<span>" );
			this._addClass( icon, "ui-accordion-header-icon", "ui-icon " + icons.header );
			icon.prependTo( this.headers );
			children = this.active.children( ".ui-accordion-header-icon" );
			this._removeClass( children, icons.header )
				._addClass( children, null, icons.activeHeader )
				._addClass( this.headers, "ui-accordion-icons" );
		}
	},

	_destroyIcons: function() {
		this._removeClass( this.headers, "ui-accordion-icons" );
		this.headers.children( ".ui-accordion-header-icon" ).remove();
	},

	_destroy: function() {
		var contents;

		// Clean up main element
		this.element.removeAttr( "role" );

		// Clean up headers
		this.headers
			.removeAttr( "role aria-expanded aria-selected aria-controls tabIndex" )
			.removeUniqueId();

		this._destroyIcons();

		// Clean up content panels
		contents = this.headers.next()
			.css( "display", "" )
			.removeAttr( "role aria-hidden aria-labelledby" )
			.removeUniqueId();

		if ( this.options.heightStyle !== "content" ) {
			contents.css( "height", "" );
		}
	},

	_setOption: function( key, value ) {
		if ( key === "active" ) {

			// _activate() will handle invalid values and update this.options
			this._activate( value );
			return;
		}

		if ( key === "event" ) {
			if ( this.options.event ) {
				this._off( this.headers, this.options.event );
			}
			this._setupEvents( value );
		}

		this._super( key, value );

		// Setting collapsible: false while collapsed; open first panel
		if ( key === "collapsible" && !value && this.options.active === false ) {
			this._activate( 0 );
		}

		if ( key === "icons" ) {
			this._destroyIcons();
			if ( value ) {
				this._createIcons();
			}
		}
	},

	_setOptionDisabled: function( value ) {
		this._super( value );

		this.element.attr( "aria-disabled", value );

		// Support: IE8 Only
		// #5332 / #6059 - opacity doesn't cascade to positioned elements in IE
		// so we need to add the disabled class to the headers and panels
		this._toggleClass( null, "ui-state-disabled", !!value );
		this._toggleClass( this.headers.add( this.headers.next() ), null, "ui-state-disabled",
			!!value );
	},

	_keydown: function( event ) {
		if ( event.altKey || event.ctrlKey ) {
			return;
		}

		var keyCode = $.ui.keyCode,
			length = this.headers.length,
			currentIndex = this.headers.index( event.target ),
			toFocus = false;

		switch ( event.keyCode ) {
		case keyCode.RIGHT:
		case keyCode.DOWN:
			toFocus = this.headers[ ( currentIndex + 1 ) % length ];
			break;
		case keyCode.LEFT:
		case keyCode.UP:
			toFocus = this.headers[ ( currentIndex - 1 + length ) % length ];
			break;
		case keyCode.SPACE:
		case keyCode.ENTER:
			this._eventHandler( event );
			break;
		case keyCode.HOME:
			toFocus = this.headers[ 0 ];
			break;
		case keyCode.END:
			toFocus = this.headers[ length - 1 ];
			break;
		}

		if ( toFocus ) {
			$( event.target ).attr( "tabIndex", -1 );
			$( toFocus ).attr( "tabIndex", 0 );
			$( toFocus ).trigger( "focus" );
			event.preventDefault();
		}
	},

	_panelKeyDown: function( event ) {
		if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) {
			$( event.currentTarget ).prev().trigger( "focus" );
		}
	},

	refresh: function() {
		var options = this.options;
		this._processPanels();

		// Was collapsed or no panel
		if ( ( options.active === false && options.collapsible === true ) ||
				!this.headers.length ) {
			options.active = false;
			this.active = $();

		// active false only when collapsible is true
		} else if ( options.active === false ) {
			this._activate( 0 );

		// was active, but active panel is gone
		} else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {

			// all remaining panel are disabled
			if ( this.headers.length === this.headers.find( ".ui-state-disabled" ).length ) {
				options.active = false;
				this.active = $();

			// activate previous panel
			} else {
				this._activate( Math.max( 0, options.active - 1 ) );
			}

		// was active, active panel still exists
		} else {

			// make sure active index is correct
			options.active = this.headers.index( this.active );
		}

		this._destroyIcons();

		this._refresh();
	},

	_processPanels: function() {
		var prevHeaders = this.headers,
			prevPanels = this.panels;

		if ( typeof this.options.header === "function" ) {
			this.headers = this.options.header( this.element );
		} else {
			this.headers = this.element.find( this.options.header );
		}
		this._addClass( this.headers, "ui-accordion-header ui-accordion-header-collapsed",
			"ui-state-default" );

		this.panels = this.headers.next().filter( ":not(.ui-accordion-content-active)" ).hide();
		this._addClass( this.panels, "ui-accordion-content", "ui-helper-reset ui-widget-content" );

		// Avoid memory leaks (#10056)
		if ( prevPanels ) {
			this._off( prevHeaders.not( this.headers ) );
			this._off( prevPanels.not( this.panels ) );
		}
	},

	_refresh: function() {
		var maxHeight,
			options = this.options,
			heightStyle = options.heightStyle,
			parent = this.element.parent();

		this.active = this._findActive( options.active );
		this._addClass( this.active, "ui-accordion-header-active", "ui-state-active" )
			._removeClass( this.active, "ui-accordion-header-collapsed" );
		this._addClass( this.active.next(), "ui-accordion-content-active" );
		this.active.next().show();

		this.headers
			.attr( "role", "tab" )
			.each( function() {
				var header = $( this ),
					headerId = header.uniqueId().attr( "id" ),
					panel = header.next(),
					panelId = panel.uniqueId().attr( "id" );
				header.attr( "aria-controls", panelId );
				panel.attr( "aria-labelledby", headerId );
			} )
			.next()
				.attr( "role", "tabpanel" );

		this.headers
			.not( this.active )
				.attr( {
					"aria-selected": "false",
					"aria-expanded": "false",
					tabIndex: -1
				} )
				.next()
					.attr( {
						"aria-hidden": "true"
					} )
					.hide();

		// Make sure at least one header is in the tab order
		if ( !this.active.length ) {
			this.headers.eq( 0 ).attr( "tabIndex", 0 );
		} else {
			this.active.attr( {
				"aria-selected": "true",
				"aria-expanded": "true",
				tabIndex: 0
			} )
				.next()
					.attr( {
						"aria-hidden": "false"
					} );
		}

		this._createIcons();

		this._setupEvents( options.event );

		if ( heightStyle === "fill" ) {
			maxHeight = parent.height();
			this.element.siblings( ":visible" ).each( function() {
				var elem = $( this ),
					position = elem.css( "position" );

				if ( position === "absolute" || position === "fixed" ) {
					return;
				}
				maxHeight -= elem.outerHeight( true );
			} );

			this.headers.each( function() {
				maxHeight -= $( this ).outerHeight( true );
			} );

			this.headers.next()
				.each( function() {
					$( this ).height( Math.max( 0, maxHeight -
						$( this ).innerHeight() + $( this ).height() ) );
				} )
				.css( "overflow", "auto" );
		} else if ( heightStyle === "auto" ) {
			maxHeight = 0;
			this.headers.next()
				.each( function() {
					var isVisible = $( this ).is( ":visible" );
					if ( !isVisible ) {
						$( this ).show();
					}
					maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() );
					if ( !isVisible ) {
						$( this ).hide();
					}
				} )
				.height( maxHeight );
		}
	},

	_activate: function( index ) {
		var active = this._findActive( index )[ 0 ];

		// Trying to activate the already active panel
		if ( active === this.active[ 0 ] ) {
			return;
		}

		// Trying to collapse, simulate a click on the currently active header
		active = active || this.active[ 0 ];

		this._eventHandler( {
			target: active,
			currentTarget: active,
			preventDefault: $.noop
		} );
	},

	_findActive: function( selector ) {
		return typeof selector === "number" ? this.headers.eq( selector ) : $();
	},

	_setupEvents: function( event ) {
		var events = {
			keydown: "_keydown"
		};
		if ( event ) {
			$.each( event.split( " " ), function( index, eventName ) {
				events[ eventName ] = "_eventHandler";
			} );
		}

		this._off( this.headers.add( this.headers.next() ) );
		this._on( this.headers, events );
		this._on( this.headers.next(), { keydown: "_panelKeyDown" } );
		this._hoverable( this.headers );
		this._focusable( this.headers );
	},

	_eventHandler: function( event ) {
		var activeChildren, clickedChildren,
			options = this.options,
			active = this.active,
			clicked = $( event.currentTarget ),
			clickedIsActive = clicked[ 0 ] === active[ 0 ],
			collapsing = clickedIsActive && options.collapsible,
			toShow = collapsing ? $() : clicked.next(),
			toHide = active.next(),
			eventData = {
				oldHeader: active,
				oldPanel: toHide,
				newHeader: collapsing ? $() : clicked,
				newPanel: toShow
			};

		event.preventDefault();

		if (

				// click on active header, but not collapsible
				( clickedIsActive && !options.collapsible ) ||

				// allow canceling activation
				( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
			return;
		}

		options.active = collapsing ? false : this.headers.index( clicked );

		// When the call to ._toggle() comes after the class changes
		// it causes a very odd bug in IE 8 (see #6720)
		this.active = clickedIsActive ? $() : clicked;
		this._toggle( eventData );

		// Switch classes
		// corner classes on the previously active header stay after the animation
		this._removeClass( active, "ui-accordion-header-active", "ui-state-active" );
		if ( options.icons ) {
			activeChildren = active.children( ".ui-accordion-header-icon" );
			this._removeClass( activeChildren, null, options.icons.activeHeader )
				._addClass( activeChildren, null, options.icons.header );
		}

		if ( !clickedIsActive ) {
			this._removeClass( clicked, "ui-accordion-header-collapsed" )
				._addClass( clicked, "ui-accordion-header-active", "ui-state-active" );
			if ( options.icons ) {
				clickedChildren = clicked.children( ".ui-accordion-header-icon" );
				this._removeClass( clickedChildren, null, options.icons.header )
					._addClass( clickedChildren, null, options.icons.activeHeader );
			}

			this._addClass( clicked.next(), "ui-accordion-content-active" );
		}
	},

	_toggle: function( data ) {
		var toShow = data.newPanel,
			toHide = this.prevShow.length ? this.prevShow : data.oldPanel;

		// Handle activating a panel during the animation for another activation
		this.prevShow.add( this.prevHide ).stop( true, true );
		this.prevShow = toShow;
		this.prevHide = toHide;

		if ( this.options.animate ) {
			this._animate( toShow, toHide, data );
		} else {
			toHide.hide();
			toShow.show();
			this._toggleComplete( data );
		}

		toHide.attr( {
			"aria-hidden": "true"
		} );
		toHide.prev().attr( {
			"aria-selected": "false",
			"aria-expanded": "false"
		} );

		// if we're switching panels, remove the old header from the tab order
		// if we're opening from collapsed state, remove the previous header from the tab order
		// if we're collapsing, then keep the collapsing header in the tab order
		if ( toShow.length && toHide.length ) {
			toHide.prev().attr( {
				"tabIndex": -1,
				"aria-expanded": "false"
			} );
		} else if ( toShow.length ) {
			this.headers.filter( function() {
				return parseInt( $( this ).attr( "tabIndex" ), 10 ) === 0;
			} )
				.attr( "tabIndex", -1 );
		}

		toShow
			.attr( "aria-hidden", "false" )
			.prev()
				.attr( {
					"aria-selected": "true",
					"aria-expanded": "true",
					tabIndex: 0
				} );
	},

	_animate: function( toShow, toHide, data ) {
		var total, easing, duration,
			that = this,
			adjust = 0,
			boxSizing = toShow.css( "box-sizing" ),
			down = toShow.length &&
				( !toHide.length || ( toShow.index() < toHide.index() ) ),
			animate = this.options.animate || {},
			options = down && animate.down || animate,
			complete = function() {
				that._toggleComplete( data );
			};

		if ( typeof options === "number" ) {
			duration = options;
		}
		if ( typeof options === "string" ) {
			easing = options;
		}

		// fall back from options to animation in case of partial down settings
		easing = easing || options.easing || animate.easing;
		duration = duration || options.duration || animate.duration;

		if ( !toHide.length ) {
			return toShow.animate( this.showProps, duration, easing, complete );
		}
		if ( !toShow.length ) {
			return toHide.animate( this.hideProps, duration, easing, complete );
		}

		total = toShow.show().outerHeight();
		toHide.animate( this.hideProps, {
			duration: duration,
			easing: easing,
			step: function( now, fx ) {
				fx.now = Math.round( now );
			}
		} );
		toShow
			.hide()
			.animate( this.showProps, {
				duration: duration,
				easing: easing,
				complete: complete,
				step: function( now, fx ) {
					fx.now = Math.round( now );
					if ( fx.prop !== "height" ) {
						if ( boxSizing === "content-box" ) {
							adjust += fx.now;
						}
					} else if ( that.options.heightStyle !== "content" ) {
						fx.now = Math.round( total - toHide.outerHeight() - adjust );
						adjust = 0;
					}
				}
			} );
	},

	_toggleComplete: function( data ) {
		var toHide = data.oldPanel,
			prev = toHide.prev();

		this._removeClass( toHide, "ui-accordion-content-active" );
		this._removeClass( prev, "ui-accordion-header-active" )
			._addClass( prev, "ui-accordion-header-collapsed" );

		// Work around for rendering bug in IE (#5421)
		if ( toHide.length ) {
			toHide.parent()[ 0 ].className = toHide.parent()[ 0 ].className;
		}
		this._trigger( "activate", null, data );
	}
} );



var safeActiveElement = $.ui.safeActiveElement = function( document ) {
	var activeElement;

	// Support: IE 9 only
	// IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
	try {
		activeElement = document.activeElement;
	} catch ( error ) {
		activeElement = document.body;
	}

	// Support: IE 9 - 11 only
	// IE may return null instead of an element
	// Interestingly, this only seems to occur when NOT in an iframe
	if ( !activeElement ) {
		activeElement = document.body;
	}

	// Support: IE 11 only
	// IE11 returns a seemingly empty object in some cases when accessing
	// document.activeElement from an <iframe>
	if ( !activeElement.nodeName ) {
		activeElement = document.body;
	}

	return activeElement;
};


/*!
 * jQuery UI Menu 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Menu
//>>group: Widgets
//>>description: Creates nestable menus.
//>>docs: http://api.jqueryui.com/menu/
//>>demos: http://jqueryui.com/menu/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/menu.css
//>>css.theme: ../../themes/base/theme.css


var widgetsMenu = $.widget( "ui.menu", {
	version: "1.13.2",
	defaultElement: "<ul>",
	delay: 300,
	options: {
		icons: {
			submenu: "ui-icon-caret-1-e"
		},
		items: "> *",
		menus: "ul",
		position: {
			my: "left top",
			at: "right top"
		},
		role: "menu",

		// Callbacks
		blur: null,
		focus: null,
		select: null
	},

	_create: function() {
		this.activeMenu = this.element;

		// Flag used to prevent firing of the click handler
		// as the event bubbles up through nested menus
		this.mouseHandled = false;
		this.lastMousePosition = { x: null, y: null };
		this.element
			.uniqueId()
			.attr( {
				role: this.options.role,
				tabIndex: 0
			} );

		this._addClass( "ui-menu", "ui-widget ui-widget-content" );
		this._on( {

			// Prevent focus from sticking to links inside menu after clicking
			// them (focus should always stay on UL during navigation).
			"mousedown .ui-menu-item": function( event ) {
				event.preventDefault();

				this._activateItem( event );
			},
			"click .ui-menu-item": function( event ) {
				var target = $( event.target );
				var active = $( $.ui.safeActiveElement( this.document[ 0 ] ) );
				if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) {
					this.select( event );

					// Only set the mouseHandled flag if the event will bubble, see #9469.
					if ( !event.isPropagationStopped() ) {
						this.mouseHandled = true;
					}

					// Open submenu on click
					if ( target.has( ".ui-menu" ).length ) {
						this.expand( event );
					} else if ( !this.element.is( ":focus" ) &&
							active.closest( ".ui-menu" ).length ) {

						// Redirect focus to the menu
						this.element.trigger( "focus", [ true ] );

						// If the active item is on the top level, let it stay active.
						// Otherwise, blur the active item since it is no longer visible.
						if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
							clearTimeout( this.timer );
						}
					}
				}
			},
			"mouseenter .ui-menu-item": "_activateItem",
			"mousemove .ui-menu-item": "_activateItem",
			mouseleave: "collapseAll",
			"mouseleave .ui-menu": "collapseAll",
			focus: function( event, keepActiveItem ) {

				// If there's already an active item, keep it active
				// If not, activate the first item
				var item = this.active || this._menuItems().first();

				if ( !keepActiveItem ) {
					this.focus( event, item );
				}
			},
			blur: function( event ) {
				this._delay( function() {
					var notContained = !$.contains(
						this.element[ 0 ],
						$.ui.safeActiveElement( this.document[ 0 ] )
					);
					if ( notContained ) {
						this.collapseAll( event );
					}
				} );
			},
			keydown: "_keydown"
		} );

		this.refresh();

		// Clicks outside of a menu collapse any open menus
		this._on( this.document, {
			click: function( event ) {
				if ( this._closeOnDocumentClick( event ) ) {
					this.collapseAll( event, true );
				}

				// Reset the mouseHandled flag
				this.mouseHandled = false;
			}
		} );
	},

	_activateItem: function( event ) {

		// Ignore mouse events while typeahead is active, see #10458.
		// Prevents focusing the wrong item when typeahead causes a scroll while the mouse
		// is over an item in the menu
		if ( this.previousFilter ) {
			return;
		}

		// If the mouse didn't actually move, but the page was scrolled, ignore the event (#9356)
		if ( event.clientX === this.lastMousePosition.x &&
				event.clientY === this.lastMousePosition.y ) {
			return;
		}

		this.lastMousePosition = {
			x: event.clientX,
			y: event.clientY
		};

		var actualTarget = $( event.target ).closest( ".ui-menu-item" ),
			target = $( event.currentTarget );

		// Ignore bubbled events on parent items, see #11641
		if ( actualTarget[ 0 ] !== target[ 0 ] ) {
			return;
		}

		// If the item is already active, there's nothing to do
		if ( target.is( ".ui-state-active" ) ) {
			return;
		}

		// Remove ui-state-active class from siblings of the newly focused menu item
		// to avoid a jump caused by adjacent elements both having a class with a border
		this._removeClass( target.siblings().children( ".ui-state-active" ),
			null, "ui-state-active" );
		this.focus( event, target );
	},

	_destroy: function() {
		var items = this.element.find( ".ui-menu-item" )
				.removeAttr( "role aria-disabled" ),
			submenus = items.children( ".ui-menu-item-wrapper" )
				.removeUniqueId()
				.removeAttr( "tabIndex role aria-haspopup" );

		// Destroy (sub)menus
		this.element
			.removeAttr( "aria-activedescendant" )
			.find( ".ui-menu" ).addBack()
				.removeAttr( "role aria-labelledby aria-expanded aria-hidden aria-disabled " +
					"tabIndex" )
				.removeUniqueId()
				.show();

		submenus.children().each( function() {
			var elem = $( this );
			if ( elem.data( "ui-menu-submenu-caret" ) ) {
				elem.remove();
			}
		} );
	},

	_keydown: function( event ) {
		var match, prev, character, skip,
			preventDefault = true;

		switch ( event.keyCode ) {
		case $.ui.keyCode.PAGE_UP:
			this.previousPage( event );
			break;
		case $.ui.keyCode.PAGE_DOWN:
			this.nextPage( event );
			break;
		case $.ui.keyCode.HOME:
			this._move( "first", "first", event );
			break;
		case $.ui.keyCode.END:
			this._move( "last", "last", event );
			break;
		case $.ui.keyCode.UP:
			this.previous( event );
			break;
		case $.ui.keyCode.DOWN:
			this.next( event );
			break;
		case $.ui.keyCode.LEFT:
			this.collapse( event );
			break;
		case $.ui.keyCode.RIGHT:
			if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
				this.expand( event );
			}
			break;
		case $.ui.keyCode.ENTER:
		case $.ui.keyCode.SPACE:
			this._activate( event );
			break;
		case $.ui.keyCode.ESCAPE:
			this.collapse( event );
			break;
		default:
			preventDefault = false;
			prev = this.previousFilter || "";
			skip = false;

			// Support number pad values
			character = event.keyCode >= 96 && event.keyCode <= 105 ?
				( event.keyCode - 96 ).toString() : String.fromCharCode( event.keyCode );

			clearTimeout( this.filterTimer );

			if ( character === prev ) {
				skip = true;
			} else {
				character = prev + character;
			}

			match = this._filterMenuItems( character );
			match = skip && match.index( this.active.next() ) !== -1 ?
				this.active.nextAll( ".ui-menu-item" ) :
				match;

			// If no matches on the current filter, reset to the last character pressed
			// to move down the menu to the first item that starts with that character
			if ( !match.length ) {
				character = String.fromCharCode( event.keyCode );
				match = this._filterMenuItems( character );
			}

			if ( match.length ) {
				this.focus( event, match );
				this.previousFilter = character;
				this.filterTimer = this._delay( function() {
					delete this.previousFilter;
				}, 1000 );
			} else {
				delete this.previousFilter;
			}
		}

		if ( preventDefault ) {
			event.preventDefault();
		}
	},

	_activate: function( event ) {
		if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
			if ( this.active.children( "[aria-haspopup='true']" ).length ) {
				this.expand( event );
			} else {
				this.select( event );
			}
		}
	},

	refresh: function() {
		var menus, items, newSubmenus, newItems, newWrappers,
			that = this,
			icon = this.options.icons.submenu,
			submenus = this.element.find( this.options.menus );

		this._toggleClass( "ui-menu-icons", null, !!this.element.find( ".ui-icon" ).length );

		// Initialize nested menus
		newSubmenus = submenus.filter( ":not(.ui-menu)" )
			.hide()
			.attr( {
				role: this.options.role,
				"aria-hidden": "true",
				"aria-expanded": "false"
			} )
			.each( function() {
				var menu = $( this ),
					item = menu.prev(),
					submenuCaret = $( "<span>" ).data( "ui-menu-submenu-caret", true );

				that._addClass( submenuCaret, "ui-menu-icon", "ui-icon " + icon );
				item
					.attr( "aria-haspopup", "true" )
					.prepend( submenuCaret );
				menu.attr( "aria-labelledby", item.attr( "id" ) );
			} );

		this._addClass( newSubmenus, "ui-menu", "ui-widget ui-widget-content ui-front" );

		menus = submenus.add( this.element );
		items = menus.find( this.options.items );

		// Initialize menu-items containing spaces and/or dashes only as dividers
		items.not( ".ui-menu-item" ).each( function() {
			var item = $( this );
			if ( that._isDivider( item ) ) {
				that._addClass( item, "ui-menu-divider", "ui-widget-content" );
			}
		} );

		// Don't refresh list items that are already adapted
		newItems = items.not( ".ui-menu-item, .ui-menu-divider" );
		newWrappers = newItems.children()
			.not( ".ui-menu" )
				.uniqueId()
				.attr( {
					tabIndex: -1,
					role: this._itemRole()
				} );
		this._addClass( newItems, "ui-menu-item" )
			._addClass( newWrappers, "ui-menu-item-wrapper" );

		// Add aria-disabled attribute to any disabled menu item
		items.filter( ".ui-state-disabled" ).attr( "aria-disabled", "true" );

		// If the active item has been removed, blur the menu
		if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
			this.blur();
		}
	},

	_itemRole: function() {
		return {
			menu: "menuitem",
			listbox: "option"
		}[ this.options.role ];
	},

	_setOption: function( key, value ) {
		if ( key === "icons" ) {
			var icons = this.element.find( ".ui-menu-icon" );
			this._removeClass( icons, null, this.options.icons.submenu )
				._addClass( icons, null, value.submenu );
		}
		this._super( key, value );
	},

	_setOptionDisabled: function( value ) {
		this._super( value );

		this.element.attr( "aria-disabled", String( value ) );
		this._toggleClass( null, "ui-state-disabled", !!value );
	},

	focus: function( event, item ) {
		var nested, focused, activeParent;
		this.blur( event, event && event.type === "focus" );

		this._scrollIntoView( item );

		this.active = item.first();

		focused = this.active.children( ".ui-menu-item-wrapper" );
		this._addClass( focused, null, "ui-state-active" );

		// Only update aria-activedescendant if there's a role
		// otherwise we assume focus is managed elsewhere
		if ( this.options.role ) {
			this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
		}

		// Highlight active parent menu item, if any
		activeParent = this.active
			.parent()
				.closest( ".ui-menu-item" )
					.children( ".ui-menu-item-wrapper" );
		this._addClass( activeParent, null, "ui-state-active" );

		if ( event && event.type === "keydown" ) {
			this._close();
		} else {
			this.timer = this._delay( function() {
				this._close();
			}, this.delay );
		}

		nested = item.children( ".ui-menu" );
		if ( nested.length && event && ( /^mouse/.test( event.type ) ) ) {
			this._startOpening( nested );
		}
		this.activeMenu = item.parent();

		this._trigger( "focus", event, { item: item } );
	},

	_scrollIntoView: function( item ) {
		var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
		if ( this._hasScroll() ) {
			borderTop = parseFloat( $.css( this.activeMenu[ 0 ], "borderTopWidth" ) ) || 0;
			paddingTop = parseFloat( $.css( this.activeMenu[ 0 ], "paddingTop" ) ) || 0;
			offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
			scroll = this.activeMenu.scrollTop();
			elementHeight = this.activeMenu.height();
			itemHeight = item.outerHeight();

			if ( offset < 0 ) {
				this.activeMenu.scrollTop( scroll + offset );
			} else if ( offset + itemHeight > elementHeight ) {
				this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
			}
		}
	},

	blur: function( event, fromFocus ) {
		if ( !fromFocus ) {
			clearTimeout( this.timer );
		}

		if ( !this.active ) {
			return;
		}

		this._removeClass( this.active.children( ".ui-menu-item-wrapper" ),
			null, "ui-state-active" );

		this._trigger( "blur", event, { item: this.active } );
		this.active = null;
	},

	_startOpening: function( submenu ) {
		clearTimeout( this.timer );

		// Don't open if already open fixes a Firefox bug that caused a .5 pixel
		// shift in the submenu position when mousing over the caret icon
		if ( submenu.attr( "aria-hidden" ) !== "true" ) {
			return;
		}

		this.timer = this._delay( function() {
			this._close();
			this._open( submenu );
		}, this.delay );
	},

	_open: function( submenu ) {
		var position = $.extend( {
			of: this.active
		}, this.options.position );

		clearTimeout( this.timer );
		this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
			.hide()
			.attr( "aria-hidden", "true" );

		submenu
			.show()
			.removeAttr( "aria-hidden" )
			.attr( "aria-expanded", "true" )
			.position( position );
	},

	collapseAll: function( event, all ) {
		clearTimeout( this.timer );
		this.timer = this._delay( function() {

			// If we were passed an event, look for the submenu that contains the event
			var currentMenu = all ? this.element :
				$( event && event.target ).closest( this.element.find( ".ui-menu" ) );

			// If we found no valid submenu ancestor, use the main menu to close all
			// sub menus anyway
			if ( !currentMenu.length ) {
				currentMenu = this.element;
			}

			this._close( currentMenu );

			this.blur( event );

			// Work around active item staying active after menu is blurred
			this._removeClass( currentMenu.find( ".ui-state-active" ), null, "ui-state-active" );

			this.activeMenu = currentMenu;
		}, all ? 0 : this.delay );
	},

	// With no arguments, closes the currently active menu - if nothing is active
	// it closes all menus.  If passed an argument, it will search for menus BELOW
	_close: function( startMenu ) {
		if ( !startMenu ) {
			startMenu = this.active ? this.active.parent() : this.element;
		}

		startMenu.find( ".ui-menu" )
			.hide()
			.attr( "aria-hidden", "true" )
			.attr( "aria-expanded", "false" );
	},

	_closeOnDocumentClick: function( event ) {
		return !$( event.target ).closest( ".ui-menu" ).length;
	},

	_isDivider: function( item ) {

		// Match hyphen, em dash, en dash
		return !/[^\-\u2014\u2013\s]/.test( item.text() );
	},

	collapse: function( event ) {
		var newItem = this.active &&
			this.active.parent().closest( ".ui-menu-item", this.element );
		if ( newItem && newItem.length ) {
			this._close();
			this.focus( event, newItem );
		}
	},

	expand: function( event ) {
		var newItem = this.active && this._menuItems( this.active.children( ".ui-menu" ) ).first();

		if ( newItem && newItem.length ) {
			this._open( newItem.parent() );

			// Delay so Firefox will not hide activedescendant change in expanding submenu from AT
			this._delay( function() {
				this.focus( event, newItem );
			} );
		}
	},

	next: function( event ) {
		this._move( "next", "first", event );
	},

	previous: function( event ) {
		this._move( "prev", "last", event );
	},

	isFirstItem: function() {
		return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
	},

	isLastItem: function() {
		return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
	},

	_menuItems: function( menu ) {
		return ( menu || this.element )
			.find( this.options.items )
			.filter( ".ui-menu-item" );
	},

	_move: function( direction, filter, event ) {
		var next;
		if ( this.active ) {
			if ( direction === "first" || direction === "last" ) {
				next = this.active
					[ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
					.last();
			} else {
				next = this.active
					[ direction + "All" ]( ".ui-menu-item" )
					.first();
			}
		}
		if ( !next || !next.length || !this.active ) {
			next = this._menuItems( this.activeMenu )[ filter ]();
		}

		this.focus( event, next );
	},

	nextPage: function( event ) {
		var item, base, height;

		if ( !this.active ) {
			this.next( event );
			return;
		}
		if ( this.isLastItem() ) {
			return;
		}
		if ( this._hasScroll() ) {
			base = this.active.offset().top;
			height = this.element.innerHeight();

			// jQuery 3.2 doesn't include scrollbars in innerHeight, add it back.
			if ( $.fn.jquery.indexOf( "3.2." ) === 0 ) {
				height += this.element[ 0 ].offsetHeight - this.element.outerHeight();
			}

			this.active.nextAll( ".ui-menu-item" ).each( function() {
				item = $( this );
				return item.offset().top - base - height < 0;
			} );

			this.focus( event, item );
		} else {
			this.focus( event, this._menuItems( this.activeMenu )
				[ !this.active ? "first" : "last" ]() );
		}
	},

	previousPage: function( event ) {
		var item, base, height;
		if ( !this.active ) {
			this.next( event );
			return;
		}
		if ( this.isFirstItem() ) {
			return;
		}
		if ( this._hasScroll() ) {
			base = this.active.offset().top;
			height = this.element.innerHeight();

			// jQuery 3.2 doesn't include scrollbars in innerHeight, add it back.
			if ( $.fn.jquery.indexOf( "3.2." ) === 0 ) {
				height += this.element[ 0 ].offsetHeight - this.element.outerHeight();
			}

			this.active.prevAll( ".ui-menu-item" ).each( function() {
				item = $( this );
				return item.offset().top - base + height > 0;
			} );

			this.focus( event, item );
		} else {
			this.focus( event, this._menuItems( this.activeMenu ).first() );
		}
	},

	_hasScroll: function() {
		return this.element.outerHeight() < this.element.prop( "scrollHeight" );
	},

	select: function( event ) {

		// TODO: It should never be possible to not have an active item at this
		// point, but the tests don't trigger mouseenter before click.
		this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
		var ui = { item: this.active };
		if ( !this.active.has( ".ui-menu" ).length ) {
			this.collapseAll( event, true );
		}
		this._trigger( "select", event, ui );
	},

	_filterMenuItems: function( character ) {
		var escapedCharacter = character.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ),
			regex = new RegExp( "^" + escapedCharacter, "i" );

		return this.activeMenu
			.find( this.options.items )

				// Only match on items, not dividers or other content (#10571)
				.filter( ".ui-menu-item" )
					.filter( function() {
						return regex.test(
							String.prototype.trim.call(
								$( this ).children( ".ui-menu-item-wrapper" ).text() ) );
					} );
	}
} );


/*!
 * jQuery UI Autocomplete 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Autocomplete
//>>group: Widgets
//>>description: Lists suggested words as the user is typing.
//>>docs: http://api.jqueryui.com/autocomplete/
//>>demos: http://jqueryui.com/autocomplete/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/autocomplete.css
//>>css.theme: ../../themes/base/theme.css


$.widget( "ui.autocomplete", {
	version: "1.13.2",
	defaultElement: "<input>",
	options: {
		appendTo: null,
		autoFocus: false,
		delay: 300,
		minLength: 1,
		position: {
			my: "left top",
			at: "left bottom",
			collision: "none"
		},
		source: null,

		// Callbacks
		change: null,
		close: null,
		focus: null,
		open: null,
		response: null,
		search: null,
		select: null
	},

	requestIndex: 0,
	pending: 0,
	liveRegionTimer: null,

	_create: function() {

		// Some browsers only repeat keydown events, not keypress events,
		// so we use the suppressKeyPress flag to determine if we've already
		// handled the keydown event. #7269
		// Unfortunately the code for & in keypress is the same as the up arrow,
		// so we use the suppressKeyPressRepeat flag to avoid handling keypress
		// events when we know the keydown event was used to modify the
		// search term. #7799
		var suppressKeyPress, suppressKeyPressRepeat, suppressInput,
			nodeName = this.element[ 0 ].nodeName.toLowerCase(),
			isTextarea = nodeName === "textarea",
			isInput = nodeName === "input";

		// Textareas are always multi-line
		// Inputs are always single-line, even if inside a contentEditable element
		// IE also treats inputs as contentEditable
		// All other element types are determined by whether or not they're contentEditable
		this.isMultiLine = isTextarea || !isInput && this._isContentEditable( this.element );

		this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ];
		this.isNewMenu = true;

		this._addClass( "ui-autocomplete-input" );
		this.element.attr( "autocomplete", "off" );

		this._on( this.element, {
			keydown: function( event ) {
				if ( this.element.prop( "readOnly" ) ) {
					suppressKeyPress = true;
					suppressInput = true;
					suppressKeyPressRepeat = true;
					return;
				}

				suppressKeyPress = false;
				suppressInput = false;
				suppressKeyPressRepeat = false;
				var keyCode = $.ui.keyCode;
				switch ( event.keyCode ) {
				case keyCode.PAGE_UP:
					suppressKeyPress = true;
					this._move( "previousPage", event );
					break;
				case keyCode.PAGE_DOWN:
					suppressKeyPress = true;
					this._move( "nextPage", event );
					break;
				case keyCode.UP:
					suppressKeyPress = true;
					this._keyEvent( "previous", event );
					break;
				case keyCode.DOWN:
					suppressKeyPress = true;
					this._keyEvent( "next", event );
					break;
				case keyCode.ENTER:

					// when menu is open and has focus
					if ( this.menu.active ) {

						// #6055 - Opera still allows the keypress to occur
						// which causes forms to submit
						suppressKeyPress = true;
						event.preventDefault();
						this.menu.select( event );
					}
					break;
				case keyCode.TAB:
					if ( this.menu.active ) {
						this.menu.select( event );
					}
					break;
				case keyCode.ESCAPE:
					if ( this.menu.element.is( ":visible" ) ) {
						if ( !this.isMultiLine ) {
							this._value( this.term );
						}
						this.close( event );

						// Different browsers have different default behavior for escape
						// Single press can mean undo or clear
						// Double press in IE means clear the whole form
						event.preventDefault();
					}
					break;
				default:
					suppressKeyPressRepeat = true;

					// search timeout should be triggered before the input value is changed
					this._searchTimeout( event );
					break;
				}
			},
			keypress: function( event ) {
				if ( suppressKeyPress ) {
					suppressKeyPress = false;
					if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
						event.preventDefault();
					}
					return;
				}
				if ( suppressKeyPressRepeat ) {
					return;
				}

				// Replicate some key handlers to allow them to repeat in Firefox and Opera
				var keyCode = $.ui.keyCode;
				switch ( event.keyCode ) {
				case keyCode.PAGE_UP:
					this._move( "previousPage", event );
					break;
				case keyCode.PAGE_DOWN:
					this._move( "nextPage", event );
					break;
				case keyCode.UP:
					this._keyEvent( "previous", event );
					break;
				case keyCode.DOWN:
					this._keyEvent( "next", event );
					break;
				}
			},
			input: function( event ) {
				if ( suppressInput ) {
					suppressInput = false;
					event.preventDefault();
					return;
				}
				this._searchTimeout( event );
			},
			focus: function() {
				this.selectedItem = null;
				this.previous = this._value();
			},
			blur: function( event ) {
				clearTimeout( this.searching );
				this.close( event );
				this._change( event );
			}
		} );

		this._initSource();
		this.menu = $( "<ul>" )
			.appendTo( this._appendTo() )
			.menu( {

				// disable ARIA support, the live region takes care of that
				role: null
			} )
			.hide()

			// Support: IE 11 only, Edge <= 14
			// For other browsers, we preventDefault() on the mousedown event
			// to keep the dropdown from taking focus from the input. This doesn't
			// work for IE/Edge, causing problems with selection and scrolling (#9638)
			// Happily, IE and Edge support an "unselectable" attribute that
			// prevents an element from receiving focus, exactly what we want here.
			.attr( {
				"unselectable": "on"
			} )
			.menu( "instance" );

		this._addClass( this.menu.element, "ui-autocomplete", "ui-front" );
		this._on( this.menu.element, {
			mousedown: function( event ) {

				// Prevent moving focus out of the text field
				event.preventDefault();
			},
			menufocus: function( event, ui ) {
				var label, item;

				// support: Firefox
				// Prevent accidental activation of menu items in Firefox (#7024 #9118)
				if ( this.isNewMenu ) {
					this.isNewMenu = false;
					if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {
						this.menu.blur();

						this.document.one( "mousemove", function() {
							$( event.target ).trigger( event.originalEvent );
						} );

						return;
					}
				}

				item = ui.item.data( "ui-autocomplete-item" );
				if ( false !== this._trigger( "focus", event, { item: item } ) ) {

					// use value to match what will end up in the input, if it was a key event
					if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) {
						this._value( item.value );
					}
				}

				// Announce the value in the liveRegion
				label = ui.item.attr( "aria-label" ) || item.value;
				if ( label && String.prototype.trim.call( label ).length ) {
					clearTimeout( this.liveRegionTimer );
					this.liveRegionTimer = this._delay( function() {
						this.liveRegion.html( $( "<div>" ).text( label ) );
					}, 100 );
				}
			},
			menuselect: function( event, ui ) {
				var item = ui.item.data( "ui-autocomplete-item" ),
					previous = this.previous;

				// Only trigger when focus was lost (click on menu)
				if ( this.element[ 0 ] !== $.ui.safeActiveElement( this.document[ 0 ] ) ) {
					this.element.trigger( "focus" );
					this.previous = previous;

					// #6109 - IE triggers two focus events and the second
					// is asynchronous, so we need to reset the previous
					// term synchronously and asynchronously :-(
					this._delay( function() {
						this.previous = previous;
						this.selectedItem = item;
					} );
				}

				if ( false !== this._trigger( "select", event, { item: item } ) ) {
					this._value( item.value );
				}

				// reset the term after the select event
				// this allows custom select handling to work properly
				this.term = this._value();

				this.close( event );
				this.selectedItem = item;
			}
		} );

		this.liveRegion = $( "<div>", {
			role: "status",
			"aria-live": "assertive",
			"aria-relevant": "additions"
		} )
			.appendTo( this.document[ 0 ].body );

		this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" );

		// Turning off autocomplete prevents the browser from remembering the
		// value when navigating through history, so we re-enable autocomplete
		// if the page is unloaded before the widget is destroyed. #7790
		this._on( this.window, {
			beforeunload: function() {
				this.element.removeAttr( "autocomplete" );
			}
		} );
	},

	_destroy: function() {
		clearTimeout( this.searching );
		this.element.removeAttr( "autocomplete" );
		this.menu.element.remove();
		this.liveRegion.remove();
	},

	_setOption: function( key, value ) {
		this._super( key, value );
		if ( key === "source" ) {
			this._initSource();
		}
		if ( key === "appendTo" ) {
			this.menu.element.appendTo( this._appendTo() );
		}
		if ( key === "disabled" && value && this.xhr ) {
			this.xhr.abort();
		}
	},

	_isEventTargetInWidget: function( event ) {
		var menuElement = this.menu.element[ 0 ];

		return event.target === this.element[ 0 ] ||
			event.target === menuElement ||
			$.contains( menuElement, event.target );
	},

	_closeOnClickOutside: function( event ) {
		if ( !this._isEventTargetInWidget( event ) ) {
			this.close();
		}
	},

	_appendTo: function() {
		var element = this.options.appendTo;

		if ( element ) {
			element = element.jquery || element.nodeType ?
				$( element ) :
				this.document.find( element ).eq( 0 );
		}

		if ( !element || !element[ 0 ] ) {
			element = this.element.closest( ".ui-front, dialog" );
		}

		if ( !element.length ) {
			element = this.document[ 0 ].body;
		}

		return element;
	},

	_initSource: function() {
		var array, url,
			that = this;
		if ( Array.isArray( this.options.source ) ) {
			array = this.options.source;
			this.source = function( request, response ) {
				response( $.ui.autocomplete.filter( array, request.term ) );
			};
		} else if ( typeof this.options.source === "string" ) {
			url = this.options.source;
			this.source = function( request, response ) {
				if ( that.xhr ) {
					that.xhr.abort();
				}
				that.xhr = $.ajax( {
					url: url,
					data: request,
					dataType: "json",
					success: function( data ) {
						response( data );
					},
					error: function() {
						response( [] );
					}
				} );
			};
		} else {
			this.source = this.options.source;
		}
	},

	_searchTimeout: function( event ) {
		clearTimeout( this.searching );
		this.searching = this._delay( function() {

			// Search if the value has changed, or if the user retypes the same value (see #7434)
			var equalValues = this.term === this._value(),
				menuVisible = this.menu.element.is( ":visible" ),
				modifierKey = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;

			if ( !equalValues || ( equalValues && !menuVisible && !modifierKey ) ) {
				this.selectedItem = null;
				this.search( null, event );
			}
		}, this.options.delay );
	},

	search: function( value, event ) {
		value = value != null ? value : this._value();

		// Always save the actual value, not the one passed as an argument
		this.term = this._value();

		if ( value.length < this.options.minLength ) {
			return this.close( event );
		}

		if ( this._trigger( "search", event ) === false ) {
			return;
		}

		return this._search( value );
	},

	_search: function( value ) {
		this.pending++;
		this._addClass( "ui-autocomplete-loading" );
		this.cancelSearch = false;

		this.source( { term: value }, this._response() );
	},

	_response: function() {
		var index = ++this.requestIndex;

		return function( content ) {
			if ( index === this.requestIndex ) {
				this.__response( content );
			}

			this.pending--;
			if ( !this.pending ) {
				this._removeClass( "ui-autocomplete-loading" );
			}
		}.bind( this );
	},

	__response: function( content ) {
		if ( content ) {
			content = this._normalize( content );
		}
		this._trigger( "response", null, { content: content } );
		if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
			this._suggest( content );
			this._trigger( "open" );
		} else {

			// use ._close() instead of .close() so we don't cancel future searches
			this._close();
		}
	},

	close: function( event ) {
		this.cancelSearch = true;
		this._close( event );
	},

	_close: function( event ) {

		// Remove the handler that closes the menu on outside clicks
		this._off( this.document, "mousedown" );

		if ( this.menu.element.is( ":visible" ) ) {
			this.menu.element.hide();
			this.menu.blur();
			this.isNewMenu = true;
			this._trigger( "close", event );
		}
	},

	_change: function( event ) {
		if ( this.previous !== this._value() ) {
			this._trigger( "change", event, { item: this.selectedItem } );
		}
	},

	_normalize: function( items ) {

		// assume all items have the right format when the first item is complete
		if ( items.length && items[ 0 ].label && items[ 0 ].value ) {
			return items;
		}
		return $.map( items, function( item ) {
			if ( typeof item === "string" ) {
				return {
					label: item,
					value: item
				};
			}
			return $.extend( {}, item, {
				label: item.label || item.value,
				value: item.value || item.label
			} );
		} );
	},

	_suggest: function( items ) {
		var ul = this.menu.element.empty();
		this._renderMenu( ul, items );
		this.isNewMenu = true;
		this.menu.refresh();

		// Size and position menu
		ul.show();
		this._resizeMenu();
		ul.position( $.extend( {
			of: this.element
		}, this.options.position ) );

		if ( this.options.autoFocus ) {
			this.menu.next();
		}

		// Listen for interactions outside of the widget (#6642)
		this._on( this.document, {
			mousedown: "_closeOnClickOutside"
		} );
	},

	_resizeMenu: function() {
		var ul = this.menu.element;
		ul.outerWidth( Math.max(

			// Firefox wraps long text (possibly a rounding bug)
			// so we add 1px to avoid the wrapping (#7513)
			ul.width( "" ).outerWidth() + 1,
			this.element.outerWidth()
		) );
	},

	_renderMenu: function( ul, items ) {
		var that = this;
		$.each( items, function( index, item ) {
			that._renderItemData( ul, item );
		} );
	},

	_renderItemData: function( ul, item ) {
		return this._renderItem( ul, item ).data( "ui-autocomplete-item", item );
	},

	_renderItem: function( ul, item ) {
		return $( "<li>" )
			.append( $( "<div>" ).text( item.label ) )
			.appendTo( ul );
	},

	_move: function( direction, event ) {
		if ( !this.menu.element.is( ":visible" ) ) {
			this.search( null, event );
			return;
		}
		if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
				this.menu.isLastItem() && /^next/.test( direction ) ) {

			if ( !this.isMultiLine ) {
				this._value( this.term );
			}

			this.menu.blur();
			return;
		}
		this.menu[ direction ]( event );
	},

	widget: function() {
		return this.menu.element;
	},

	_value: function() {
		return this.valueMethod.apply( this.element, arguments );
	},

	_keyEvent: function( keyEvent, event ) {
		if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
			this._move( keyEvent, event );

			// Prevents moving cursor to beginning/end of the text field in some browsers
			event.preventDefault();
		}
	},

	// Support: Chrome <=50
	// We should be able to just use this.element.prop( "isContentEditable" )
	// but hidden elements always report false in Chrome.
	// https://code.google.com/p/chromium/issues/detail?id=313082
	_isContentEditable: function( element ) {
		if ( !element.length ) {
			return false;
		}

		var editable = element.prop( "contentEditable" );

		if ( editable === "inherit" ) {
			return this._isContentEditable( element.parent() );
		}

		return editable === "true";
	}
} );

$.extend( $.ui.autocomplete, {
	escapeRegex: function( value ) {
		return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
	},
	filter: function( array, term ) {
		var matcher = new RegExp( $.ui.autocomplete.escapeRegex( term ), "i" );
		return $.grep( array, function( value ) {
			return matcher.test( value.label || value.value || value );
		} );
	}
} );

// Live region extension, adding a `messages` option
// NOTE: This is an experimental API. We are still investigating
// a full solution for string manipulation and internationalization.
$.widget( "ui.autocomplete", $.ui.autocomplete, {
	options: {
		messages: {
			noResults: "No search results.",
			results: function( amount ) {
				return amount + ( amount > 1 ? " results are" : " result is" ) +
					" available, use up and down arrow keys to navigate.";
			}
		}
	},

	__response: function( content ) {
		var message;
		this._superApply( arguments );
		if ( this.options.disabled || this.cancelSearch ) {
			return;
		}
		if ( content && content.length ) {
			message = this.options.messages.results( content.length );
		} else {
			message = this.options.messages.noResults;
		}
		clearTimeout( this.liveRegionTimer );
		this.liveRegionTimer = this._delay( function() {
			this.liveRegion.html( $( "<div>" ).text( message ) );
		}, 100 );
	}
} );

var widgetsAutocomplete = $.ui.autocomplete;


/*!
 * jQuery UI Controlgroup 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Controlgroup
//>>group: Widgets
//>>description: Visually groups form control widgets
//>>docs: http://api.jqueryui.com/controlgroup/
//>>demos: http://jqueryui.com/controlgroup/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/controlgroup.css
//>>css.theme: ../../themes/base/theme.css


var controlgroupCornerRegex = /ui-corner-([a-z]){2,6}/g;

var widgetsControlgroup = $.widget( "ui.controlgroup", {
	version: "1.13.2",
	defaultElement: "<div>",
	options: {
		direction: "horizontal",
		disabled: null,
		onlyVisible: true,
		items: {
			"button": "input[type=button], input[type=submit], input[type=reset], button, a",
			"controlgroupLabel": ".ui-controlgroup-label",
			"checkboxradio": "input[type='checkbox'], input[type='radio']",
			"selectmenu": "select",
			"spinner": ".ui-spinner-input"
		}
	},

	_create: function() {
		this._enhance();
	},

	// To support the enhanced option in jQuery Mobile, we isolate DOM manipulation
	_enhance: function() {
		this.element.attr( "role", "toolbar" );
		this.refresh();
	},

	_destroy: function() {
		this._callChildMethod( "destroy" );
		this.childWidgets.removeData( "ui-controlgroup-data" );
		this.element.removeAttr( "role" );
		if ( this.options.items.controlgroupLabel ) {
			this.element
				.find( this.options.items.controlgroupLabel )
				.find( ".ui-controlgroup-label-contents" )
				.contents().unwrap();
		}
	},

	_initWidgets: function() {
		var that = this,
			childWidgets = [];

		// First we iterate over each of the items options
		$.each( this.options.items, function( widget, selector ) {
			var labels;
			var options = {};

			// Make sure the widget has a selector set
			if ( !selector ) {
				return;
			}

			if ( widget === "controlgroupLabel" ) {
				labels = that.element.find( selector );
				labels.each( function() {
					var element = $( this );

					if ( element.children( ".ui-controlgroup-label-contents" ).length ) {
						return;
					}
					element.contents()
						.wrapAll( "<span class='ui-controlgroup-label-contents'></span>" );
				} );
				that._addClass( labels, null, "ui-widget ui-widget-content ui-state-default" );
				childWidgets = childWidgets.concat( labels.get() );
				return;
			}

			// Make sure the widget actually exists
			if ( !$.fn[ widget ] ) {
				return;
			}

			// We assume everything is in the middle to start because we can't determine
			// first / last elements until all enhancments are done.
			if ( that[ "_" + widget + "Options" ] ) {
				options = that[ "_" + widget + "Options" ]( "middle" );
			} else {
				options = { classes: {} };
			}

			// Find instances of this widget inside controlgroup and init them
			that.element
				.find( selector )
				.each( function() {
					var element = $( this );
					var instance = element[ widget ]( "instance" );

					// We need to clone the default options for this type of widget to avoid
					// polluting the variable options which has a wider scope than a single widget.
					var instanceOptions = $.widget.extend( {}, options );

					// If the button is the child of a spinner ignore it
					// TODO: Find a more generic solution
					if ( widget === "button" && element.parent( ".ui-spinner" ).length ) {
						return;
					}

					// Create the widget if it doesn't exist
					if ( !instance ) {
						instance = element[ widget ]()[ widget ]( "instance" );
					}
					if ( instance ) {
						instanceOptions.classes =
							that._resolveClassesValues( instanceOptions.classes, instance );
					}
					element[ widget ]( instanceOptions );

					// Store an instance of the controlgroup to be able to reference
					// from the outermost element for changing options and refresh
					var widgetElement = element[ widget ]( "widget" );
					$.data( widgetElement[ 0 ], "ui-controlgroup-data",
						instance ? instance : element[ widget ]( "instance" ) );

					childWidgets.push( widgetElement[ 0 ] );
				} );
		} );

		this.childWidgets = $( $.uniqueSort( childWidgets ) );
		this._addClass( this.childWidgets, "ui-controlgroup-item" );
	},

	_callChildMethod: function( method ) {
		this.childWidgets.each( function() {
			var element = $( this ),
				data = element.data( "ui-controlgroup-data" );
			if ( data && data[ method ] ) {
				data[ method ]();
			}
		} );
	},

	_updateCornerClass: function( element, position ) {
		var remove = "ui-corner-top ui-corner-bottom ui-corner-left ui-corner-right ui-corner-all";
		var add = this._buildSimpleOptions( position, "label" ).classes.label;

		this._removeClass( element, null, remove );
		this._addClass( element, null, add );
	},

	_buildSimpleOptions: function( position, key ) {
		var direction = this.options.direction === "vertical";
		var result = {
			classes: {}
		};
		result.classes[ key ] = {
			"middle": "",
			"first": "ui-corner-" + ( direction ? "top" : "left" ),
			"last": "ui-corner-" + ( direction ? "bottom" : "right" ),
			"only": "ui-corner-all"
		}[ position ];

		return result;
	},

	_spinnerOptions: function( position ) {
		var options = this._buildSimpleOptions( position, "ui-spinner" );

		options.classes[ "ui-spinner-up" ] = "";
		options.classes[ "ui-spinner-down" ] = "";

		return options;
	},

	_buttonOptions: function( position ) {
		return this._buildSimpleOptions( position, "ui-button" );
	},

	_checkboxradioOptions: function( position ) {
		return this._buildSimpleOptions( position, "ui-checkboxradio-label" );
	},

	_selectmenuOptions: function( position ) {
		var direction = this.options.direction === "vertical";
		return {
			width: direction ? "auto" : false,
			classes: {
				middle: {
					"ui-selectmenu-button-open": "",
					"ui-selectmenu-button-closed": ""
				},
				first: {
					"ui-selectmenu-button-open": "ui-corner-" + ( direction ? "top" : "tl" ),
					"ui-selectmenu-button-closed": "ui-corner-" + ( direction ? "top" : "left" )
				},
				last: {
					"ui-selectmenu-button-open": direction ? "" : "ui-corner-tr",
					"ui-selectmenu-button-closed": "ui-corner-" + ( direction ? "bottom" : "right" )
				},
				only: {
					"ui-selectmenu-button-open": "ui-corner-top",
					"ui-selectmenu-button-closed": "ui-corner-all"
				}

			}[ position ]
		};
	},

	_resolveClassesValues: function( classes, instance ) {
		var result = {};
		$.each( classes, function( key ) {
			var current = instance.options.classes[ key ] || "";
			current = String.prototype.trim.call( current.replace( controlgroupCornerRegex, "" ) );
			result[ key ] = ( current + " " + classes[ key ] ).replace( /\s+/g, " " );
		} );
		return result;
	},

	_setOption: function( key, value ) {
		if ( key === "direction" ) {
			this._removeClass( "ui-controlgroup-" + this.options.direction );
		}

		this._super( key, value );
		if ( key === "disabled" ) {
			this._callChildMethod( value ? "disable" : "enable" );
			return;
		}

		this.refresh();
	},

	refresh: function() {
		var children,
			that = this;

		this._addClass( "ui-controlgroup ui-controlgroup-" + this.options.direction );

		if ( this.options.direction === "horizontal" ) {
			this._addClass( null, "ui-helper-clearfix" );
		}
		this._initWidgets();

		children = this.childWidgets;

		// We filter here because we need to track all childWidgets not just the visible ones
		if ( this.options.onlyVisible ) {
			children = children.filter( ":visible" );
		}

		if ( children.length ) {

			// We do this last because we need to make sure all enhancment is done
			// before determining first and last
			$.each( [ "first", "last" ], function( index, value ) {
				var instance = children[ value ]().data( "ui-controlgroup-data" );

				if ( instance && that[ "_" + instance.widgetName + "Options" ] ) {
					var options = that[ "_" + instance.widgetName + "Options" ](
						children.length === 1 ? "only" : value
					);
					options.classes = that._resolveClassesValues( options.classes, instance );
					instance.element[ instance.widgetName ]( options );
				} else {
					that._updateCornerClass( children[ value ](), value );
				}
			} );

			// Finally call the refresh method on each of the child widgets.
			this._callChildMethod( "refresh" );
		}
	}
} );

/*!
 * jQuery UI Checkboxradio 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Checkboxradio
//>>group: Widgets
//>>description: Enhances a form with multiple themeable checkboxes or radio buttons.
//>>docs: http://api.jqueryui.com/checkboxradio/
//>>demos: http://jqueryui.com/checkboxradio/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/button.css
//>>css.structure: ../../themes/base/checkboxradio.css
//>>css.theme: ../../themes/base/theme.css


$.widget( "ui.checkboxradio", [ $.ui.formResetMixin, {
	version: "1.13.2",
	options: {
		disabled: null,
		label: null,
		icon: true,
		classes: {
			"ui-checkboxradio-label": "ui-corner-all",
			"ui-checkboxradio-icon": "ui-corner-all"
		}
	},

	_getCreateOptions: function() {
		var disabled, labels, labelContents;
		var options = this._super() || {};

		// We read the type here, because it makes more sense to throw a element type error first,
		// rather then the error for lack of a label. Often if its the wrong type, it
		// won't have a label (e.g. calling on a div, btn, etc)
		this._readType();

		labels = this.element.labels();

		// If there are multiple labels, use the last one
		this.label = $( labels[ labels.length - 1 ] );
		if ( !this.label.length ) {
			$.error( "No label found for checkboxradio widget" );
		}

		this.originalLabel = "";

		// We need to get the label text but this may also need to make sure it does not contain the
		// input itself.
		// The label contents could be text, html, or a mix. We wrap all elements
		// and read the wrapper's `innerHTML` to get a string representation of
		// the label, without the input as part of it.
		labelContents = this.label.contents().not( this.element[ 0 ] );

		if ( labelContents.length ) {
			this.originalLabel += labelContents
				.clone()
				.wrapAll( "<div></div>" )
				.parent()
				.html();
		}

		// Set the label option if we found label text
		if ( this.originalLabel ) {
			options.label = this.originalLabel;
		}

		disabled = this.element[ 0 ].disabled;
		if ( disabled != null ) {
			options.disabled = disabled;
		}
		return options;
	},

	_create: function() {
		var checked = this.element[ 0 ].checked;

		this._bindFormResetHandler();

		if ( this.options.disabled == null ) {
			this.options.disabled = this.element[ 0 ].disabled;
		}

		this._setOption( "disabled", this.options.disabled );
		this._addClass( "ui-checkboxradio", "ui-helper-hidden-accessible" );
		this._addClass( this.label, "ui-checkboxradio-label", "ui-button ui-widget" );

		if ( this.type === "radio" ) {
			this._addClass( this.label, "ui-checkboxradio-radio-label" );
		}

		if ( this.options.label && this.options.label !== this.originalLabel ) {
			this._updateLabel();
		} else if ( this.originalLabel ) {
			this.options.label = this.originalLabel;
		}

		this._enhance();

		if ( checked ) {
			this._addClass( this.label, "ui-checkboxradio-checked", "ui-state-active" );
		}

		this._on( {
			change: "_toggleClasses",
			focus: function() {
				this._addClass( this.label, null, "ui-state-focus ui-visual-focus" );
			},
			blur: function() {
				this._removeClass( this.label, null, "ui-state-focus ui-visual-focus" );
			}
		} );
	},

	_readType: function() {
		var nodeName = this.element[ 0 ].nodeName.toLowerCase();
		this.type = this.element[ 0 ].type;
		if ( nodeName !== "input" || !/radio|checkbox/.test( this.type ) ) {
			$.error( "Can't create checkboxradio on element.nodeName=" + nodeName +
				" and element.type=" + this.type );
		}
	},

	// Support jQuery Mobile enhanced option
	_enhance: function() {
		this._updateIcon( this.element[ 0 ].checked );
	},

	widget: function() {
		return this.label;
	},

	_getRadioGroup: function() {
		var group;
		var name = this.element[ 0 ].name;
		var nameSelector = "input[name='" + $.escapeSelector( name ) + "']";

		if ( !name ) {
			return $( [] );
		}

		if ( this.form.length ) {
			group = $( this.form[ 0 ].elements ).filter( nameSelector );
		} else {

			// Not inside a form, check all inputs that also are not inside a form
			group = $( nameSelector ).filter( function() {
				return $( this )._form().length === 0;
			} );
		}

		return group.not( this.element );
	},

	_toggleClasses: function() {
		var checked = this.element[ 0 ].checked;
		this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked );

		if ( this.options.icon && this.type === "checkbox" ) {
			this._toggleClass( this.icon, null, "ui-icon-check ui-state-checked", checked )
				._toggleClass( this.icon, null, "ui-icon-blank", !checked );
		}

		if ( this.type === "radio" ) {
			this._getRadioGroup()
				.each( function() {
					var instance = $( this ).checkboxradio( "instance" );

					if ( instance ) {
						instance._removeClass( instance.label,
							"ui-checkboxradio-checked", "ui-state-active" );
					}
				} );
		}
	},

	_destroy: function() {
		this._unbindFormResetHandler();

		if ( this.icon ) {
			this.icon.remove();
			this.iconSpace.remove();
		}
	},

	_setOption: function( key, value ) {

		// We don't allow the value to be set to nothing
		if ( key === "label" && !value ) {
			return;
		}

		this._super( key, value );

		if ( key === "disabled" ) {
			this._toggleClass( this.label, null, "ui-state-disabled", value );
			this.element[ 0 ].disabled = value;

			// Don't refresh when setting disabled
			return;
		}
		this.refresh();
	},

	_updateIcon: function( checked ) {
		var toAdd = "ui-icon ui-icon-background ";

		if ( this.options.icon ) {
			if ( !this.icon ) {
				this.icon = $( "<span>" );
				this.iconSpace = $( "<span> </span>" );
				this._addClass( this.iconSpace, "ui-checkboxradio-icon-space" );
			}

			if ( this.type === "checkbox" ) {
				toAdd += checked ? "ui-icon-check ui-state-checked" : "ui-icon-blank";
				this._removeClass( this.icon, null, checked ? "ui-icon-blank" : "ui-icon-check" );
			} else {
				toAdd += "ui-icon-blank";
			}
			this._addClass( this.icon, "ui-checkboxradio-icon", toAdd );
			if ( !checked ) {
				this._removeClass( this.icon, null, "ui-icon-check ui-state-checked" );
			}
			this.icon.prependTo( this.label ).after( this.iconSpace );
		} else if ( this.icon !== undefined ) {
			this.icon.remove();
			this.iconSpace.remove();
			delete this.icon;
		}
	},

	_updateLabel: function() {

		// Remove the contents of the label ( minus the icon, icon space, and input )
		var contents = this.label.contents().not( this.element[ 0 ] );
		if ( this.icon ) {
			contents = contents.not( this.icon[ 0 ] );
		}
		if ( this.iconSpace ) {
			contents = contents.not( this.iconSpace[ 0 ] );
		}
		contents.remove();

		this.label.append( this.options.label );
	},

	refresh: function() {
		var checked = this.element[ 0 ].checked,
			isDisabled = this.element[ 0 ].disabled;

		this._updateIcon( checked );
		this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked );
		if ( this.options.label !== null ) {
			this._updateLabel();
		}

		if ( isDisabled !== this.options.disabled ) {
			this._setOptions( { "disabled": isDisabled } );
		}
	}

} ] );

var widgetsCheckboxradio = $.ui.checkboxradio;


/*!
 * jQuery UI Button 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Button
//>>group: Widgets
//>>description: Enhances a form with themeable buttons.
//>>docs: http://api.jqueryui.com/button/
//>>demos: http://jqueryui.com/button/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/button.css
//>>css.theme: ../../themes/base/theme.css


$.widget( "ui.button", {
	version: "1.13.2",
	defaultElement: "<button>",
	options: {
		classes: {
			"ui-button": "ui-corner-all"
		},
		disabled: null,
		icon: null,
		iconPosition: "beginning",
		label: null,
		showLabel: true
	},

	_getCreateOptions: function() {
		var disabled,

			// This is to support cases like in jQuery Mobile where the base widget does have
			// an implementation of _getCreateOptions
			options = this._super() || {};

		this.isInput = this.element.is( "input" );

		disabled = this.element[ 0 ].disabled;
		if ( disabled != null ) {
			options.disabled = disabled;
		}

		this.originalLabel = this.isInput ? this.element.val() : this.element.html();
		if ( this.originalLabel ) {
			options.label = this.originalLabel;
		}

		return options;
	},

	_create: function() {
		if ( !this.option.showLabel & !this.options.icon ) {
			this.options.showLabel = true;
		}

		// We have to check the option again here even though we did in _getCreateOptions,
		// because null may have been passed on init which would override what was set in
		// _getCreateOptions
		if ( this.options.disabled == null ) {
			this.options.disabled = this.element[ 0 ].disabled || false;
		}

		this.hasTitle = !!this.element.attr( "title" );

		// Check to see if the label needs to be set or if its already correct
		if ( this.options.label && this.options.label !== this.originalLabel ) {
			if ( this.isInput ) {
				this.element.val( this.options.label );
			} else {
				this.element.html( this.options.label );
			}
		}
		this._addClass( "ui-button", "ui-widget" );
		this._setOption( "disabled", this.options.disabled );
		this._enhance();

		if ( this.element.is( "a" ) ) {
			this._on( {
				"keyup": function( event ) {
					if ( event.keyCode === $.ui.keyCode.SPACE ) {
						event.preventDefault();

						// Support: PhantomJS <= 1.9, IE 8 Only
						// If a native click is available use it so we actually cause navigation
						// otherwise just trigger a click event
						if ( this.element[ 0 ].click ) {
							this.element[ 0 ].click();
						} else {
							this.element.trigger( "click" );
						}
					}
				}
			} );
		}
	},

	_enhance: function() {
		if ( !this.element.is( "button" ) ) {
			this.element.attr( "role", "button" );
		}

		if ( this.options.icon ) {
			this._updateIcon( "icon", this.options.icon );
			this._updateTooltip();
		}
	},

	_updateTooltip: function() {
		this.title = this.element.attr( "title" );

		if ( !this.options.showLabel && !this.title ) {
			this.element.attr( "title", this.options.label );
		}
	},

	_updateIcon: function( option, value ) {
		var icon = option !== "iconPosition",
			position = icon ? this.options.iconPosition : value,
			displayBlock = position === "top" || position === "bottom";

		// Create icon
		if ( !this.icon ) {
			this.icon = $( "<span>" );

			this._addClass( this.icon, "ui-button-icon", "ui-icon" );

			if ( !this.options.showLabel ) {
				this._addClass( "ui-button-icon-only" );
			}
		} else if ( icon ) {

			// If we are updating the icon remove the old icon class
			this._removeClass( this.icon, null, this.options.icon );
		}

		// If we are updating the icon add the new icon class
		if ( icon ) {
			this._addClass( this.icon, null, value );
		}

		this._attachIcon( position );

		// If the icon is on top or bottom we need to add the ui-widget-icon-block class and remove
		// the iconSpace if there is one.
		if ( displayBlock ) {
			this._addClass( this.icon, null, "ui-widget-icon-block" );
			if ( this.iconSpace ) {
				this.iconSpace.remove();
			}
		} else {

			// Position is beginning or end so remove the ui-widget-icon-block class and add the
			// space if it does not exist
			if ( !this.iconSpace ) {
				this.iconSpace = $( "<span> </span>" );
				this._addClass( this.iconSpace, "ui-button-icon-space" );
			}
			this._removeClass( this.icon, null, "ui-wiget-icon-block" );
			this._attachIconSpace( position );
		}
	},

	_destroy: function() {
		this.element.removeAttr( "role" );

		if ( this.icon ) {
			this.icon.remove();
		}
		if ( this.iconSpace ) {
			this.iconSpace.remove();
		}
		if ( !this.hasTitle ) {
			this.element.removeAttr( "title" );
		}
	},

	_attachIconSpace: function( iconPosition ) {
		this.icon[ /^(?:end|bottom)/.test( iconPosition ) ? "before" : "after" ]( this.iconSpace );
	},

	_attachIcon: function( iconPosition ) {
		this.element[ /^(?:end|bottom)/.test( iconPosition ) ? "append" : "prepend" ]( this.icon );
	},

	_setOptions: function( options ) {
		var newShowLabel = options.showLabel === undefined ?
				this.options.showLabel :
				options.showLabel,
			newIcon = options.icon === undefined ? this.options.icon : options.icon;

		if ( !newShowLabel && !newIcon ) {
			options.showLabel = true;
		}
		this._super( options );
	},

	_setOption: function( key, value ) {
		if ( key === "icon" ) {
			if ( value ) {
				this._updateIcon( key, value );
			} else if ( this.icon ) {
				this.icon.remove();
				if ( this.iconSpace ) {
					this.iconSpace.remove();
				}
			}
		}

		if ( key === "iconPosition" ) {
			this._updateIcon( key, value );
		}

		// Make sure we can't end up with a button that has neither text nor icon
		if ( key === "showLabel" ) {
				this._toggleClass( "ui-button-icon-only", null, !value );
				this._updateTooltip();
		}

		if ( key === "label" ) {
			if ( this.isInput ) {
				this.element.val( value );
			} else {

				// If there is an icon, append it, else nothing then append the value
				// this avoids removal of the icon when setting label text
				this.element.html( value );
				if ( this.icon ) {
					this._attachIcon( this.options.iconPosition );
					this._attachIconSpace( this.options.iconPosition );
				}
			}
		}

		this._super( key, value );

		if ( key === "disabled" ) {
			this._toggleClass( null, "ui-state-disabled", value );
			this.element[ 0 ].disabled = value;
			if ( value ) {
				this.element.trigger( "blur" );
			}
		}
	},

	refresh: function() {

		// Make sure to only check disabled if its an element that supports this otherwise
		// check for the disabled class to determine state
		var isDisabled = this.element.is( "input, button" ) ?
			this.element[ 0 ].disabled : this.element.hasClass( "ui-button-disabled" );

		if ( isDisabled !== this.options.disabled ) {
			this._setOptions( { disabled: isDisabled } );
		}

		this._updateTooltip();
	}
} );

// DEPRECATED
if ( $.uiBackCompat !== false ) {

	// Text and Icons options
	$.widget( "ui.button", $.ui.button, {
		options: {
			text: true,
			icons: {
				primary: null,
				secondary: null
			}
		},

		_create: function() {
			if ( this.options.showLabel && !this.options.text ) {
				this.options.showLabel = this.options.text;
			}
			if ( !this.options.showLabel && this.options.text ) {
				this.options.text = this.options.showLabel;
			}
			if ( !this.options.icon && ( this.options.icons.primary ||
					this.options.icons.secondary ) ) {
				if ( this.options.icons.primary ) {
					this.options.icon = this.options.icons.primary;
				} else {
					this.options.icon = this.options.icons.secondary;
					this.options.iconPosition = "end";
				}
			} else if ( this.options.icon ) {
				this.options.icons.primary = this.options.icon;
			}
			this._super();
		},

		_setOption: function( key, value ) {
			if ( key === "text" ) {
				this._super( "showLabel", value );
				return;
			}
			if ( key === "showLabel" ) {
				this.options.text = value;
			}
			if ( key === "icon" ) {
				this.options.icons.primary = value;
			}
			if ( key === "icons" ) {
				if ( value.primary ) {
					this._super( "icon", value.primary );
					this._super( "iconPosition", "beginning" );
				} else if ( value.secondary ) {
					this._super( "icon", value.secondary );
					this._super( "iconPosition", "end" );
				}
			}
			this._superApply( arguments );
		}
	} );

	$.fn.button = ( function( orig ) {
		return function( options ) {
			var isMethodCall = typeof options === "string";
			var args = Array.prototype.slice.call( arguments, 1 );
			var returnValue = this;

			if ( isMethodCall ) {

				// If this is an empty collection, we need to have the instance method
				// return undefined instead of the jQuery instance
				if ( !this.length && options === "instance" ) {
					returnValue = undefined;
				} else {
					this.each( function() {
						var methodValue;
						var type = $( this ).attr( "type" );
						var name = type !== "checkbox" && type !== "radio" ?
							"button" :
							"checkboxradio";
						var instance = $.data( this, "ui-" + name );

						if ( options === "instance" ) {
							returnValue = instance;
							return false;
						}

						if ( !instance ) {
							return $.error( "cannot call methods on button" +
								" prior to initialization; " +
								"attempted to call method '" + options + "'" );
						}

						if ( typeof instance[ options ] !== "function" ||
							options.charAt( 0 ) === "_" ) {
							return $.error( "no such method '" + options + "' for button" +
								" widget instance" );
						}

						methodValue = instance[ options ].apply( instance, args );

						if ( methodValue !== instance && methodValue !== undefined ) {
							returnValue = methodValue && methodValue.jquery ?
								returnValue.pushStack( methodValue.get() ) :
								methodValue;
							return false;
						}
					} );
				}
			} else {

				// Allow multiple hashes to be passed on init
				if ( args.length ) {
					options = $.widget.extend.apply( null, [ options ].concat( args ) );
				}

				this.each( function() {
					var type = $( this ).attr( "type" );
					var name = type !== "checkbox" && type !== "radio" ? "button" : "checkboxradio";
					var instance = $.data( this, "ui-" + name );

					if ( instance ) {
						instance.option( options || {} );
						if ( instance._init ) {
							instance._init();
						}
					} else {
						if ( name === "button" ) {
							orig.call( $( this ), options );
							return;
						}

						$( this ).checkboxradio( $.extend( { icon: false }, options ) );
					}
				} );
			}

			return returnValue;
		};
	} )( $.fn.button );

	$.fn.buttonset = function() {
		if ( !$.ui.controlgroup ) {
			$.error( "Controlgroup widget missing" );
		}
		if ( arguments[ 0 ] === "option" && arguments[ 1 ] === "items" && arguments[ 2 ] ) {
			return this.controlgroup.apply( this,
				[ arguments[ 0 ], "items.button", arguments[ 2 ] ] );
		}
		if ( arguments[ 0 ] === "option" && arguments[ 1 ] === "items" ) {
			return this.controlgroup.apply( this, [ arguments[ 0 ], "items.button" ] );
		}
		if ( typeof arguments[ 0 ] === "object" && arguments[ 0 ].items ) {
			arguments[ 0 ].items = {
				button: arguments[ 0 ].items
			};
		}
		return this.controlgroup.apply( this, arguments );
	};
}

var widgetsButton = $.ui.button;


/* eslint-disable max-len, camelcase */
/*!
 * jQuery UI Datepicker 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Datepicker
//>>group: Widgets
//>>description: Displays a calendar from an input or inline for selecting dates.
//>>docs: http://api.jqueryui.com/datepicker/
//>>demos: http://jqueryui.com/datepicker/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/datepicker.css
//>>css.theme: ../../themes/base/theme.css


$.extend( $.ui, { datepicker: { version: "1.13.2" } } );

var datepicker_instActive;

function datepicker_getZindex( elem ) {
	var position, value;
	while ( elem.length && elem[ 0 ] !== document ) {

		// Ignore z-index if position is set to a value where z-index is ignored by the browser
		// This makes behavior of this function consistent across browsers
		// WebKit always returns auto if the element is positioned
		position = elem.css( "position" );
		if ( position === "absolute" || position === "relative" || position === "fixed" ) {

			// IE returns 0 when zIndex is not specified
			// other browsers return a string
			// we ignore the case of nested elements with an explicit value of 0
			// <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
			value = parseInt( elem.css( "zIndex" ), 10 );
			if ( !isNaN( value ) && value !== 0 ) {
				return value;
			}
		}
		elem = elem.parent();
	}

	return 0;
}

/* Date picker manager.
   Use the singleton instance of this class, $.datepicker, to interact with the date picker.
   Settings for (groups of) date pickers are maintained in an instance object,
   allowing multiple different settings on the same page. */

function Datepicker() {
	this._curInst = null; // The current instance in use
	this._keyEvent = false; // If the last event was a key event
	this._disabledInputs = []; // List of date picker inputs that have been disabled
	this._datepickerShowing = false; // True if the popup picker is showing , false if not
	this._inDialog = false; // True if showing within a "dialog", false if not
	this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
	this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
	this._appendClass = "ui-datepicker-append"; // The name of the append marker class
	this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
	this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
	this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
	this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
	this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
	this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
	this.regional = []; // Available regional settings, indexed by language code
	this.regional[ "" ] = { // Default regional settings
		closeText: "Done", // Display text for close link
		prevText: "Prev", // Display text for previous month link
		nextText: "Next", // Display text for next month link
		currentText: "Today", // Display text for current month link
		monthNames: [ "January", "February", "March", "April", "May", "June",
			"July", "August", "September", "October", "November", "December" ], // Names of months for drop-down and formatting
		monthNamesShort: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ], // For formatting
		dayNames: [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], // For formatting
		dayNamesShort: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], // For formatting
		dayNamesMin: [ "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa" ], // Column headings for days starting at Sunday
		weekHeader: "Wk", // Column header for week of the year
		dateFormat: "mm/dd/yy", // See format options on parseDate
		firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
		isRTL: false, // True if right-to-left language, false if left-to-right
		showMonthAfterYear: false, // True if the year select precedes month, false for month then year
		yearSuffix: "", // Additional text to append to the year in the month headers,
		selectMonthLabel: "Select month", // Invisible label for month selector
		selectYearLabel: "Select year" // Invisible label for year selector
	};
	this._defaults = { // Global defaults for all the date picker instances
		showOn: "focus", // "focus" for popup on focus,
			// "button" for trigger button, or "both" for either
		showAnim: "fadeIn", // Name of jQuery animation for popup
		showOptions: {}, // Options for enhanced animations
		defaultDate: null, // Used when field is blank: actual date,
			// +/-number for offset from today, null for today
		appendText: "", // Display text following the input box, e.g. showing the format
		buttonText: "...", // Text for trigger button
		buttonImage: "", // URL for trigger button image
		buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
		hideIfNoPrevNext: false, // True to hide next/previous month links
			// if not applicable, false to just disable them
		navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
		gotoCurrent: false, // True if today link goes back to current selection instead
		changeMonth: false, // True if month can be selected directly, false if only prev/next
		changeYear: false, // True if year can be selected directly, false if only prev/next
		yearRange: "c-10:c+10", // Range of years to display in drop-down,
			// either relative to today's year (-nn:+nn), relative to currently displayed year
			// (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
		showOtherMonths: false, // True to show dates in other months, false to leave blank
		selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
		showWeek: false, // True to show week of the year, false to not show it
		calculateWeek: this.iso8601Week, // How to calculate the week of the year,
			// takes a Date and returns the number of the week for it
		shortYearCutoff: "+10", // Short year values < this are in the current century,
			// > this are in the previous century,
			// string value starting with "+" for current year + value
		minDate: null, // The earliest selectable date, or null for no limit
		maxDate: null, // The latest selectable date, or null for no limit
		duration: "fast", // Duration of display/closure
		beforeShowDay: null, // Function that takes a date and returns an array with
			// [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
			// [2] = cell title (optional), e.g. $.datepicker.noWeekends
		beforeShow: null, // Function that takes an input field and
			// returns a set of custom settings for the date picker
		onSelect: null, // Define a callback function when a date is selected
		onChangeMonthYear: null, // Define a callback function when the month or year is changed
		onClose: null, // Define a callback function when the datepicker is closed
		onUpdateDatepicker: null, // Define a callback function when the datepicker is updated
		numberOfMonths: 1, // Number of months to show at a time
		showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
		stepMonths: 1, // Number of months to step back/forward
		stepBigMonths: 12, // Number of months to step back/forward for the big links
		altField: "", // Selector for an alternate field to store selected dates into
		altFormat: "", // The date format to use for the alternate field
		constrainInput: true, // The input is constrained by the current date format
		showButtonPanel: false, // True to show button panel, false to not show it
		autoSize: false, // True to size the input for the date format, false to leave as is
		disabled: false // The initial disabled state
	};
	$.extend( this._defaults, this.regional[ "" ] );
	this.regional.en = $.extend( true, {}, this.regional[ "" ] );
	this.regional[ "en-US" ] = $.extend( true, {}, this.regional.en );
	this.dpDiv = datepicker_bindHover( $( "<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) );
}

$.extend( Datepicker.prototype, {

	/* Class name added to elements to indicate already configured with a date picker. */
	markerClassName: "hasDatepicker",

	//Keep track of the maximum number of rows displayed (see #7043)
	maxRows: 4,

	// TODO rename to "widget" when switching to widget factory
	_widgetDatepicker: function() {
		return this.dpDiv;
	},

	/* Override the default settings for all instances of the date picker.
	 * @param  settings  object - the new settings to use as defaults (anonymous object)
	 * @return the manager object
	 */
	setDefaults: function( settings ) {
		datepicker_extendRemove( this._defaults, settings || {} );
		return this;
	},

	/* Attach the date picker to a jQuery selection.
	 * @param  target	element - the target input field or division or span
	 * @param  settings  object - the new settings to use for this date picker instance (anonymous)
	 */
	_attachDatepicker: function( target, settings ) {
		var nodeName, inline, inst;
		nodeName = target.nodeName.toLowerCase();
		inline = ( nodeName === "div" || nodeName === "span" );
		if ( !target.id ) {
			this.uuid += 1;
			target.id = "dp" + this.uuid;
		}
		inst = this._newInst( $( target ), inline );
		inst.settings = $.extend( {}, settings || {} );
		if ( nodeName === "input" ) {
			this._connectDatepicker( target, inst );
		} else if ( inline ) {
			this._inlineDatepicker( target, inst );
		}
	},

	/* Create a new instance object. */
	_newInst: function( target, inline ) {
		var id = target[ 0 ].id.replace( /([^A-Za-z0-9_\-])/g, "\\\\$1" ); // escape jQuery meta chars
		return { id: id, input: target, // associated target
			selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
			drawMonth: 0, drawYear: 0, // month being drawn
			inline: inline, // is datepicker inline or not
			dpDiv: ( !inline ? this.dpDiv : // presentation div
			datepicker_bindHover( $( "<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) ) ) };
	},

	/* Attach the date picker to an input field. */
	_connectDatepicker: function( target, inst ) {
		var input = $( target );
		inst.append = $( [] );
		inst.trigger = $( [] );
		if ( input.hasClass( this.markerClassName ) ) {
			return;
		}
		this._attachments( input, inst );
		input.addClass( this.markerClassName ).on( "keydown", this._doKeyDown ).
			on( "keypress", this._doKeyPress ).on( "keyup", this._doKeyUp );
		this._autoSize( inst );
		$.data( target, "datepicker", inst );

		//If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
		if ( inst.settings.disabled ) {
			this._disableDatepicker( target );
		}
	},

	/* Make attachments based on settings. */
	_attachments: function( input, inst ) {
		var showOn, buttonText, buttonImage,
			appendText = this._get( inst, "appendText" ),
			isRTL = this._get( inst, "isRTL" );

		if ( inst.append ) {
			inst.append.remove();
		}
		if ( appendText ) {
			inst.append = $( "<span>" )
				.addClass( this._appendClass )
				.text( appendText );
			input[ isRTL ? "before" : "after" ]( inst.append );
		}

		input.off( "focus", this._showDatepicker );

		if ( inst.trigger ) {
			inst.trigger.remove();
		}

		showOn = this._get( inst, "showOn" );
		if ( showOn === "focus" || showOn === "both" ) { // pop-up date picker when in the marked field
			input.on( "focus", this._showDatepicker );
		}
		if ( showOn === "button" || showOn === "both" ) { // pop-up date picker when button clicked
			buttonText = this._get( inst, "buttonText" );
			buttonImage = this._get( inst, "buttonImage" );

			if ( this._get( inst, "buttonImageOnly" ) ) {
				inst.trigger = $( "<img>" )
					.addClass( this._triggerClass )
					.attr( {
						src: buttonImage,
						alt: buttonText,
						title: buttonText
					} );
			} else {
				inst.trigger = $( "<button type='button'>" )
					.addClass( this._triggerClass );
				if ( buttonImage ) {
					inst.trigger.html(
						$( "<img>" )
							.attr( {
								src: buttonImage,
								alt: buttonText,
								title: buttonText
							} )
					);
				} else {
					inst.trigger.text( buttonText );
				}
			}

			input[ isRTL ? "before" : "after" ]( inst.trigger );
			inst.trigger.on( "click", function() {
				if ( $.datepicker._datepickerShowing && $.datepicker._lastInput === input[ 0 ] ) {
					$.datepicker._hideDatepicker();
				} else if ( $.datepicker._datepickerShowing && $.datepicker._lastInput !== input[ 0 ] ) {
					$.datepicker._hideDatepicker();
					$.datepicker._showDatepicker( input[ 0 ] );
				} else {
					$.datepicker._showDatepicker( input[ 0 ] );
				}
				return false;
			} );
		}
	},

	/* Apply the maximum length for the date format. */
	_autoSize: function( inst ) {
		if ( this._get( inst, "autoSize" ) && !inst.inline ) {
			var findMax, max, maxI, i,
				date = new Date( 2009, 12 - 1, 20 ), // Ensure double digits
				dateFormat = this._get( inst, "dateFormat" );

			if ( dateFormat.match( /[DM]/ ) ) {
				findMax = function( names ) {
					max = 0;
					maxI = 0;
					for ( i = 0; i < names.length; i++ ) {
						if ( names[ i ].length > max ) {
							max = names[ i ].length;
							maxI = i;
						}
					}
					return maxI;
				};
				date.setMonth( findMax( this._get( inst, ( dateFormat.match( /MM/ ) ?
					"monthNames" : "monthNamesShort" ) ) ) );
				date.setDate( findMax( this._get( inst, ( dateFormat.match( /DD/ ) ?
					"dayNames" : "dayNamesShort" ) ) ) + 20 - date.getDay() );
			}
			inst.input.attr( "size", this._formatDate( inst, date ).length );
		}
	},

	/* Attach an inline date picker to a div. */
	_inlineDatepicker: function( target, inst ) {
		var divSpan = $( target );
		if ( divSpan.hasClass( this.markerClassName ) ) {
			return;
		}
		divSpan.addClass( this.markerClassName ).append( inst.dpDiv );
		$.data( target, "datepicker", inst );
		this._setDate( inst, this._getDefaultDate( inst ), true );
		this._updateDatepicker( inst );
		this._updateAlternate( inst );

		//If disabled option is true, disable the datepicker before showing it (see ticket #5665)
		if ( inst.settings.disabled ) {
			this._disableDatepicker( target );
		}

		// Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
		// http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
		inst.dpDiv.css( "display", "block" );
	},

	/* Pop-up the date picker in a "dialog" box.
	 * @param  input element - ignored
	 * @param  date	string or Date - the initial date to display
	 * @param  onSelect  function - the function to call when a date is selected
	 * @param  settings  object - update the dialog date picker instance's settings (anonymous object)
	 * @param  pos int[2] - coordinates for the dialog's position within the screen or
	 *					event - with x/y coordinates or
	 *					leave empty for default (screen centre)
	 * @return the manager object
	 */
	_dialogDatepicker: function( input, date, onSelect, settings, pos ) {
		var id, browserWidth, browserHeight, scrollX, scrollY,
			inst = this._dialogInst; // internal instance

		if ( !inst ) {
			this.uuid += 1;
			id = "dp" + this.uuid;
			this._dialogInput = $( "<input type='text' id='" + id +
				"' style='position: absolute; top: -100px; width: 0px;'/>" );
			this._dialogInput.on( "keydown", this._doKeyDown );
			$( "body" ).append( this._dialogInput );
			inst = this._dialogInst = this._newInst( this._dialogInput, false );
			inst.settings = {};
			$.data( this._dialogInput[ 0 ], "datepicker", inst );
		}
		datepicker_extendRemove( inst.settings, settings || {} );
		date = ( date && date.constructor === Date ? this._formatDate( inst, date ) : date );
		this._dialogInput.val( date );

		this._pos = ( pos ? ( pos.length ? pos : [ pos.pageX, pos.pageY ] ) : null );
		if ( !this._pos ) {
			browserWidth = document.documentElement.clientWidth;
			browserHeight = document.documentElement.clientHeight;
			scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
			scrollY = document.documentElement.scrollTop || document.body.scrollTop;
			this._pos = // should use actual width/height below
				[ ( browserWidth / 2 ) - 100 + scrollX, ( browserHeight / 2 ) - 150 + scrollY ];
		}

		// Move input on screen for focus, but hidden behind dialog
		this._dialogInput.css( "left", ( this._pos[ 0 ] + 20 ) + "px" ).css( "top", this._pos[ 1 ] + "px" );
		inst.settings.onSelect = onSelect;
		this._inDialog = true;
		this.dpDiv.addClass( this._dialogClass );
		this._showDatepicker( this._dialogInput[ 0 ] );
		if ( $.blockUI ) {
			$.blockUI( this.dpDiv );
		}
		$.data( this._dialogInput[ 0 ], "datepicker", inst );
		return this;
	},

	/* Detach a datepicker from its control.
	 * @param  target	element - the target input field or division or span
	 */
	_destroyDatepicker: function( target ) {
		var nodeName,
			$target = $( target ),
			inst = $.data( target, "datepicker" );

		if ( !$target.hasClass( this.markerClassName ) ) {
			return;
		}

		nodeName = target.nodeName.toLowerCase();
		$.removeData( target, "datepicker" );
		if ( nodeName === "input" ) {
			inst.append.remove();
			inst.trigger.remove();
			$target.removeClass( this.markerClassName ).
				off( "focus", this._showDatepicker ).
				off( "keydown", this._doKeyDown ).
				off( "keypress", this._doKeyPress ).
				off( "keyup", this._doKeyUp );
		} else if ( nodeName === "div" || nodeName === "span" ) {
			$target.removeClass( this.markerClassName ).empty();
		}

		if ( datepicker_instActive === inst ) {
			datepicker_instActive = null;
			this._curInst = null;
		}
	},

	/* Enable the date picker to a jQuery selection.
	 * @param  target	element - the target input field or division or span
	 */
	_enableDatepicker: function( target ) {
		var nodeName, inline,
			$target = $( target ),
			inst = $.data( target, "datepicker" );

		if ( !$target.hasClass( this.markerClassName ) ) {
			return;
		}

		nodeName = target.nodeName.toLowerCase();
		if ( nodeName === "input" ) {
			target.disabled = false;
			inst.trigger.filter( "button" ).
				each( function() {
					this.disabled = false;
				} ).end().
				filter( "img" ).css( { opacity: "1.0", cursor: "" } );
		} else if ( nodeName === "div" || nodeName === "span" ) {
			inline = $target.children( "." + this._inlineClass );
			inline.children().removeClass( "ui-state-disabled" );
			inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ).
				prop( "disabled", false );
		}
		this._disabledInputs = $.map( this._disabledInputs,

			// Delete entry
			function( value ) {
				return ( value === target ? null : value );
			} );
	},

	/* Disable the date picker to a jQuery selection.
	 * @param  target	element - the target input field or division or span
	 */
	_disableDatepicker: function( target ) {
		var nodeName, inline,
			$target = $( target ),
			inst = $.data( target, "datepicker" );

		if ( !$target.hasClass( this.markerClassName ) ) {
			return;
		}

		nodeName = target.nodeName.toLowerCase();
		if ( nodeName === "input" ) {
			target.disabled = true;
			inst.trigger.filter( "button" ).
				each( function() {
					this.disabled = true;
				} ).end().
				filter( "img" ).css( { opacity: "0.5", cursor: "default" } );
		} else if ( nodeName === "div" || nodeName === "span" ) {
			inline = $target.children( "." + this._inlineClass );
			inline.children().addClass( "ui-state-disabled" );
			inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ).
				prop( "disabled", true );
		}
		this._disabledInputs = $.map( this._disabledInputs,

			// Delete entry
			function( value ) {
				return ( value === target ? null : value );
			} );
		this._disabledInputs[ this._disabledInputs.length ] = target;
	},

	/* Is the first field in a jQuery collection disabled as a datepicker?
	 * @param  target	element - the target input field or division or span
	 * @return boolean - true if disabled, false if enabled
	 */
	_isDisabledDatepicker: function( target ) {
		if ( !target ) {
			return false;
		}
		for ( var i = 0; i < this._disabledInputs.length; i++ ) {
			if ( this._disabledInputs[ i ] === target ) {
				return true;
			}
		}
		return false;
	},

	/* Retrieve the instance data for the target control.
	 * @param  target  element - the target input field or division or span
	 * @return  object - the associated instance data
	 * @throws  error if a jQuery problem getting data
	 */
	_getInst: function( target ) {
		try {
			return $.data( target, "datepicker" );
		} catch ( err ) {
			throw "Missing instance data for this datepicker";
		}
	},

	/* Update or retrieve the settings for a date picker attached to an input field or division.
	 * @param  target  element - the target input field or division or span
	 * @param  name	object - the new settings to update or
	 *				string - the name of the setting to change or retrieve,
	 *				when retrieving also "all" for all instance settings or
	 *				"defaults" for all global defaults
	 * @param  value   any - the new value for the setting
	 *				(omit if above is an object or to retrieve a value)
	 */
	_optionDatepicker: function( target, name, value ) {
		var settings, date, minDate, maxDate,
			inst = this._getInst( target );

		if ( arguments.length === 2 && typeof name === "string" ) {
			return ( name === "defaults" ? $.extend( {}, $.datepicker._defaults ) :
				( inst ? ( name === "all" ? $.extend( {}, inst.settings ) :
				this._get( inst, name ) ) : null ) );
		}

		settings = name || {};
		if ( typeof name === "string" ) {
			settings = {};
			settings[ name ] = value;
		}

		if ( inst ) {
			if ( this._curInst === inst ) {
				this._hideDatepicker();
			}

			date = this._getDateDatepicker( target, true );
			minDate = this._getMinMaxDate( inst, "min" );
			maxDate = this._getMinMaxDate( inst, "max" );
			datepicker_extendRemove( inst.settings, settings );

			// reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
			if ( minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined ) {
				inst.settings.minDate = this._formatDate( inst, minDate );
			}
			if ( maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined ) {
				inst.settings.maxDate = this._formatDate( inst, maxDate );
			}
			if ( "disabled" in settings ) {
				if ( settings.disabled ) {
					this._disableDatepicker( target );
				} else {
					this._enableDatepicker( target );
				}
			}
			this._attachments( $( target ), inst );
			this._autoSize( inst );
			this._setDate( inst, date );
			this._updateAlternate( inst );
			this._updateDatepicker( inst );
		}
	},

	// Change method deprecated
	_changeDatepicker: function( target, name, value ) {
		this._optionDatepicker( target, name, value );
	},

	/* Redraw the date picker attached to an input field or division.
	 * @param  target  element - the target input field or division or span
	 */
	_refreshDatepicker: function( target ) {
		var inst = this._getInst( target );
		if ( inst ) {
			this._updateDatepicker( inst );
		}
	},

	/* Set the dates for a jQuery selection.
	 * @param  target element - the target input field or division or span
	 * @param  date	Date - the new date
	 */
	_setDateDatepicker: function( target, date ) {
		var inst = this._getInst( target );
		if ( inst ) {
			this._setDate( inst, date );
			this._updateDatepicker( inst );
			this._updateAlternate( inst );
		}
	},

	/* Get the date(s) for the first entry in a jQuery selection.
	 * @param  target element - the target input field or division or span
	 * @param  noDefault boolean - true if no default date is to be used
	 * @return Date - the current date
	 */
	_getDateDatepicker: function( target, noDefault ) {
		var inst = this._getInst( target );
		if ( inst && !inst.inline ) {
			this._setDateFromField( inst, noDefault );
		}
		return ( inst ? this._getDate( inst ) : null );
	},

	/* Handle keystrokes. */
	_doKeyDown: function( event ) {
		var onSelect, dateStr, sel,
			inst = $.datepicker._getInst( event.target ),
			handled = true,
			isRTL = inst.dpDiv.is( ".ui-datepicker-rtl" );

		inst._keyEvent = true;
		if ( $.datepicker._datepickerShowing ) {
			switch ( event.keyCode ) {
				case 9: $.datepicker._hideDatepicker();
						handled = false;
						break; // hide on tab out
				case 13: sel = $( "td." + $.datepicker._dayOverClass + ":not(." +
									$.datepicker._currentClass + ")", inst.dpDiv );
						if ( sel[ 0 ] ) {
							$.datepicker._selectDay( event.target, inst.selectedMonth, inst.selectedYear, sel[ 0 ] );
						}

						onSelect = $.datepicker._get( inst, "onSelect" );
						if ( onSelect ) {
							dateStr = $.datepicker._formatDate( inst );

							// Trigger custom callback
							onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] );
						} else {
							$.datepicker._hideDatepicker();
						}

						return false; // don't submit the form
				case 27: $.datepicker._hideDatepicker();
						break; // hide on escape
				case 33: $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
							-$.datepicker._get( inst, "stepBigMonths" ) :
							-$.datepicker._get( inst, "stepMonths" ) ), "M" );
						break; // previous month/year on page up/+ ctrl
				case 34: $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
							+$.datepicker._get( inst, "stepBigMonths" ) :
							+$.datepicker._get( inst, "stepMonths" ) ), "M" );
						break; // next month/year on page down/+ ctrl
				case 35: if ( event.ctrlKey || event.metaKey ) {
							$.datepicker._clearDate( event.target );
						}
						handled = event.ctrlKey || event.metaKey;
						break; // clear on ctrl or command +end
				case 36: if ( event.ctrlKey || event.metaKey ) {
							$.datepicker._gotoToday( event.target );
						}
						handled = event.ctrlKey || event.metaKey;
						break; // current on ctrl or command +home
				case 37: if ( event.ctrlKey || event.metaKey ) {
							$.datepicker._adjustDate( event.target, ( isRTL ? +1 : -1 ), "D" );
						}
						handled = event.ctrlKey || event.metaKey;

						// -1 day on ctrl or command +left
						if ( event.originalEvent.altKey ) {
							$.datepicker._adjustDate( event.target, ( event.ctrlKey ?
								-$.datepicker._get( inst, "stepBigMonths" ) :
								-$.datepicker._get( inst, "stepMonths" ) ), "M" );
						}

						// next month/year on alt +left on Mac
						break;
				case 38: if ( event.ctrlKey || event.metaKey ) {
							$.datepicker._adjustDate( event.target, -7, "D" );
						}
						handled = event.ctrlKey || event.metaKey;
						break; // -1 week on ctrl or command +up
				case 39: if ( event.ctrlKey || event.metaKey ) {
							$.datepicker._adjustDate( event.target, ( isRTL ? -1 : +1 ), "D" );
						}
						handled = event.ctrlKey || event.metaKey;

						// +1 day on ctrl or command +right
						if ( event.originalEvent.altKey ) {
							$.datepicker._adjustDate( event.target, ( event.ctrlKey ?
								+$.datepicker._get( inst, "stepBigMonths" ) :
								+$.datepicker._get( inst, "stepMonths" ) ), "M" );
						}

						// next month/year on alt +right
						break;
				case 40: if ( event.ctrlKey || event.metaKey ) {
							$.datepicker._adjustDate( event.target, +7, "D" );
						}
						handled = event.ctrlKey || event.metaKey;
						break; // +1 week on ctrl or command +down
				default: handled = false;
			}
		} else if ( event.keyCode === 36 && event.ctrlKey ) { // display the date picker on ctrl+home
			$.datepicker._showDatepicker( this );
		} else {
			handled = false;
		}

		if ( handled ) {
			event.preventDefault();
			event.stopPropagation();
		}
	},

	/* Filter entered characters - based on date format. */
	_doKeyPress: function( event ) {
		var chars, chr,
			inst = $.datepicker._getInst( event.target );

		if ( $.datepicker._get( inst, "constrainInput" ) ) {
			chars = $.datepicker._possibleChars( $.datepicker._get( inst, "dateFormat" ) );
			chr = String.fromCharCode( event.charCode == null ? event.keyCode : event.charCode );
			return event.ctrlKey || event.metaKey || ( chr < " " || !chars || chars.indexOf( chr ) > -1 );
		}
	},

	/* Synchronise manual entry and field/alternate field. */
	_doKeyUp: function( event ) {
		var date,
			inst = $.datepicker._getInst( event.target );

		if ( inst.input.val() !== inst.lastVal ) {
			try {
				date = $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ),
					( inst.input ? inst.input.val() : null ),
					$.datepicker._getFormatConfig( inst ) );

				if ( date ) { // only if valid
					$.datepicker._setDateFromField( inst );
					$.datepicker._updateAlternate( inst );
					$.datepicker._updateDatepicker( inst );
				}
			} catch ( err ) {
			}
		}
		return true;
	},

	/* Pop-up the date picker for a given input field.
	 * If false returned from beforeShow event handler do not show.
	 * @param  input  element - the input field attached to the date picker or
	 *					event - if triggered by focus
	 */
	_showDatepicker: function( input ) {
		input = input.target || input;
		if ( input.nodeName.toLowerCase() !== "input" ) { // find from button/image trigger
			input = $( "input", input.parentNode )[ 0 ];
		}

		if ( $.datepicker._isDisabledDatepicker( input ) || $.datepicker._lastInput === input ) { // already here
			return;
		}

		var inst, beforeShow, beforeShowSettings, isFixed,
			offset, showAnim, duration;

		inst = $.datepicker._getInst( input );
		if ( $.datepicker._curInst && $.datepicker._curInst !== inst ) {
			$.datepicker._curInst.dpDiv.stop( true, true );
			if ( inst && $.datepicker._datepickerShowing ) {
				$.datepicker._hideDatepicker( $.datepicker._curInst.input[ 0 ] );
			}
		}

		beforeShow = $.datepicker._get( inst, "beforeShow" );
		beforeShowSettings = beforeShow ? beforeShow.apply( input, [ input, inst ] ) : {};
		if ( beforeShowSettings === false ) {
			return;
		}
		datepicker_extendRemove( inst.settings, beforeShowSettings );

		inst.lastVal = null;
		$.datepicker._lastInput = input;
		$.datepicker._setDateFromField( inst );

		if ( $.datepicker._inDialog ) { // hide cursor
			input.value = "";
		}
		if ( !$.datepicker._pos ) { // position below input
			$.datepicker._pos = $.datepicker._findPos( input );
			$.datepicker._pos[ 1 ] += input.offsetHeight; // add the height
		}

		isFixed = false;
		$( input ).parents().each( function() {
			isFixed |= $( this ).css( "position" ) === "fixed";
			return !isFixed;
		} );

		offset = { left: $.datepicker._pos[ 0 ], top: $.datepicker._pos[ 1 ] };
		$.datepicker._pos = null;

		//to avoid flashes on Firefox
		inst.dpDiv.empty();

		// determine sizing offscreen
		inst.dpDiv.css( { position: "absolute", display: "block", top: "-1000px" } );
		$.datepicker._updateDatepicker( inst );

		// fix width for dynamic number of date pickers
		// and adjust position before showing
		offset = $.datepicker._checkOffset( inst, offset, isFixed );
		inst.dpDiv.css( { position: ( $.datepicker._inDialog && $.blockUI ?
			"static" : ( isFixed ? "fixed" : "absolute" ) ), display: "none",
			left: offset.left + "px", top: offset.top + "px" } );

		if ( !inst.inline ) {
			showAnim = $.datepicker._get( inst, "showAnim" );
			duration = $.datepicker._get( inst, "duration" );
			inst.dpDiv.css( "z-index", datepicker_getZindex( $( input ) ) + 1 );
			$.datepicker._datepickerShowing = true;

			if ( $.effects && $.effects.effect[ showAnim ] ) {
				inst.dpDiv.show( showAnim, $.datepicker._get( inst, "showOptions" ), duration );
			} else {
				inst.dpDiv[ showAnim || "show" ]( showAnim ? duration : null );
			}

			if ( $.datepicker._shouldFocusInput( inst ) ) {
				inst.input.trigger( "focus" );
			}

			$.datepicker._curInst = inst;
		}
	},

	/* Generate the date picker content. */
	_updateDatepicker: function( inst ) {
		this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
		datepicker_instActive = inst; // for delegate hover events
		inst.dpDiv.empty().append( this._generateHTML( inst ) );
		this._attachHandlers( inst );

		var origyearshtml,
			numMonths = this._getNumberOfMonths( inst ),
			cols = numMonths[ 1 ],
			width = 17,
			activeCell = inst.dpDiv.find( "." + this._dayOverClass + " a" ),
			onUpdateDatepicker = $.datepicker._get( inst, "onUpdateDatepicker" );

		if ( activeCell.length > 0 ) {
			datepicker_handleMouseover.apply( activeCell.get( 0 ) );
		}

		inst.dpDiv.removeClass( "ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4" ).width( "" );
		if ( cols > 1 ) {
			inst.dpDiv.addClass( "ui-datepicker-multi-" + cols ).css( "width", ( width * cols ) + "em" );
		}
		inst.dpDiv[ ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ? "add" : "remove" ) +
			"Class" ]( "ui-datepicker-multi" );
		inst.dpDiv[ ( this._get( inst, "isRTL" ) ? "add" : "remove" ) +
			"Class" ]( "ui-datepicker-rtl" );

		if ( inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
			inst.input.trigger( "focus" );
		}

		// Deffered render of the years select (to avoid flashes on Firefox)
		if ( inst.yearshtml ) {
			origyearshtml = inst.yearshtml;
			setTimeout( function() {

				//assure that inst.yearshtml didn't change.
				if ( origyearshtml === inst.yearshtml && inst.yearshtml ) {
					inst.dpDiv.find( "select.ui-datepicker-year" ).first().replaceWith( inst.yearshtml );
				}
				origyearshtml = inst.yearshtml = null;
			}, 0 );
		}

		if ( onUpdateDatepicker ) {
			onUpdateDatepicker.apply( ( inst.input ? inst.input[ 0 ] : null ), [ inst ] );
		}
	},

	// #6694 - don't focus the input if it's already focused
	// this breaks the change event in IE
	// Support: IE and jQuery <1.9
	_shouldFocusInput: function( inst ) {
		return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
	},

	/* Check positioning to remain on screen. */
	_checkOffset: function( inst, offset, isFixed ) {
		var dpWidth = inst.dpDiv.outerWidth(),
			dpHeight = inst.dpDiv.outerHeight(),
			inputWidth = inst.input ? inst.input.outerWidth() : 0,
			inputHeight = inst.input ? inst.input.outerHeight() : 0,
			viewWidth = document.documentElement.clientWidth + ( isFixed ? 0 : $( document ).scrollLeft() ),
			viewHeight = document.documentElement.clientHeight + ( isFixed ? 0 : $( document ).scrollTop() );

		offset.left -= ( this._get( inst, "isRTL" ) ? ( dpWidth - inputWidth ) : 0 );
		offset.left -= ( isFixed && offset.left === inst.input.offset().left ) ? $( document ).scrollLeft() : 0;
		offset.top -= ( isFixed && offset.top === ( inst.input.offset().top + inputHeight ) ) ? $( document ).scrollTop() : 0;

		// Now check if datepicker is showing outside window viewport - move to a better place if so.
		offset.left -= Math.min( offset.left, ( offset.left + dpWidth > viewWidth && viewWidth > dpWidth ) ?
			Math.abs( offset.left + dpWidth - viewWidth ) : 0 );
		offset.top -= Math.min( offset.top, ( offset.top + dpHeight > viewHeight && viewHeight > dpHeight ) ?
			Math.abs( dpHeight + inputHeight ) : 0 );

		return offset;
	},

	/* Find an object's position on the screen. */
	_findPos: function( obj ) {
		var position,
			inst = this._getInst( obj ),
			isRTL = this._get( inst, "isRTL" );

		while ( obj && ( obj.type === "hidden" || obj.nodeType !== 1 || $.expr.pseudos.hidden( obj ) ) ) {
			obj = obj[ isRTL ? "previousSibling" : "nextSibling" ];
		}

		position = $( obj ).offset();
		return [ position.left, position.top ];
	},

	/* Hide the date picker from view.
	 * @param  input  element - the input field attached to the date picker
	 */
	_hideDatepicker: function( input ) {
		var showAnim, duration, postProcess, onClose,
			inst = this._curInst;

		if ( !inst || ( input && inst !== $.data( input, "datepicker" ) ) ) {
			return;
		}

		if ( this._datepickerShowing ) {
			showAnim = this._get( inst, "showAnim" );
			duration = this._get( inst, "duration" );
			postProcess = function() {
				$.datepicker._tidyDialog( inst );
			};

			// DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
			if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
				inst.dpDiv.hide( showAnim, $.datepicker._get( inst, "showOptions" ), duration, postProcess );
			} else {
				inst.dpDiv[ ( showAnim === "slideDown" ? "slideUp" :
					( showAnim === "fadeIn" ? "fadeOut" : "hide" ) ) ]( ( showAnim ? duration : null ), postProcess );
			}

			if ( !showAnim ) {
				postProcess();
			}
			this._datepickerShowing = false;

			onClose = this._get( inst, "onClose" );
			if ( onClose ) {
				onClose.apply( ( inst.input ? inst.input[ 0 ] : null ), [ ( inst.input ? inst.input.val() : "" ), inst ] );
			}

			this._lastInput = null;
			if ( this._inDialog ) {
				this._dialogInput.css( { position: "absolute", left: "0", top: "-100px" } );
				if ( $.blockUI ) {
					$.unblockUI();
					$( "body" ).append( this.dpDiv );
				}
			}
			this._inDialog = false;
		}
	},

	/* Tidy up after a dialog display. */
	_tidyDialog: function( inst ) {
		inst.dpDiv.removeClass( this._dialogClass ).off( ".ui-datepicker-calendar" );
	},

	/* Close date picker if clicked elsewhere. */
	_checkExternalClick: function( event ) {
		if ( !$.datepicker._curInst ) {
			return;
		}

		var $target = $( event.target ),
			inst = $.datepicker._getInst( $target[ 0 ] );

		if ( ( ( $target[ 0 ].id !== $.datepicker._mainDivId &&
				$target.parents( "#" + $.datepicker._mainDivId ).length === 0 &&
				!$target.hasClass( $.datepicker.markerClassName ) &&
				!$target.closest( "." + $.datepicker._triggerClass ).length &&
				$.datepicker._datepickerShowing && !( $.datepicker._inDialog && $.blockUI ) ) ) ||
			( $target.hasClass( $.datepicker.markerClassName ) && $.datepicker._curInst !== inst ) ) {
				$.datepicker._hideDatepicker();
		}
	},

	/* Adjust one of the date sub-fields. */
	_adjustDate: function( id, offset, period ) {
		var target = $( id ),
			inst = this._getInst( target[ 0 ] );

		if ( this._isDisabledDatepicker( target[ 0 ] ) ) {
			return;
		}
		this._adjustInstDate( inst, offset, period );
		this._updateDatepicker( inst );
	},

	/* Action for current link. */
	_gotoToday: function( id ) {
		var date,
			target = $( id ),
			inst = this._getInst( target[ 0 ] );

		if ( this._get( inst, "gotoCurrent" ) && inst.currentDay ) {
			inst.selectedDay = inst.currentDay;
			inst.drawMonth = inst.selectedMonth = inst.currentMonth;
			inst.drawYear = inst.selectedYear = inst.currentYear;
		} else {
			date = new Date();
			inst.selectedDay = date.getDate();
			inst.drawMonth = inst.selectedMonth = date.getMonth();
			inst.drawYear = inst.selectedYear = date.getFullYear();
		}
		this._notifyChange( inst );
		this._adjustDate( target );
	},

	/* Action for selecting a new month/year. */
	_selectMonthYear: function( id, select, period ) {
		var target = $( id ),
			inst = this._getInst( target[ 0 ] );

		inst[ "selected" + ( period === "M" ? "Month" : "Year" ) ] =
		inst[ "draw" + ( period === "M" ? "Month" : "Year" ) ] =
			parseInt( select.options[ select.selectedIndex ].value, 10 );

		this._notifyChange( inst );
		this._adjustDate( target );
	},

	/* Action for selecting a day. */
	_selectDay: function( id, month, year, td ) {
		var inst,
			target = $( id );

		if ( $( td ).hasClass( this._unselectableClass ) || this._isDisabledDatepicker( target[ 0 ] ) ) {
			return;
		}

		inst = this._getInst( target[ 0 ] );
		inst.selectedDay = inst.currentDay = parseInt( $( "a", td ).attr( "data-date" ) );
		inst.selectedMonth = inst.currentMonth = month;
		inst.selectedYear = inst.currentYear = year;
		this._selectDate( id, this._formatDate( inst,
			inst.currentDay, inst.currentMonth, inst.currentYear ) );
	},

	/* Erase the input field and hide the date picker. */
	_clearDate: function( id ) {
		var target = $( id );
		this._selectDate( target, "" );
	},

	/* Update the input field with the selected date. */
	_selectDate: function( id, dateStr ) {
		var onSelect,
			target = $( id ),
			inst = this._getInst( target[ 0 ] );

		dateStr = ( dateStr != null ? dateStr : this._formatDate( inst ) );
		if ( inst.input ) {
			inst.input.val( dateStr );
		}
		this._updateAlternate( inst );

		onSelect = this._get( inst, "onSelect" );
		if ( onSelect ) {
			onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] );  // trigger custom callback
		} else if ( inst.input ) {
			inst.input.trigger( "change" ); // fire the change event
		}

		if ( inst.inline ) {
			this._updateDatepicker( inst );
		} else {
			this._hideDatepicker();
			this._lastInput = inst.input[ 0 ];
			if ( typeof( inst.input[ 0 ] ) !== "object" ) {
				inst.input.trigger( "focus" ); // restore focus
			}
			this._lastInput = null;
		}
	},

	/* Update any alternate field to synchronise with the main field. */
	_updateAlternate: function( inst ) {
		var altFormat, date, dateStr,
			altField = this._get( inst, "altField" );

		if ( altField ) { // update alternate field too
			altFormat = this._get( inst, "altFormat" ) || this._get( inst, "dateFormat" );
			date = this._getDate( inst );
			dateStr = this.formatDate( altFormat, date, this._getFormatConfig( inst ) );
			$( document ).find( altField ).val( dateStr );
		}
	},

	/* Set as beforeShowDay function to prevent selection of weekends.
	 * @param  date  Date - the date to customise
	 * @return [boolean, string] - is this date selectable?, what is its CSS class?
	 */
	noWeekends: function( date ) {
		var day = date.getDay();
		return [ ( day > 0 && day < 6 ), "" ];
	},

	/* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
	 * @param  date  Date - the date to get the week for
	 * @return  number - the number of the week within the year that contains this date
	 */
	iso8601Week: function( date ) {
		var time,
			checkDate = new Date( date.getTime() );

		// Find Thursday of this week starting on Monday
		checkDate.setDate( checkDate.getDate() + 4 - ( checkDate.getDay() || 7 ) );

		time = checkDate.getTime();
		checkDate.setMonth( 0 ); // Compare with Jan 1
		checkDate.setDate( 1 );
		return Math.floor( Math.round( ( time - checkDate ) / 86400000 ) / 7 ) + 1;
	},

	/* Parse a string value into a date object.
	 * See formatDate below for the possible formats.
	 *
	 * @param  format string - the expected format of the date
	 * @param  value string - the date in the above format
	 * @param  settings Object - attributes include:
	 *					shortYearCutoff  number - the cutoff year for determining the century (optional)
	 *					dayNamesShort	string[7] - abbreviated names of the days from Sunday (optional)
	 *					dayNames		string[7] - names of the days from Sunday (optional)
	 *					monthNamesShort string[12] - abbreviated names of the months (optional)
	 *					monthNames		string[12] - names of the months (optional)
	 * @return  Date - the extracted date value or null if value is blank
	 */
	parseDate: function( format, value, settings ) {
		if ( format == null || value == null ) {
			throw "Invalid arguments";
		}

		value = ( typeof value === "object" ? value.toString() : value + "" );
		if ( value === "" ) {
			return null;
		}

		var iFormat, dim, extra,
			iValue = 0,
			shortYearCutoffTemp = ( settings ? settings.shortYearCutoff : null ) || this._defaults.shortYearCutoff,
			shortYearCutoff = ( typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
				new Date().getFullYear() % 100 + parseInt( shortYearCutoffTemp, 10 ) ),
			dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort,
			dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames,
			monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort,
			monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames,
			year = -1,
			month = -1,
			day = -1,
			doy = -1,
			literal = false,
			date,

			// Check whether a format character is doubled
			lookAhead = function( match ) {
				var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
				if ( matches ) {
					iFormat++;
				}
				return matches;
			},

			// Extract a number from the string value
			getNumber = function( match ) {
				var isDoubled = lookAhead( match ),
					size = ( match === "@" ? 14 : ( match === "!" ? 20 :
					( match === "y" && isDoubled ? 4 : ( match === "o" ? 3 : 2 ) ) ) ),
					minSize = ( match === "y" ? size : 1 ),
					digits = new RegExp( "^\\d{" + minSize + "," + size + "}" ),
					num = value.substring( iValue ).match( digits );
				if ( !num ) {
					throw "Missing number at position " + iValue;
				}
				iValue += num[ 0 ].length;
				return parseInt( num[ 0 ], 10 );
			},

			// Extract a name from the string value and convert to an index
			getName = function( match, shortNames, longNames ) {
				var index = -1,
					names = $.map( lookAhead( match ) ? longNames : shortNames, function( v, k ) {
						return [ [ k, v ] ];
					} ).sort( function( a, b ) {
						return -( a[ 1 ].length - b[ 1 ].length );
					} );

				$.each( names, function( i, pair ) {
					var name = pair[ 1 ];
					if ( value.substr( iValue, name.length ).toLowerCase() === name.toLowerCase() ) {
						index = pair[ 0 ];
						iValue += name.length;
						return false;
					}
				} );
				if ( index !== -1 ) {
					return index + 1;
				} else {
					throw "Unknown name at position " + iValue;
				}
			},

			// Confirm that a literal character matches the string value
			checkLiteral = function() {
				if ( value.charAt( iValue ) !== format.charAt( iFormat ) ) {
					throw "Unexpected literal at position " + iValue;
				}
				iValue++;
			};

		for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
			if ( literal ) {
				if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
					literal = false;
				} else {
					checkLiteral();
				}
			} else {
				switch ( format.charAt( iFormat ) ) {
					case "d":
						day = getNumber( "d" );
						break;
					case "D":
						getName( "D", dayNamesShort, dayNames );
						break;
					case "o":
						doy = getNumber( "o" );
						break;
					case "m":
						month = getNumber( "m" );
						break;
					case "M":
						month = getName( "M", monthNamesShort, monthNames );
						break;
					case "y":
						year = getNumber( "y" );
						break;
					case "@":
						date = new Date( getNumber( "@" ) );
						year = date.getFullYear();
						month = date.getMonth() + 1;
						day = date.getDate();
						break;
					case "!":
						date = new Date( ( getNumber( "!" ) - this._ticksTo1970 ) / 10000 );
						year = date.getFullYear();
						month = date.getMonth() + 1;
						day = date.getDate();
						break;
					case "'":
						if ( lookAhead( "'" ) ) {
							checkLiteral();
						} else {
							literal = true;
						}
						break;
					default:
						checkLiteral();
				}
			}
		}

		if ( iValue < value.length ) {
			extra = value.substr( iValue );
			if ( !/^\s+/.test( extra ) ) {
				throw "Extra/unparsed characters found in date: " + extra;
			}
		}

		if ( year === -1 ) {
			year = new Date().getFullYear();
		} else if ( year < 100 ) {
			year += new Date().getFullYear() - new Date().getFullYear() % 100 +
				( year <= shortYearCutoff ? 0 : -100 );
		}

		if ( doy > -1 ) {
			month = 1;
			day = doy;
			do {
				dim = this._getDaysInMonth( year, month - 1 );
				if ( day <= dim ) {
					break;
				}
				month++;
				day -= dim;
			} while ( true );
		}

		date = this._daylightSavingAdjust( new Date( year, month - 1, day ) );
		if ( date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day ) {
			throw "Invalid date"; // E.g. 31/02/00
		}
		return date;
	},

	/* Standard date formats. */
	ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
	COOKIE: "D, dd M yy",
	ISO_8601: "yy-mm-dd",
	RFC_822: "D, d M y",
	RFC_850: "DD, dd-M-y",
	RFC_1036: "D, d M y",
	RFC_1123: "D, d M yy",
	RFC_2822: "D, d M yy",
	RSS: "D, d M y", // RFC 822
	TICKS: "!",
	TIMESTAMP: "@",
	W3C: "yy-mm-dd", // ISO 8601

	_ticksTo1970: ( ( ( 1970 - 1 ) * 365 + Math.floor( 1970 / 4 ) - Math.floor( 1970 / 100 ) +
		Math.floor( 1970 / 400 ) ) * 24 * 60 * 60 * 10000000 ),

	/* Format a date object into a string value.
	 * The format can be combinations of the following:
	 * d  - day of month (no leading zero)
	 * dd - day of month (two digit)
	 * o  - day of year (no leading zeros)
	 * oo - day of year (three digit)
	 * D  - day name short
	 * DD - day name long
	 * m  - month of year (no leading zero)
	 * mm - month of year (two digit)
	 * M  - month name short
	 * MM - month name long
	 * y  - year (two digit)
	 * yy - year (four digit)
	 * @ - Unix timestamp (ms since 01/01/1970)
	 * ! - Windows ticks (100ns since 01/01/0001)
	 * "..." - literal text
	 * '' - single quote
	 *
	 * @param  format string - the desired format of the date
	 * @param  date Date - the date value to format
	 * @param  settings Object - attributes include:
	 *					dayNamesShort	string[7] - abbreviated names of the days from Sunday (optional)
	 *					dayNames		string[7] - names of the days from Sunday (optional)
	 *					monthNamesShort string[12] - abbreviated names of the months (optional)
	 *					monthNames		string[12] - names of the months (optional)
	 * @return  string - the date in the above format
	 */
	formatDate: function( format, date, settings ) {
		if ( !date ) {
			return "";
		}

		var iFormat,
			dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort,
			dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames,
			monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort,
			monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames,

			// Check whether a format character is doubled
			lookAhead = function( match ) {
				var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
				if ( matches ) {
					iFormat++;
				}
				return matches;
			},

			// Format a number, with leading zero if necessary
			formatNumber = function( match, value, len ) {
				var num = "" + value;
				if ( lookAhead( match ) ) {
					while ( num.length < len ) {
						num = "0" + num;
					}
				}
				return num;
			},

			// Format a name, short or long as requested
			formatName = function( match, value, shortNames, longNames ) {
				return ( lookAhead( match ) ? longNames[ value ] : shortNames[ value ] );
			},
			output = "",
			literal = false;

		if ( date ) {
			for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
				if ( literal ) {
					if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
						literal = false;
					} else {
						output += format.charAt( iFormat );
					}
				} else {
					switch ( format.charAt( iFormat ) ) {
						case "d":
							output += formatNumber( "d", date.getDate(), 2 );
							break;
						case "D":
							output += formatName( "D", date.getDay(), dayNamesShort, dayNames );
							break;
						case "o":
							output += formatNumber( "o",
								Math.round( ( new Date( date.getFullYear(), date.getMonth(), date.getDate() ).getTime() - new Date( date.getFullYear(), 0, 0 ).getTime() ) / 86400000 ), 3 );
							break;
						case "m":
							output += formatNumber( "m", date.getMonth() + 1, 2 );
							break;
						case "M":
							output += formatName( "M", date.getMonth(), monthNamesShort, monthNames );
							break;
						case "y":
							output += ( lookAhead( "y" ) ? date.getFullYear() :
								( date.getFullYear() % 100 < 10 ? "0" : "" ) + date.getFullYear() % 100 );
							break;
						case "@":
							output += date.getTime();
							break;
						case "!":
							output += date.getTime() * 10000 + this._ticksTo1970;
							break;
						case "'":
							if ( lookAhead( "'" ) ) {
								output += "'";
							} else {
								literal = true;
							}
							break;
						default:
							output += format.charAt( iFormat );
					}
				}
			}
		}
		return output;
	},

	/* Extract all possible characters from the date format. */
	_possibleChars: function( format ) {
		var iFormat,
			chars = "",
			literal = false,

			// Check whether a format character is doubled
			lookAhead = function( match ) {
				var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
				if ( matches ) {
					iFormat++;
				}
				return matches;
			};

		for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
			if ( literal ) {
				if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
					literal = false;
				} else {
					chars += format.charAt( iFormat );
				}
			} else {
				switch ( format.charAt( iFormat ) ) {
					case "d": case "m": case "y": case "@":
						chars += "0123456789";
						break;
					case "D": case "M":
						return null; // Accept anything
					case "'":
						if ( lookAhead( "'" ) ) {
							chars += "'";
						} else {
							literal = true;
						}
						break;
					default:
						chars += format.charAt( iFormat );
				}
			}
		}
		return chars;
	},

	/* Get a setting value, defaulting if necessary. */
	_get: function( inst, name ) {
		return inst.settings[ name ] !== undefined ?
			inst.settings[ name ] : this._defaults[ name ];
	},

	/* Parse existing date and initialise date picker. */
	_setDateFromField: function( inst, noDefault ) {
		if ( inst.input.val() === inst.lastVal ) {
			return;
		}

		var dateFormat = this._get( inst, "dateFormat" ),
			dates = inst.lastVal = inst.input ? inst.input.val() : null,
			defaultDate = this._getDefaultDate( inst ),
			date = defaultDate,
			settings = this._getFormatConfig( inst );

		try {
			date = this.parseDate( dateFormat, dates, settings ) || defaultDate;
		} catch ( event ) {
			dates = ( noDefault ? "" : dates );
		}
		inst.selectedDay = date.getDate();
		inst.drawMonth = inst.selectedMonth = date.getMonth();
		inst.drawYear = inst.selectedYear = date.getFullYear();
		inst.currentDay = ( dates ? date.getDate() : 0 );
		inst.currentMonth = ( dates ? date.getMonth() : 0 );
		inst.currentYear = ( dates ? date.getFullYear() : 0 );
		this._adjustInstDate( inst );
	},

	/* Retrieve the default date shown on opening. */
	_getDefaultDate: function( inst ) {
		return this._restrictMinMax( inst,
			this._determineDate( inst, this._get( inst, "defaultDate" ), new Date() ) );
	},

	/* A date may be specified as an exact value or a relative one. */
	_determineDate: function( inst, date, defaultDate ) {
		var offsetNumeric = function( offset ) {
				var date = new Date();
				date.setDate( date.getDate() + offset );
				return date;
			},
			offsetString = function( offset ) {
				try {
					return $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ),
						offset, $.datepicker._getFormatConfig( inst ) );
				} catch ( e ) {

					// Ignore
				}

				var date = ( offset.toLowerCase().match( /^c/ ) ?
					$.datepicker._getDate( inst ) : null ) || new Date(),
					year = date.getFullYear(),
					month = date.getMonth(),
					day = date.getDate(),
					pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
					matches = pattern.exec( offset );

				while ( matches ) {
					switch ( matches[ 2 ] || "d" ) {
						case "d" : case "D" :
							day += parseInt( matches[ 1 ], 10 ); break;
						case "w" : case "W" :
							day += parseInt( matches[ 1 ], 10 ) * 7; break;
						case "m" : case "M" :
							month += parseInt( matches[ 1 ], 10 );
							day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) );
							break;
						case "y": case "Y" :
							year += parseInt( matches[ 1 ], 10 );
							day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) );
							break;
					}
					matches = pattern.exec( offset );
				}
				return new Date( year, month, day );
			},
			newDate = ( date == null || date === "" ? defaultDate : ( typeof date === "string" ? offsetString( date ) :
				( typeof date === "number" ? ( isNaN( date ) ? defaultDate : offsetNumeric( date ) ) : new Date( date.getTime() ) ) ) );

		newDate = ( newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate );
		if ( newDate ) {
			newDate.setHours( 0 );
			newDate.setMinutes( 0 );
			newDate.setSeconds( 0 );
			newDate.setMilliseconds( 0 );
		}
		return this._daylightSavingAdjust( newDate );
	},

	/* Handle switch to/from daylight saving.
	 * Hours may be non-zero on daylight saving cut-over:
	 * > 12 when midnight changeover, but then cannot generate
	 * midnight datetime, so jump to 1AM, otherwise reset.
	 * @param  date  (Date) the date to check
	 * @return  (Date) the corrected date
	 */
	_daylightSavingAdjust: function( date ) {
		if ( !date ) {
			return null;
		}
		date.setHours( date.getHours() > 12 ? date.getHours() + 2 : 0 );
		return date;
	},

	/* Set the date(s) directly. */
	_setDate: function( inst, date, noChange ) {
		var clear = !date,
			origMonth = inst.selectedMonth,
			origYear = inst.selectedYear,
			newDate = this._restrictMinMax( inst, this._determineDate( inst, date, new Date() ) );

		inst.selectedDay = inst.currentDay = newDate.getDate();
		inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
		inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
		if ( ( origMonth !== inst.selectedMonth || origYear !== inst.selectedYear ) && !noChange ) {
			this._notifyChange( inst );
		}
		this._adjustInstDate( inst );
		if ( inst.input ) {
			inst.input.val( clear ? "" : this._formatDate( inst ) );
		}
	},

	/* Retrieve the date(s) directly. */
	_getDate: function( inst ) {
		var startDate = ( !inst.currentYear || ( inst.input && inst.input.val() === "" ) ? null :
			this._daylightSavingAdjust( new Date(
			inst.currentYear, inst.currentMonth, inst.currentDay ) ) );
			return startDate;
	},

	/* Attach the onxxx handlers.  These are declared statically so
	 * they work with static code transformers like Caja.
	 */
	_attachHandlers: function( inst ) {
		var stepMonths = this._get( inst, "stepMonths" ),
			id = "#" + inst.id.replace( /\\\\/g, "\\" );
		inst.dpDiv.find( "[data-handler]" ).map( function() {
			var handler = {
				prev: function() {
					$.datepicker._adjustDate( id, -stepMonths, "M" );
				},
				next: function() {
					$.datepicker._adjustDate( id, +stepMonths, "M" );
				},
				hide: function() {
					$.datepicker._hideDatepicker();
				},
				today: function() {
					$.datepicker._gotoToday( id );
				},
				selectDay: function() {
					$.datepicker._selectDay( id, +this.getAttribute( "data-month" ), +this.getAttribute( "data-year" ), this );
					return false;
				},
				selectMonth: function() {
					$.datepicker._selectMonthYear( id, this, "M" );
					return false;
				},
				selectYear: function() {
					$.datepicker._selectMonthYear( id, this, "Y" );
					return false;
				}
			};
			$( this ).on( this.getAttribute( "data-event" ), handler[ this.getAttribute( "data-handler" ) ] );
		} );
	},

	/* Generate the HTML for the current state of the date picker. */
	_generateHTML: function( inst ) {
		var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
			controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
			monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
			selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
			cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
			printDate, dRow, tbody, daySettings, otherMonth, unselectable,
			tempDate = new Date(),
			today = this._daylightSavingAdjust(
				new Date( tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate() ) ), // clear time
			isRTL = this._get( inst, "isRTL" ),
			showButtonPanel = this._get( inst, "showButtonPanel" ),
			hideIfNoPrevNext = this._get( inst, "hideIfNoPrevNext" ),
			navigationAsDateFormat = this._get( inst, "navigationAsDateFormat" ),
			numMonths = this._getNumberOfMonths( inst ),
			showCurrentAtPos = this._get( inst, "showCurrentAtPos" ),
			stepMonths = this._get( inst, "stepMonths" ),
			isMultiMonth = ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ),
			currentDate = this._daylightSavingAdjust( ( !inst.currentDay ? new Date( 9999, 9, 9 ) :
				new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) ),
			minDate = this._getMinMaxDate( inst, "min" ),
			maxDate = this._getMinMaxDate( inst, "max" ),
			drawMonth = inst.drawMonth - showCurrentAtPos,
			drawYear = inst.drawYear;

		if ( drawMonth < 0 ) {
			drawMonth += 12;
			drawYear--;
		}
		if ( maxDate ) {
			maxDraw = this._daylightSavingAdjust( new Date( maxDate.getFullYear(),
				maxDate.getMonth() - ( numMonths[ 0 ] * numMonths[ 1 ] ) + 1, maxDate.getDate() ) );
			maxDraw = ( minDate && maxDraw < minDate ? minDate : maxDraw );
			while ( this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 ) ) > maxDraw ) {
				drawMonth--;
				if ( drawMonth < 0 ) {
					drawMonth = 11;
					drawYear--;
				}
			}
		}
		inst.drawMonth = drawMonth;
		inst.drawYear = drawYear;

		prevText = this._get( inst, "prevText" );
		prevText = ( !navigationAsDateFormat ? prevText : this.formatDate( prevText,
			this._daylightSavingAdjust( new Date( drawYear, drawMonth - stepMonths, 1 ) ),
			this._getFormatConfig( inst ) ) );

		if ( this._canAdjustMonth( inst, -1, drawYear, drawMonth ) ) {
			prev = $( "<a>" )
				.attr( {
					"class": "ui-datepicker-prev ui-corner-all",
					"data-handler": "prev",
					"data-event": "click",
					title: prevText
				} )
				.append(
					$( "<span>" )
						.addClass( "ui-icon ui-icon-circle-triangle-" +
							( isRTL ? "e" : "w" ) )
						.text( prevText )
				)[ 0 ].outerHTML;
		} else if ( hideIfNoPrevNext ) {
			prev = "";
		} else {
			prev = $( "<a>" )
				.attr( {
					"class": "ui-datepicker-prev ui-corner-all ui-state-disabled",
					title: prevText
				} )
				.append(
					$( "<span>" )
						.addClass( "ui-icon ui-icon-circle-triangle-" +
							( isRTL ? "e" : "w" ) )
						.text( prevText )
				)[ 0 ].outerHTML;
		}

		nextText = this._get( inst, "nextText" );
		nextText = ( !navigationAsDateFormat ? nextText : this.formatDate( nextText,
			this._daylightSavingAdjust( new Date( drawYear, drawMonth + stepMonths, 1 ) ),
			this._getFormatConfig( inst ) ) );

		if ( this._canAdjustMonth( inst, +1, drawYear, drawMonth ) ) {
			next = $( "<a>" )
				.attr( {
					"class": "ui-datepicker-next ui-corner-all",
					"data-handler": "next",
					"data-event": "click",
					title: nextText
				} )
				.append(
					$( "<span>" )
						.addClass( "ui-icon ui-icon-circle-triangle-" +
							( isRTL ? "w" : "e" ) )
						.text( nextText )
				)[ 0 ].outerHTML;
		} else if ( hideIfNoPrevNext ) {
			next = "";
		} else {
			next = $( "<a>" )
				.attr( {
					"class": "ui-datepicker-next ui-corner-all ui-state-disabled",
					title: nextText
				} )
				.append(
					$( "<span>" )
						.attr( "class", "ui-icon ui-icon-circle-triangle-" +
							( isRTL ? "w" : "e" ) )
						.text( nextText )
				)[ 0 ].outerHTML;
		}

		currentText = this._get( inst, "currentText" );
		gotoDate = ( this._get( inst, "gotoCurrent" ) && inst.currentDay ? currentDate : today );
		currentText = ( !navigationAsDateFormat ? currentText :
			this.formatDate( currentText, gotoDate, this._getFormatConfig( inst ) ) );

		controls = "";
		if ( !inst.inline ) {
			controls = $( "<button>" )
				.attr( {
					type: "button",
					"class": "ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all",
					"data-handler": "hide",
					"data-event": "click"
				} )
				.text( this._get( inst, "closeText" ) )[ 0 ].outerHTML;
		}

		buttonPanel = "";
		if ( showButtonPanel ) {
			buttonPanel = $( "<div class='ui-datepicker-buttonpane ui-widget-content'>" )
				.append( isRTL ? controls : "" )
				.append( this._isInRange( inst, gotoDate ) ?
					$( "<button>" )
						.attr( {
							type: "button",
							"class": "ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all",
							"data-handler": "today",
							"data-event": "click"
						} )
						.text( currentText ) :
					"" )
				.append( isRTL ? "" : controls )[ 0 ].outerHTML;
		}

		firstDay = parseInt( this._get( inst, "firstDay" ), 10 );
		firstDay = ( isNaN( firstDay ) ? 0 : firstDay );

		showWeek = this._get( inst, "showWeek" );
		dayNames = this._get( inst, "dayNames" );
		dayNamesMin = this._get( inst, "dayNamesMin" );
		monthNames = this._get( inst, "monthNames" );
		monthNamesShort = this._get( inst, "monthNamesShort" );
		beforeShowDay = this._get( inst, "beforeShowDay" );
		showOtherMonths = this._get( inst, "showOtherMonths" );
		selectOtherMonths = this._get( inst, "selectOtherMonths" );
		defaultDate = this._getDefaultDate( inst );
		html = "";

		for ( row = 0; row < numMonths[ 0 ]; row++ ) {
			group = "";
			this.maxRows = 4;
			for ( col = 0; col < numMonths[ 1 ]; col++ ) {
				selectedDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, inst.selectedDay ) );
				cornerClass = " ui-corner-all";
				calender = "";
				if ( isMultiMonth ) {
					calender += "<div class='ui-datepicker-group";
					if ( numMonths[ 1 ] > 1 ) {
						switch ( col ) {
							case 0: calender += " ui-datepicker-group-first";
								cornerClass = " ui-corner-" + ( isRTL ? "right" : "left" ); break;
							case numMonths[ 1 ] - 1: calender += " ui-datepicker-group-last";
								cornerClass = " ui-corner-" + ( isRTL ? "left" : "right" ); break;
							default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
						}
					}
					calender += "'>";
				}
				calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
					( /all|left/.test( cornerClass ) && row === 0 ? ( isRTL ? next : prev ) : "" ) +
					( /all|right/.test( cornerClass ) && row === 0 ? ( isRTL ? prev : next ) : "" ) +
					this._generateMonthYearHeader( inst, drawMonth, drawYear, minDate, maxDate,
					row > 0 || col > 0, monthNames, monthNamesShort ) + // draw month headers
					"</div><table class='ui-datepicker-calendar'><thead>" +
					"<tr>";
				thead = ( showWeek ? "<th class='ui-datepicker-week-col'>" + this._get( inst, "weekHeader" ) + "</th>" : "" );
				for ( dow = 0; dow < 7; dow++ ) { // days of the week
					day = ( dow + firstDay ) % 7;
					thead += "<th scope='col'" + ( ( dow + firstDay + 6 ) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "" ) + ">" +
						"<span title='" + dayNames[ day ] + "'>" + dayNamesMin[ day ] + "</span></th>";
				}
				calender += thead + "</tr></thead><tbody>";
				daysInMonth = this._getDaysInMonth( drawYear, drawMonth );
				if ( drawYear === inst.selectedYear && drawMonth === inst.selectedMonth ) {
					inst.selectedDay = Math.min( inst.selectedDay, daysInMonth );
				}
				leadDays = ( this._getFirstDayOfMonth( drawYear, drawMonth ) - firstDay + 7 ) % 7;
				curRows = Math.ceil( ( leadDays + daysInMonth ) / 7 ); // calculate the number of rows to generate
				numRows = ( isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows ); //If multiple months, use the higher number of rows (see #7043)
				this.maxRows = numRows;
				printDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 - leadDays ) );
				for ( dRow = 0; dRow < numRows; dRow++ ) { // create date picker rows
					calender += "<tr>";
					tbody = ( !showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
						this._get( inst, "calculateWeek" )( printDate ) + "</td>" );
					for ( dow = 0; dow < 7; dow++ ) { // create date picker days
						daySettings = ( beforeShowDay ?
							beforeShowDay.apply( ( inst.input ? inst.input[ 0 ] : null ), [ printDate ] ) : [ true, "" ] );
						otherMonth = ( printDate.getMonth() !== drawMonth );
						unselectable = ( otherMonth && !selectOtherMonths ) || !daySettings[ 0 ] ||
							( minDate && printDate < minDate ) || ( maxDate && printDate > maxDate );
						tbody += "<td class='" +
							( ( dow + firstDay + 6 ) % 7 >= 5 ? " ui-datepicker-week-end" : "" ) + // highlight weekends
							( otherMonth ? " ui-datepicker-other-month" : "" ) + // highlight days from other months
							( ( printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent ) || // user pressed key
							( defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime() ) ?

							// or defaultDate is current printedDate and defaultDate is selectedDate
							" " + this._dayOverClass : "" ) + // highlight selected day
							( unselectable ? " " + this._unselectableClass + " ui-state-disabled" : "" ) +  // highlight unselectable days
							( otherMonth && !showOtherMonths ? "" : " " + daySettings[ 1 ] + // highlight custom dates
							( printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "" ) + // highlight selected day
							( printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "" ) ) + "'" + // highlight today (if different)
							( ( !otherMonth || showOtherMonths ) && daySettings[ 2 ] ? " title='" + daySettings[ 2 ].replace( /'/g, "&#39;" ) + "'" : "" ) + // cell title
							( unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'" ) + ">" + // actions
							( otherMonth && !showOtherMonths ? "&#xa0;" : // display for other months
							( unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
							( printDate.getTime() === today.getTime() ? " ui-state-highlight" : "" ) +
							( printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "" ) + // highlight selected day
							( otherMonth ? " ui-priority-secondary" : "" ) + // distinguish dates from other months
							"' href='#' aria-current='" + ( printDate.getTime() === currentDate.getTime() ? "true" : "false" ) + // mark date as selected for screen reader
							"' data-date='" + printDate.getDate() + // store date as data
							"'>" + printDate.getDate() + "</a>" ) ) + "</td>"; // display selectable date
						printDate.setDate( printDate.getDate() + 1 );
						printDate = this._daylightSavingAdjust( printDate );
					}
					calender += tbody + "</tr>";
				}
				drawMonth++;
				if ( drawMonth > 11 ) {
					drawMonth = 0;
					drawYear++;
				}
				calender += "</tbody></table>" + ( isMultiMonth ? "</div>" +
							( ( numMonths[ 0 ] > 0 && col === numMonths[ 1 ] - 1 ) ? "<div class='ui-datepicker-row-break'></div>" : "" ) : "" );
				group += calender;
			}
			html += group;
		}
		html += buttonPanel;
		inst._keyEvent = false;
		return html;
	},

	/* Generate the month and year header. */
	_generateMonthYearHeader: function( inst, drawMonth, drawYear, minDate, maxDate,
			secondary, monthNames, monthNamesShort ) {

		var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
			changeMonth = this._get( inst, "changeMonth" ),
			changeYear = this._get( inst, "changeYear" ),
			showMonthAfterYear = this._get( inst, "showMonthAfterYear" ),
			selectMonthLabel = this._get( inst, "selectMonthLabel" ),
			selectYearLabel = this._get( inst, "selectYearLabel" ),
			html = "<div class='ui-datepicker-title'>",
			monthHtml = "";

		// Month selection
		if ( secondary || !changeMonth ) {
			monthHtml += "<span class='ui-datepicker-month'>" + monthNames[ drawMonth ] + "</span>";
		} else {
			inMinYear = ( minDate && minDate.getFullYear() === drawYear );
			inMaxYear = ( maxDate && maxDate.getFullYear() === drawYear );
			monthHtml += "<select class='ui-datepicker-month' aria-label='" + selectMonthLabel + "' data-handler='selectMonth' data-event='change'>";
			for ( month = 0; month < 12; month++ ) {
				if ( ( !inMinYear || month >= minDate.getMonth() ) && ( !inMaxYear || month <= maxDate.getMonth() ) ) {
					monthHtml += "<option value='" + month + "'" +
						( month === drawMonth ? " selected='selected'" : "" ) +
						">" + monthNamesShort[ month ] + "</option>";
				}
			}
			monthHtml += "</select>";
		}

		if ( !showMonthAfterYear ) {
			html += monthHtml + ( secondary || !( changeMonth && changeYear ) ? "&#xa0;" : "" );
		}

		// Year selection
		if ( !inst.yearshtml ) {
			inst.yearshtml = "";
			if ( secondary || !changeYear ) {
				html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
			} else {

				// determine range of years to display
				years = this._get( inst, "yearRange" ).split( ":" );
				thisYear = new Date().getFullYear();
				determineYear = function( value ) {
					var year = ( value.match( /c[+\-].*/ ) ? drawYear + parseInt( value.substring( 1 ), 10 ) :
						( value.match( /[+\-].*/ ) ? thisYear + parseInt( value, 10 ) :
						parseInt( value, 10 ) ) );
					return ( isNaN( year ) ? thisYear : year );
				};
				year = determineYear( years[ 0 ] );
				endYear = Math.max( year, determineYear( years[ 1 ] || "" ) );
				year = ( minDate ? Math.max( year, minDate.getFullYear() ) : year );
				endYear = ( maxDate ? Math.min( endYear, maxDate.getFullYear() ) : endYear );
				inst.yearshtml += "<select class='ui-datepicker-year' aria-label='" + selectYearLabel + "' data-handler='selectYear' data-event='change'>";
				for ( ; year <= endYear; year++ ) {
					inst.yearshtml += "<option value='" + year + "'" +
						( year === drawYear ? " selected='selected'" : "" ) +
						">" + year + "</option>";
				}
				inst.yearshtml += "</select>";

				html += inst.yearshtml;
				inst.yearshtml = null;
			}
		}

		html += this._get( inst, "yearSuffix" );
		if ( showMonthAfterYear ) {
			html += ( secondary || !( changeMonth && changeYear ) ? "&#xa0;" : "" ) + monthHtml;
		}
		html += "</div>"; // Close datepicker_header
		return html;
	},

	/* Adjust one of the date sub-fields. */
	_adjustInstDate: function( inst, offset, period ) {
		var year = inst.selectedYear + ( period === "Y" ? offset : 0 ),
			month = inst.selectedMonth + ( period === "M" ? offset : 0 ),
			day = Math.min( inst.selectedDay, this._getDaysInMonth( year, month ) ) + ( period === "D" ? offset : 0 ),
			date = this._restrictMinMax( inst, this._daylightSavingAdjust( new Date( year, month, day ) ) );

		inst.selectedDay = date.getDate();
		inst.drawMonth = inst.selectedMonth = date.getMonth();
		inst.drawYear = inst.selectedYear = date.getFullYear();
		if ( period === "M" || period === "Y" ) {
			this._notifyChange( inst );
		}
	},

	/* Ensure a date is within any min/max bounds. */
	_restrictMinMax: function( inst, date ) {
		var minDate = this._getMinMaxDate( inst, "min" ),
			maxDate = this._getMinMaxDate( inst, "max" ),
			newDate = ( minDate && date < minDate ? minDate : date );
		return ( maxDate && newDate > maxDate ? maxDate : newDate );
	},

	/* Notify change of month/year. */
	_notifyChange: function( inst ) {
		var onChange = this._get( inst, "onChangeMonthYear" );
		if ( onChange ) {
			onChange.apply( ( inst.input ? inst.input[ 0 ] : null ),
				[ inst.selectedYear, inst.selectedMonth + 1, inst ] );
		}
	},

	/* Determine the number of months to show. */
	_getNumberOfMonths: function( inst ) {
		var numMonths = this._get( inst, "numberOfMonths" );
		return ( numMonths == null ? [ 1, 1 ] : ( typeof numMonths === "number" ? [ 1, numMonths ] : numMonths ) );
	},

	/* Determine the current maximum date - ensure no time components are set. */
	_getMinMaxDate: function( inst, minMax ) {
		return this._determineDate( inst, this._get( inst, minMax + "Date" ), null );
	},

	/* Find the number of days in a given month. */
	_getDaysInMonth: function( year, month ) {
		return 32 - this._daylightSavingAdjust( new Date( year, month, 32 ) ).getDate();
	},

	/* Find the day of the week of the first of a month. */
	_getFirstDayOfMonth: function( year, month ) {
		return new Date( year, month, 1 ).getDay();
	},

	/* Determines if we should allow a "next/prev" month display change. */
	_canAdjustMonth: function( inst, offset, curYear, curMonth ) {
		var numMonths = this._getNumberOfMonths( inst ),
			date = this._daylightSavingAdjust( new Date( curYear,
			curMonth + ( offset < 0 ? offset : numMonths[ 0 ] * numMonths[ 1 ] ), 1 ) );

		if ( offset < 0 ) {
			date.setDate( this._getDaysInMonth( date.getFullYear(), date.getMonth() ) );
		}
		return this._isInRange( inst, date );
	},

	/* Is the given date in the accepted range? */
	_isInRange: function( inst, date ) {
		var yearSplit, currentYear,
			minDate = this._getMinMaxDate( inst, "min" ),
			maxDate = this._getMinMaxDate( inst, "max" ),
			minYear = null,
			maxYear = null,
			years = this._get( inst, "yearRange" );
			if ( years ) {
				yearSplit = years.split( ":" );
				currentYear = new Date().getFullYear();
				minYear = parseInt( yearSplit[ 0 ], 10 );
				maxYear = parseInt( yearSplit[ 1 ], 10 );
				if ( yearSplit[ 0 ].match( /[+\-].*/ ) ) {
					minYear += currentYear;
				}
				if ( yearSplit[ 1 ].match( /[+\-].*/ ) ) {
					maxYear += currentYear;
				}
			}

		return ( ( !minDate || date.getTime() >= minDate.getTime() ) &&
			( !maxDate || date.getTime() <= maxDate.getTime() ) &&
			( !minYear || date.getFullYear() >= minYear ) &&
			( !maxYear || date.getFullYear() <= maxYear ) );
	},

	/* Provide the configuration settings for formatting/parsing. */
	_getFormatConfig: function( inst ) {
		var shortYearCutoff = this._get( inst, "shortYearCutoff" );
		shortYearCutoff = ( typeof shortYearCutoff !== "string" ? shortYearCutoff :
			new Date().getFullYear() % 100 + parseInt( shortYearCutoff, 10 ) );
		return { shortYearCutoff: shortYearCutoff,
			dayNamesShort: this._get( inst, "dayNamesShort" ), dayNames: this._get( inst, "dayNames" ),
			monthNamesShort: this._get( inst, "monthNamesShort" ), monthNames: this._get( inst, "monthNames" ) };
	},

	/* Format the given date for display. */
	_formatDate: function( inst, day, month, year ) {
		if ( !day ) {
			inst.currentDay = inst.selectedDay;
			inst.currentMonth = inst.selectedMonth;
			inst.currentYear = inst.selectedYear;
		}
		var date = ( day ? ( typeof day === "object" ? day :
			this._daylightSavingAdjust( new Date( year, month, day ) ) ) :
			this._daylightSavingAdjust( new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) );
		return this.formatDate( this._get( inst, "dateFormat" ), date, this._getFormatConfig( inst ) );
	}
} );

/*
 * Bind hover events for datepicker elements.
 * Done via delegate so the binding only occurs once in the lifetime of the parent div.
 * Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
 */
function datepicker_bindHover( dpDiv ) {
	var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
	return dpDiv.on( "mouseout", selector, function() {
			$( this ).removeClass( "ui-state-hover" );
			if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) {
				$( this ).removeClass( "ui-datepicker-prev-hover" );
			}
			if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) {
				$( this ).removeClass( "ui-datepicker-next-hover" );
			}
		} )
		.on( "mouseover", selector, datepicker_handleMouseover );
}

function datepicker_handleMouseover() {
	if ( !$.datepicker._isDisabledDatepicker( datepicker_instActive.inline ? datepicker_instActive.dpDiv.parent()[ 0 ] : datepicker_instActive.input[ 0 ] ) ) {
		$( this ).parents( ".ui-datepicker-calendar" ).find( "a" ).removeClass( "ui-state-hover" );
		$( this ).addClass( "ui-state-hover" );
		if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) {
			$( this ).addClass( "ui-datepicker-prev-hover" );
		}
		if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) {
			$( this ).addClass( "ui-datepicker-next-hover" );
		}
	}
}

/* jQuery extend now ignores nulls! */
function datepicker_extendRemove( target, props ) {
	$.extend( target, props );
	for ( var name in props ) {
		if ( props[ name ] == null ) {
			target[ name ] = props[ name ];
		}
	}
	return target;
}

/* Invoke the datepicker functionality.
   @param  options  string - a command, optionally followed by additional parameters or
					Object - settings for attaching new datepicker functionality
   @return  jQuery object */
$.fn.datepicker = function( options ) {

	/* Verify an empty collection wasn't passed - Fixes #6976 */
	if ( !this.length ) {
		return this;
	}

	/* Initialise the date picker. */
	if ( !$.datepicker.initialized ) {
		$( document ).on( "mousedown", $.datepicker._checkExternalClick );
		$.datepicker.initialized = true;
	}

	/* Append datepicker main container to body if not exist. */
	if ( $( "#" + $.datepicker._mainDivId ).length === 0 ) {
		$( "body" ).append( $.datepicker.dpDiv );
	}

	var otherArgs = Array.prototype.slice.call( arguments, 1 );
	if ( typeof options === "string" && ( options === "isDisabled" || options === "getDate" || options === "widget" ) ) {
		return $.datepicker[ "_" + options + "Datepicker" ].
			apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) );
	}
	if ( options === "option" && arguments.length === 2 && typeof arguments[ 1 ] === "string" ) {
		return $.datepicker[ "_" + options + "Datepicker" ].
			apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) );
	}
	return this.each( function() {
		if ( typeof options === "string" ) {
			$.datepicker[ "_" + options + "Datepicker" ]
				.apply( $.datepicker, [ this ].concat( otherArgs ) );
		} else {
			$.datepicker._attachDatepicker( this, options );
		}
	} );
};

$.datepicker = new Datepicker(); // singleton instance
$.datepicker.initialized = false;
$.datepicker.uuid = new Date().getTime();
$.datepicker.version = "1.13.2";

var widgetsDatepicker = $.datepicker;



// This file is deprecated
var ie = $.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() );

/*!
 * jQuery UI Mouse 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Mouse
//>>group: Widgets
//>>description: Abstracts mouse-based interactions to assist in creating certain widgets.
//>>docs: http://api.jqueryui.com/mouse/


var mouseHandled = false;
$( document ).on( "mouseup", function() {
	mouseHandled = false;
} );

var widgetsMouse = $.widget( "ui.mouse", {
	version: "1.13.2",
	options: {
		cancel: "input, textarea, button, select, option",
		distance: 1,
		delay: 0
	},
	_mouseInit: function() {
		var that = this;

		this.element
			.on( "mousedown." + this.widgetName, function( event ) {
				return that._mouseDown( event );
			} )
			.on( "click." + this.widgetName, function( event ) {
				if ( true === $.data( event.target, that.widgetName + ".preventClickEvent" ) ) {
					$.removeData( event.target, that.widgetName + ".preventClickEvent" );
					event.stopImmediatePropagation();
					return false;
				}
			} );

		this.started = false;
	},

	// TODO: make sure destroying one instance of mouse doesn't mess with
	// other instances of mouse
	_mouseDestroy: function() {
		this.element.off( "." + this.widgetName );
		if ( this._mouseMoveDelegate ) {
			this.document
				.off( "mousemove." + this.widgetName, this._mouseMoveDelegate )
				.off( "mouseup." + this.widgetName, this._mouseUpDelegate );
		}
	},

	_mouseDown: function( event ) {

		// don't let more than one widget handle mouseStart
		if ( mouseHandled ) {
			return;
		}

		this._mouseMoved = false;

		// We may have missed mouseup (out of window)
		if ( this._mouseStarted ) {
			this._mouseUp( event );
		}

		this._mouseDownEvent = event;

		var that = this,
			btnIsLeft = ( event.which === 1 ),

			// event.target.nodeName works around a bug in IE 8 with
			// disabled inputs (#7620)
			elIsCancel = ( typeof this.options.cancel === "string" && event.target.nodeName ?
				$( event.target ).closest( this.options.cancel ).length : false );
		if ( !btnIsLeft || elIsCancel || !this._mouseCapture( event ) ) {
			return true;
		}

		this.mouseDelayMet = !this.options.delay;
		if ( !this.mouseDelayMet ) {
			this._mouseDelayTimer = setTimeout( function() {
				that.mouseDelayMet = true;
			}, this.options.delay );
		}

		if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) {
			this._mouseStarted = ( this._mouseStart( event ) !== false );
			if ( !this._mouseStarted ) {
				event.preventDefault();
				return true;
			}
		}

		// Click event may never have fired (Gecko & Opera)
		if ( true === $.data( event.target, this.widgetName + ".preventClickEvent" ) ) {
			$.removeData( event.target, this.widgetName + ".preventClickEvent" );
		}

		// These delegates are required to keep context
		this._mouseMoveDelegate = function( event ) {
			return that._mouseMove( event );
		};
		this._mouseUpDelegate = function( event ) {
			return that._mouseUp( event );
		};

		this.document
			.on( "mousemove." + this.widgetName, this._mouseMoveDelegate )
			.on( "mouseup." + this.widgetName, this._mouseUpDelegate );

		event.preventDefault();

		mouseHandled = true;
		return true;
	},

	_mouseMove: function( event ) {

		// Only check for mouseups outside the document if you've moved inside the document
		// at least once. This prevents the firing of mouseup in the case of IE<9, which will
		// fire a mousemove event if content is placed under the cursor. See #7778
		// Support: IE <9
		if ( this._mouseMoved ) {

			// IE mouseup check - mouseup happened when mouse was out of window
			if ( $.ui.ie && ( !document.documentMode || document.documentMode < 9 ) &&
					!event.button ) {
				return this._mouseUp( event );

			// Iframe mouseup check - mouseup occurred in another document
			} else if ( !event.which ) {

				// Support: Safari <=8 - 9
				// Safari sets which to 0 if you press any of the following keys
				// during a drag (#14461)
				if ( event.originalEvent.altKey || event.originalEvent.ctrlKey ||
						event.originalEvent.metaKey || event.originalEvent.shiftKey ) {
					this.ignoreMissingWhich = true;
				} else if ( !this.ignoreMissingWhich ) {
					return this._mouseUp( event );
				}
			}
		}

		if ( event.which || event.button ) {
			this._mouseMoved = true;
		}

		if ( this._mouseStarted ) {
			this._mouseDrag( event );
			return event.preventDefault();
		}

		if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) {
			this._mouseStarted =
				( this._mouseStart( this._mouseDownEvent, event ) !== false );
			if ( this._mouseStarted ) {
				this._mouseDrag( event );
			} else {
				this._mouseUp( event );
			}
		}

		return !this._mouseStarted;
	},

	_mouseUp: function( event ) {
		this.document
			.off( "mousemove." + this.widgetName, this._mouseMoveDelegate )
			.off( "mouseup." + this.widgetName, this._mouseUpDelegate );

		if ( this._mouseStarted ) {
			this._mouseStarted = false;

			if ( event.target === this._mouseDownEvent.target ) {
				$.data( event.target, this.widgetName + ".preventClickEvent", true );
			}

			this._mouseStop( event );
		}

		if ( this._mouseDelayTimer ) {
			clearTimeout( this._mouseDelayTimer );
			delete this._mouseDelayTimer;
		}

		this.ignoreMissingWhich = false;
		mouseHandled = false;
		event.preventDefault();
	},

	_mouseDistanceMet: function( event ) {
		return ( Math.max(
				Math.abs( this._mouseDownEvent.pageX - event.pageX ),
				Math.abs( this._mouseDownEvent.pageY - event.pageY )
			) >= this.options.distance
		);
	},

	_mouseDelayMet: function( /* event */ ) {
		return this.mouseDelayMet;
	},

	// These are placeholder methods, to be overriden by extending plugin
	_mouseStart: function( /* event */ ) {},
	_mouseDrag: function( /* event */ ) {},
	_mouseStop: function( /* event */ ) {},
	_mouseCapture: function( /* event */ ) {
		return true;
	}
} );



// $.ui.plugin is deprecated. Use $.widget() extensions instead.
var plugin = $.ui.plugin = {
	add: function( module, option, set ) {
		var i,
			proto = $.ui[ module ].prototype;
		for ( i in set ) {
			proto.plugins[ i ] = proto.plugins[ i ] || [];
			proto.plugins[ i ].push( [ option, set[ i ] ] );
		}
	},
	call: function( instance, name, args, allowDisconnected ) {
		var i,
			set = instance.plugins[ name ];

		if ( !set ) {
			return;
		}

		if ( !allowDisconnected && ( !instance.element[ 0 ].parentNode ||
				instance.element[ 0 ].parentNode.nodeType === 11 ) ) {
			return;
		}

		for ( i = 0; i < set.length; i++ ) {
			if ( instance.options[ set[ i ][ 0 ] ] ) {
				set[ i ][ 1 ].apply( instance.element, args );
			}
		}
	}
};



var safeBlur = $.ui.safeBlur = function( element ) {

	// Support: IE9 - 10 only
	// If the <body> is blurred, IE will switch windows, see #9420
	if ( element && element.nodeName.toLowerCase() !== "body" ) {
		$( element ).trigger( "blur" );
	}
};


/*!
 * jQuery UI Draggable 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Draggable
//>>group: Interactions
//>>description: Enables dragging functionality for any element.
//>>docs: http://api.jqueryui.com/draggable/
//>>demos: http://jqueryui.com/draggable/
//>>css.structure: ../../themes/base/draggable.css


$.widget( "ui.draggable", $.ui.mouse, {
	version: "1.13.2",
	widgetEventPrefix: "drag",
	options: {
		addClasses: true,
		appendTo: "parent",
		axis: false,
		connectToSortable: false,
		containment: false,
		cursor: "auto",
		cursorAt: false,
		grid: false,
		handle: false,
		helper: "original",
		iframeFix: false,
		opacity: false,
		refreshPositions: false,
		revert: false,
		revertDuration: 500,
		scope: "default",
		scroll: true,
		scrollSensitivity: 20,
		scrollSpeed: 20,
		snap: false,
		snapMode: "both",
		snapTolerance: 20,
		stack: false,
		zIndex: false,

		// Callbacks
		drag: null,
		start: null,
		stop: null
	},
	_create: function() {

		if ( this.options.helper === "original" ) {
			this._setPositionRelative();
		}
		if ( this.options.addClasses ) {
			this._addClass( "ui-draggable" );
		}
		this._setHandleClassName();

		this._mouseInit();
	},

	_setOption: function( key, value ) {
		this._super( key, value );
		if ( key === "handle" ) {
			this._removeHandleClassName();
			this._setHandleClassName();
		}
	},

	_destroy: function() {
		if ( ( this.helper || this.element ).is( ".ui-draggable-dragging" ) ) {
			this.destroyOnClear = true;
			return;
		}
		this._removeHandleClassName();
		this._mouseDestroy();
	},

	_mouseCapture: function( event ) {
		var o = this.options;

		// Among others, prevent a drag on a resizable-handle
		if ( this.helper || o.disabled ||
				$( event.target ).closest( ".ui-resizable-handle" ).length > 0 ) {
			return false;
		}

		//Quit if we're not on a valid handle
		this.handle = this._getHandle( event );
		if ( !this.handle ) {
			return false;
		}

		this._blurActiveElement( event );

		this._blockFrames( o.iframeFix === true ? "iframe" : o.iframeFix );

		return true;

	},

	_blockFrames: function( selector ) {
		this.iframeBlocks = this.document.find( selector ).map( function() {
			var iframe = $( this );

			return $( "<div>" )
				.css( "position", "absolute" )
				.appendTo( iframe.parent() )
				.outerWidth( iframe.outerWidth() )
				.outerHeight( iframe.outerHeight() )
				.offset( iframe.offset() )[ 0 ];
		} );
	},

	_unblockFrames: function() {
		if ( this.iframeBlocks ) {
			this.iframeBlocks.remove();
			delete this.iframeBlocks;
		}
	},

	_blurActiveElement: function( event ) {
		var activeElement = $.ui.safeActiveElement( this.document[ 0 ] ),
			target = $( event.target );

		// Don't blur if the event occurred on an element that is within
		// the currently focused element
		// See #10527, #12472
		if ( target.closest( activeElement ).length ) {
			return;
		}

		// Blur any element that currently has focus, see #4261
		$.ui.safeBlur( activeElement );
	},

	_mouseStart: function( event ) {

		var o = this.options;

		//Create and append the visible helper
		this.helper = this._createHelper( event );

		this._addClass( this.helper, "ui-draggable-dragging" );

		//Cache the helper size
		this._cacheHelperProportions();

		//If ddmanager is used for droppables, set the global draggable
		if ( $.ui.ddmanager ) {
			$.ui.ddmanager.current = this;
		}

		/*
		 * - Position generation -
		 * This block generates everything position related - it's the core of draggables.
		 */

		//Cache the margins of the original element
		this._cacheMargins();

		//Store the helper's css position
		this.cssPosition = this.helper.css( "position" );
		this.scrollParent = this.helper.scrollParent( true );
		this.offsetParent = this.helper.offsetParent();
		this.hasFixedAncestor = this.helper.parents().filter( function() {
				return $( this ).css( "position" ) === "fixed";
			} ).length > 0;

		//The element's absolute position on the page minus margins
		this.positionAbs = this.element.offset();
		this._refreshOffsets( event );

		//Generate the original position
		this.originalPosition = this.position = this._generatePosition( event, false );
		this.originalPageX = event.pageX;
		this.originalPageY = event.pageY;

		//Adjust the mouse offset relative to the helper if "cursorAt" is supplied
		if ( o.cursorAt ) {
			this._adjustOffsetFromHelper( o.cursorAt );
		}

		//Set a containment if given in the options
		this._setContainment();

		//Trigger event + callbacks
		if ( this._trigger( "start", event ) === false ) {
			this._clear();
			return false;
		}

		//Recache the helper size
		this._cacheHelperProportions();

		//Prepare the droppable offsets
		if ( $.ui.ddmanager && !o.dropBehaviour ) {
			$.ui.ddmanager.prepareOffsets( this, event );
		}

		// Execute the drag once - this causes the helper not to be visible before getting its
		// correct position
		this._mouseDrag( event, true );

		// If the ddmanager is used for droppables, inform the manager that dragging has started
		// (see #5003)
		if ( $.ui.ddmanager ) {
			$.ui.ddmanager.dragStart( this, event );
		}

		return true;
	},

	_refreshOffsets: function( event ) {
		this.offset = {
			top: this.positionAbs.top - this.margins.top,
			left: this.positionAbs.left - this.margins.left,
			scroll: false,
			parent: this._getParentOffset(),
			relative: this._getRelativeOffset()
		};

		this.offset.click = {
			left: event.pageX - this.offset.left,
			top: event.pageY - this.offset.top
		};
	},

	_mouseDrag: function( event, noPropagation ) {

		// reset any necessary cached properties (see #5009)
		if ( this.hasFixedAncestor ) {
			this.offset.parent = this._getParentOffset();
		}

		//Compute the helpers position
		this.position = this._generatePosition( event, true );
		this.positionAbs = this._convertPositionTo( "absolute" );

		//Call plugins and callbacks and use the resulting position if something is returned
		if ( !noPropagation ) {
			var ui = this._uiHash();
			if ( this._trigger( "drag", event, ui ) === false ) {
				this._mouseUp( new $.Event( "mouseup", event ) );
				return false;
			}
			this.position = ui.position;
		}

		this.helper[ 0 ].style.left = this.position.left + "px";
		this.helper[ 0 ].style.top = this.position.top + "px";

		if ( $.ui.ddmanager ) {
			$.ui.ddmanager.drag( this, event );
		}

		return false;
	},

	_mouseStop: function( event ) {

		//If we are using droppables, inform the manager about the drop
		var that = this,
			dropped = false;
		if ( $.ui.ddmanager && !this.options.dropBehaviour ) {
			dropped = $.ui.ddmanager.drop( this, event );
		}

		//if a drop comes from outside (a sortable)
		if ( this.dropped ) {
			dropped = this.dropped;
			this.dropped = false;
		}

		if ( ( this.options.revert === "invalid" && !dropped ) ||
				( this.options.revert === "valid" && dropped ) ||
				this.options.revert === true || ( typeof this.options.revert === "function" &&
				this.options.revert.call( this.element, dropped ) )
		) {
			$( this.helper ).animate(
				this.originalPosition,
				parseInt( this.options.revertDuration, 10 ),
				function() {
					if ( that._trigger( "stop", event ) !== false ) {
						that._clear();
					}
				}
			);
		} else {
			if ( this._trigger( "stop", event ) !== false ) {
				this._clear();
			}
		}

		return false;
	},

	_mouseUp: function( event ) {
		this._unblockFrames();

		// If the ddmanager is used for droppables, inform the manager that dragging has stopped
		// (see #5003)
		if ( $.ui.ddmanager ) {
			$.ui.ddmanager.dragStop( this, event );
		}

		// Only need to focus if the event occurred on the draggable itself, see #10527
		if ( this.handleElement.is( event.target ) ) {

			// The interaction is over; whether or not the click resulted in a drag,
			// focus the element
			this.element.trigger( "focus" );
		}

		return $.ui.mouse.prototype._mouseUp.call( this, event );
	},

	cancel: function() {

		if ( this.helper.is( ".ui-draggable-dragging" ) ) {
			this._mouseUp( new $.Event( "mouseup", { target: this.element[ 0 ] } ) );
		} else {
			this._clear();
		}

		return this;

	},

	_getHandle: function( event ) {
		return this.options.handle ?
			!!$( event.target ).closest( this.element.find( this.options.handle ) ).length :
			true;
	},

	_setHandleClassName: function() {
		this.handleElement = this.options.handle ?
			this.element.find( this.options.handle ) : this.element;
		this._addClass( this.handleElement, "ui-draggable-handle" );
	},

	_removeHandleClassName: function() {
		this._removeClass( this.handleElement, "ui-draggable-handle" );
	},

	_createHelper: function( event ) {

		var o = this.options,
			helperIsFunction = typeof o.helper === "function",
			helper = helperIsFunction ?
				$( o.helper.apply( this.element[ 0 ], [ event ] ) ) :
				( o.helper === "clone" ?
					this.element.clone().removeAttr( "id" ) :
					this.element );

		if ( !helper.parents( "body" ).length ) {
			helper.appendTo( ( o.appendTo === "parent" ?
				this.element[ 0 ].parentNode :
				o.appendTo ) );
		}

		// Http://bugs.jqueryui.com/ticket/9446
		// a helper function can return the original element
		// which wouldn't have been set to relative in _create
		if ( helperIsFunction && helper[ 0 ] === this.element[ 0 ] ) {
			this._setPositionRelative();
		}

		if ( helper[ 0 ] !== this.element[ 0 ] &&
				!( /(fixed|absolute)/ ).test( helper.css( "position" ) ) ) {
			helper.css( "position", "absolute" );
		}

		return helper;

	},

	_setPositionRelative: function() {
		if ( !( /^(?:r|a|f)/ ).test( this.element.css( "position" ) ) ) {
			this.element[ 0 ].style.position = "relative";
		}
	},

	_adjustOffsetFromHelper: function( obj ) {
		if ( typeof obj === "string" ) {
			obj = obj.split( " " );
		}
		if ( Array.isArray( obj ) ) {
			obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 };
		}
		if ( "left" in obj ) {
			this.offset.click.left = obj.left + this.margins.left;
		}
		if ( "right" in obj ) {
			this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
		}
		if ( "top" in obj ) {
			this.offset.click.top = obj.top + this.margins.top;
		}
		if ( "bottom" in obj ) {
			this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
		}
	},

	_isRootNode: function( element ) {
		return ( /(html|body)/i ).test( element.tagName ) || element === this.document[ 0 ];
	},

	_getParentOffset: function() {

		//Get the offsetParent and cache its position
		var po = this.offsetParent.offset(),
			document = this.document[ 0 ];

		// This is a special case where we need to modify a offset calculated on start, since the
		// following happened:
		// 1. The position of the helper is absolute, so it's position is calculated based on the
		// next positioned parent
		// 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't
		// the document, which means that the scroll is included in the initial calculation of the
		// offset of the parent, and never recalculated upon drag
		if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== document &&
				$.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) {
			po.left += this.scrollParent.scrollLeft();
			po.top += this.scrollParent.scrollTop();
		}

		if ( this._isRootNode( this.offsetParent[ 0 ] ) ) {
			po = { top: 0, left: 0 };
		}

		return {
			top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ),
			left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 )
		};

	},

	_getRelativeOffset: function() {
		if ( this.cssPosition !== "relative" ) {
			return { top: 0, left: 0 };
		}

		var p = this.element.position(),
			scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );

		return {
			top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) +
				( !scrollIsRootNode ? this.scrollParent.scrollTop() : 0 ),
			left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) +
				( !scrollIsRootNode ? this.scrollParent.scrollLeft() : 0 )
		};

	},

	_cacheMargins: function() {
		this.margins = {
			left: ( parseInt( this.element.css( "marginLeft" ), 10 ) || 0 ),
			top: ( parseInt( this.element.css( "marginTop" ), 10 ) || 0 ),
			right: ( parseInt( this.element.css( "marginRight" ), 10 ) || 0 ),
			bottom: ( parseInt( this.element.css( "marginBottom" ), 10 ) || 0 )
		};
	},

	_cacheHelperProportions: function() {
		this.helperProportions = {
			width: this.helper.outerWidth(),
			height: this.helper.outerHeight()
		};
	},

	_setContainment: function() {

		var isUserScrollable, c, ce,
			o = this.options,
			document = this.document[ 0 ];

		this.relativeContainer = null;

		if ( !o.containment ) {
			this.containment = null;
			return;
		}

		if ( o.containment === "window" ) {
			this.containment = [
				$( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
				$( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top,
				$( window ).scrollLeft() + $( window ).width() -
					this.helperProportions.width - this.margins.left,
				$( window ).scrollTop() +
					( $( window ).height() || document.body.parentNode.scrollHeight ) -
					this.helperProportions.height - this.margins.top
			];
			return;
		}

		if ( o.containment === "document" ) {
			this.containment = [
				0,
				0,
				$( document ).width() - this.helperProportions.width - this.margins.left,
				( $( document ).height() || document.body.parentNode.scrollHeight ) -
					this.helperProportions.height - this.margins.top
			];
			return;
		}

		if ( o.containment.constructor === Array ) {
			this.containment = o.containment;
			return;
		}

		if ( o.containment === "parent" ) {
			o.containment = this.helper[ 0 ].parentNode;
		}

		c = $( o.containment );
		ce = c[ 0 ];

		if ( !ce ) {
			return;
		}

		isUserScrollable = /(scroll|auto)/.test( c.css( "overflow" ) );

		this.containment = [
			( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) +
				( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ),
			( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) +
				( parseInt( c.css( "paddingTop" ), 10 ) || 0 ),
			( isUserScrollable ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) -
				( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) -
				( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) -
				this.helperProportions.width -
				this.margins.left -
				this.margins.right,
			( isUserScrollable ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) -
				( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) -
				( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) -
				this.helperProportions.height -
				this.margins.top -
				this.margins.bottom
		];
		this.relativeContainer = c;
	},

	_convertPositionTo: function( d, pos ) {

		if ( !pos ) {
			pos = this.position;
		}

		var mod = d === "absolute" ? 1 : -1,
			scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );

		return {
			top: (

				// The absolute mouse position
				pos.top	+

				// Only for relative positioned nodes: Relative offset from element to offset parent
				this.offset.relative.top * mod +

				// The offsetParent's offset without borders (offset + border)
				this.offset.parent.top * mod -
				( ( this.cssPosition === "fixed" ?
					-this.offset.scroll.top :
					( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) * mod )
			),
			left: (

				// The absolute mouse position
				pos.left +

				// Only for relative positioned nodes: Relative offset from element to offset parent
				this.offset.relative.left * mod +

				// The offsetParent's offset without borders (offset + border)
				this.offset.parent.left * mod	-
				( ( this.cssPosition === "fixed" ?
					-this.offset.scroll.left :
					( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) * mod )
			)
		};

	},

	_generatePosition: function( event, constrainPosition ) {

		var containment, co, top, left,
			o = this.options,
			scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ),
			pageX = event.pageX,
			pageY = event.pageY;

		// Cache the scroll
		if ( !scrollIsRootNode || !this.offset.scroll ) {
			this.offset.scroll = {
				top: this.scrollParent.scrollTop(),
				left: this.scrollParent.scrollLeft()
			};
		}

		/*
		 * - Position constraining -
		 * Constrain the position to a mix of grid, containment.
		 */

		// If we are not dragging yet, we won't check for options
		if ( constrainPosition ) {
			if ( this.containment ) {
				if ( this.relativeContainer ) {
					co = this.relativeContainer.offset();
					containment = [
						this.containment[ 0 ] + co.left,
						this.containment[ 1 ] + co.top,
						this.containment[ 2 ] + co.left,
						this.containment[ 3 ] + co.top
					];
				} else {
					containment = this.containment;
				}

				if ( event.pageX - this.offset.click.left < containment[ 0 ] ) {
					pageX = containment[ 0 ] + this.offset.click.left;
				}
				if ( event.pageY - this.offset.click.top < containment[ 1 ] ) {
					pageY = containment[ 1 ] + this.offset.click.top;
				}
				if ( event.pageX - this.offset.click.left > containment[ 2 ] ) {
					pageX = containment[ 2 ] + this.offset.click.left;
				}
				if ( event.pageY - this.offset.click.top > containment[ 3 ] ) {
					pageY = containment[ 3 ] + this.offset.click.top;
				}
			}

			if ( o.grid ) {

				//Check for grid elements set to 0 to prevent divide by 0 error causing invalid
				// argument errors in IE (see ticket #6950)
				top = o.grid[ 1 ] ? this.originalPageY + Math.round( ( pageY -
					this.originalPageY ) / o.grid[ 1 ] ) * o.grid[ 1 ] : this.originalPageY;
				pageY = containment ? ( ( top - this.offset.click.top >= containment[ 1 ] ||
					top - this.offset.click.top > containment[ 3 ] ) ?
						top :
						( ( top - this.offset.click.top >= containment[ 1 ] ) ?
							top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) : top;

				left = o.grid[ 0 ] ? this.originalPageX +
					Math.round( ( pageX - this.originalPageX ) / o.grid[ 0 ] ) * o.grid[ 0 ] :
					this.originalPageX;
				pageX = containment ? ( ( left - this.offset.click.left >= containment[ 0 ] ||
					left - this.offset.click.left > containment[ 2 ] ) ?
						left :
						( ( left - this.offset.click.left >= containment[ 0 ] ) ?
							left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) : left;
			}

			if ( o.axis === "y" ) {
				pageX = this.originalPageX;
			}

			if ( o.axis === "x" ) {
				pageY = this.originalPageY;
			}
		}

		return {
			top: (

				// The absolute mouse position
				pageY -

				// Click offset (relative to the element)
				this.offset.click.top -

				// Only for relative positioned nodes: Relative offset from element to offset parent
				this.offset.relative.top -

				// The offsetParent's offset without borders (offset + border)
				this.offset.parent.top +
				( this.cssPosition === "fixed" ?
					-this.offset.scroll.top :
					( scrollIsRootNode ? 0 : this.offset.scroll.top ) )
			),
			left: (

				// The absolute mouse position
				pageX -

				// Click offset (relative to the element)
				this.offset.click.left -

				// Only for relative positioned nodes: Relative offset from element to offset parent
				this.offset.relative.left -

				// The offsetParent's offset without borders (offset + border)
				this.offset.parent.left +
				( this.cssPosition === "fixed" ?
					-this.offset.scroll.left :
					( scrollIsRootNode ? 0 : this.offset.scroll.left ) )
			)
		};

	},

	_clear: function() {
		this._removeClass( this.helper, "ui-draggable-dragging" );
		if ( this.helper[ 0 ] !== this.element[ 0 ] && !this.cancelHelperRemoval ) {
			this.helper.remove();
		}
		this.helper = null;
		this.cancelHelperRemoval = false;
		if ( this.destroyOnClear ) {
			this.destroy();
		}
	},

	// From now on bulk stuff - mainly helpers

	_trigger: function( type, event, ui ) {
		ui = ui || this._uiHash();
		$.ui.plugin.call( this, type, [ event, ui, this ], true );

		// Absolute position and offset (see #6884 ) have to be recalculated after plugins
		if ( /^(drag|start|stop)/.test( type ) ) {
			this.positionAbs = this._convertPositionTo( "absolute" );
			ui.offset = this.positionAbs;
		}
		return $.Widget.prototype._trigger.call( this, type, event, ui );
	},

	plugins: {},

	_uiHash: function() {
		return {
			helper: this.helper,
			position: this.position,
			originalPosition: this.originalPosition,
			offset: this.positionAbs
		};
	}

} );

$.ui.plugin.add( "draggable", "connectToSortable", {
	start: function( event, ui, draggable ) {
		var uiSortable = $.extend( {}, ui, {
			item: draggable.element
		} );

		draggable.sortables = [];
		$( draggable.options.connectToSortable ).each( function() {
			var sortable = $( this ).sortable( "instance" );

			if ( sortable && !sortable.options.disabled ) {
				draggable.sortables.push( sortable );

				// RefreshPositions is called at drag start to refresh the containerCache
				// which is used in drag. This ensures it's initialized and synchronized
				// with any changes that might have happened on the page since initialization.
				sortable.refreshPositions();
				sortable._trigger( "activate", event, uiSortable );
			}
		} );
	},
	stop: function( event, ui, draggable ) {
		var uiSortable = $.extend( {}, ui, {
			item: draggable.element
		} );

		draggable.cancelHelperRemoval = false;

		$.each( draggable.sortables, function() {
			var sortable = this;

			if ( sortable.isOver ) {
				sortable.isOver = 0;

				// Allow this sortable to handle removing the helper
				draggable.cancelHelperRemoval = true;
				sortable.cancelHelperRemoval = false;

				// Use _storedCSS To restore properties in the sortable,
				// as this also handles revert (#9675) since the draggable
				// may have modified them in unexpected ways (#8809)
				sortable._storedCSS = {
					position: sortable.placeholder.css( "position" ),
					top: sortable.placeholder.css( "top" ),
					left: sortable.placeholder.css( "left" )
				};

				sortable._mouseStop( event );

				// Once drag has ended, the sortable should return to using
				// its original helper, not the shared helper from draggable
				sortable.options.helper = sortable.options._helper;
			} else {

				// Prevent this Sortable from removing the helper.
				// However, don't set the draggable to remove the helper
				// either as another connected Sortable may yet handle the removal.
				sortable.cancelHelperRemoval = true;

				sortable._trigger( "deactivate", event, uiSortable );
			}
		} );
	},
	drag: function( event, ui, draggable ) {
		$.each( draggable.sortables, function() {
			var innermostIntersecting = false,
				sortable = this;

			// Copy over variables that sortable's _intersectsWith uses
			sortable.positionAbs = draggable.positionAbs;
			sortable.helperProportions = draggable.helperProportions;
			sortable.offset.click = draggable.offset.click;

			if ( sortable._intersectsWith( sortable.containerCache ) ) {
				innermostIntersecting = true;

				$.each( draggable.sortables, function() {

					// Copy over variables that sortable's _intersectsWith uses
					this.positionAbs = draggable.positionAbs;
					this.helperProportions = draggable.helperProportions;
					this.offset.click = draggable.offset.click;

					if ( this !== sortable &&
							this._intersectsWith( this.containerCache ) &&
							$.contains( sortable.element[ 0 ], this.element[ 0 ] ) ) {
						innermostIntersecting = false;
					}

					return innermostIntersecting;
				} );
			}

			if ( innermostIntersecting ) {

				// If it intersects, we use a little isOver variable and set it once,
				// so that the move-in stuff gets fired only once.
				if ( !sortable.isOver ) {
					sortable.isOver = 1;

					// Store draggable's parent in case we need to reappend to it later.
					draggable._parent = ui.helper.parent();

					sortable.currentItem = ui.helper
						.appendTo( sortable.element )
						.data( "ui-sortable-item", true );

					// Store helper option to later restore it
					sortable.options._helper = sortable.options.helper;

					sortable.options.helper = function() {
						return ui.helper[ 0 ];
					};

					// Fire the start events of the sortable with our passed browser event,
					// and our own helper (so it doesn't create a new one)
					event.target = sortable.currentItem[ 0 ];
					sortable._mouseCapture( event, true );
					sortable._mouseStart( event, true, true );

					// Because the browser event is way off the new appended portlet,
					// modify necessary variables to reflect the changes
					sortable.offset.click.top = draggable.offset.click.top;
					sortable.offset.click.left = draggable.offset.click.left;
					sortable.offset.parent.left -= draggable.offset.parent.left -
						sortable.offset.parent.left;
					sortable.offset.parent.top -= draggable.offset.parent.top -
						sortable.offset.parent.top;

					draggable._trigger( "toSortable", event );

					// Inform draggable that the helper is in a valid drop zone,
					// used solely in the revert option to handle "valid/invalid".
					draggable.dropped = sortable.element;

					// Need to refreshPositions of all sortables in the case that
					// adding to one sortable changes the location of the other sortables (#9675)
					$.each( draggable.sortables, function() {
						this.refreshPositions();
					} );

					// Hack so receive/update callbacks work (mostly)
					draggable.currentItem = draggable.element;
					sortable.fromOutside = draggable;
				}

				if ( sortable.currentItem ) {
					sortable._mouseDrag( event );

					// Copy the sortable's position because the draggable's can potentially reflect
					// a relative position, while sortable is always absolute, which the dragged
					// element has now become. (#8809)
					ui.position = sortable.position;
				}
			} else {

				// If it doesn't intersect with the sortable, and it intersected before,
				// we fake the drag stop of the sortable, but make sure it doesn't remove
				// the helper by using cancelHelperRemoval.
				if ( sortable.isOver ) {

					sortable.isOver = 0;
					sortable.cancelHelperRemoval = true;

					// Calling sortable's mouseStop would trigger a revert,
					// so revert must be temporarily false until after mouseStop is called.
					sortable.options._revert = sortable.options.revert;
					sortable.options.revert = false;

					sortable._trigger( "out", event, sortable._uiHash( sortable ) );
					sortable._mouseStop( event, true );

					// Restore sortable behaviors that were modfied
					// when the draggable entered the sortable area (#9481)
					sortable.options.revert = sortable.options._revert;
					sortable.options.helper = sortable.options._helper;

					if ( sortable.placeholder ) {
						sortable.placeholder.remove();
					}

					// Restore and recalculate the draggable's offset considering the sortable
					// may have modified them in unexpected ways. (#8809, #10669)
					ui.helper.appendTo( draggable._parent );
					draggable._refreshOffsets( event );
					ui.position = draggable._generatePosition( event, true );

					draggable._trigger( "fromSortable", event );

					// Inform draggable that the helper is no longer in a valid drop zone
					draggable.dropped = false;

					// Need to refreshPositions of all sortables just in case removing
					// from one sortable changes the location of other sortables (#9675)
					$.each( draggable.sortables, function() {
						this.refreshPositions();
					} );
				}
			}
		} );
	}
} );

$.ui.plugin.add( "draggable", "cursor", {
	start: function( event, ui, instance ) {
		var t = $( "body" ),
			o = instance.options;

		if ( t.css( "cursor" ) ) {
			o._cursor = t.css( "cursor" );
		}
		t.css( "cursor", o.cursor );
	},
	stop: function( event, ui, instance ) {
		var o = instance.options;
		if ( o._cursor ) {
			$( "body" ).css( "cursor", o._cursor );
		}
	}
} );

$.ui.plugin.add( "draggable", "opacity", {
	start: function( event, ui, instance ) {
		var t = $( ui.helper ),
			o = instance.options;
		if ( t.css( "opacity" ) ) {
			o._opacity = t.css( "opacity" );
		}
		t.css( "opacity", o.opacity );
	},
	stop: function( event, ui, instance ) {
		var o = instance.options;
		if ( o._opacity ) {
			$( ui.helper ).css( "opacity", o._opacity );
		}
	}
} );

$.ui.plugin.add( "draggable", "scroll", {
	start: function( event, ui, i ) {
		if ( !i.scrollParentNotHidden ) {
			i.scrollParentNotHidden = i.helper.scrollParent( false );
		}

		if ( i.scrollParentNotHidden[ 0 ] !== i.document[ 0 ] &&
				i.scrollParentNotHidden[ 0 ].tagName !== "HTML" ) {
			i.overflowOffset = i.scrollParentNotHidden.offset();
		}
	},
	drag: function( event, ui, i  ) {

		var o = i.options,
			scrolled = false,
			scrollParent = i.scrollParentNotHidden[ 0 ],
			document = i.document[ 0 ];

		if ( scrollParent !== document && scrollParent.tagName !== "HTML" ) {
			if ( !o.axis || o.axis !== "x" ) {
				if ( ( i.overflowOffset.top + scrollParent.offsetHeight ) - event.pageY <
						o.scrollSensitivity ) {
					scrollParent.scrollTop = scrolled = scrollParent.scrollTop + o.scrollSpeed;
				} else if ( event.pageY - i.overflowOffset.top < o.scrollSensitivity ) {
					scrollParent.scrollTop = scrolled = scrollParent.scrollTop - o.scrollSpeed;
				}
			}

			if ( !o.axis || o.axis !== "y" ) {
				if ( ( i.overflowOffset.left + scrollParent.offsetWidth ) - event.pageX <
						o.scrollSensitivity ) {
					scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft + o.scrollSpeed;
				} else if ( event.pageX - i.overflowOffset.left < o.scrollSensitivity ) {
					scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft - o.scrollSpeed;
				}
			}

		} else {

			if ( !o.axis || o.axis !== "x" ) {
				if ( event.pageY - $( document ).scrollTop() < o.scrollSensitivity ) {
					scrolled = $( document ).scrollTop( $( document ).scrollTop() - o.scrollSpeed );
				} else if ( $( window ).height() - ( event.pageY - $( document ).scrollTop() ) <
						o.scrollSensitivity ) {
					scrolled = $( document ).scrollTop( $( document ).scrollTop() + o.scrollSpeed );
				}
			}

			if ( !o.axis || o.axis !== "y" ) {
				if ( event.pageX - $( document ).scrollLeft() < o.scrollSensitivity ) {
					scrolled = $( document ).scrollLeft(
						$( document ).scrollLeft() - o.scrollSpeed
					);
				} else if ( $( window ).width() - ( event.pageX - $( document ).scrollLeft() ) <
						o.scrollSensitivity ) {
					scrolled = $( document ).scrollLeft(
						$( document ).scrollLeft() + o.scrollSpeed
					);
				}
			}

		}

		if ( scrolled !== false && $.ui.ddmanager && !o.dropBehaviour ) {
			$.ui.ddmanager.prepareOffsets( i, event );
		}

	}
} );

$.ui.plugin.add( "draggable", "snap", {
	start: function( event, ui, i ) {

		var o = i.options;

		i.snapElements = [];

		$( o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap )
			.each( function() {
				var $t = $( this ),
					$o = $t.offset();
				if ( this !== i.element[ 0 ] ) {
					i.snapElements.push( {
						item: this,
						width: $t.outerWidth(), height: $t.outerHeight(),
						top: $o.top, left: $o.left
					} );
				}
			} );

	},
	drag: function( event, ui, inst ) {

		var ts, bs, ls, rs, l, r, t, b, i, first,
			o = inst.options,
			d = o.snapTolerance,
			x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
			y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;

		for ( i = inst.snapElements.length - 1; i >= 0; i-- ) {

			l = inst.snapElements[ i ].left - inst.margins.left;
			r = l + inst.snapElements[ i ].width;
			t = inst.snapElements[ i ].top - inst.margins.top;
			b = t + inst.snapElements[ i ].height;

			if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d ||
					!$.contains( inst.snapElements[ i ].item.ownerDocument,
					inst.snapElements[ i ].item ) ) {
				if ( inst.snapElements[ i ].snapping ) {
					if ( inst.options.snap.release ) {
						inst.options.snap.release.call(
							inst.element,
							event,
							$.extend( inst._uiHash(), { snapItem: inst.snapElements[ i ].item } )
						);
					}
				}
				inst.snapElements[ i ].snapping = false;
				continue;
			}

			if ( o.snapMode !== "inner" ) {
				ts = Math.abs( t - y2 ) <= d;
				bs = Math.abs( b - y1 ) <= d;
				ls = Math.abs( l - x2 ) <= d;
				rs = Math.abs( r - x1 ) <= d;
				if ( ts ) {
					ui.position.top = inst._convertPositionTo( "relative", {
						top: t - inst.helperProportions.height,
						left: 0
					} ).top;
				}
				if ( bs ) {
					ui.position.top = inst._convertPositionTo( "relative", {
						top: b,
						left: 0
					} ).top;
				}
				if ( ls ) {
					ui.position.left = inst._convertPositionTo( "relative", {
						top: 0,
						left: l - inst.helperProportions.width
					} ).left;
				}
				if ( rs ) {
					ui.position.left = inst._convertPositionTo( "relative", {
						top: 0,
						left: r
					} ).left;
				}
			}

			first = ( ts || bs || ls || rs );

			if ( o.snapMode !== "outer" ) {
				ts = Math.abs( t - y1 ) <= d;
				bs = Math.abs( b - y2 ) <= d;
				ls = Math.abs( l - x1 ) <= d;
				rs = Math.abs( r - x2 ) <= d;
				if ( ts ) {
					ui.position.top = inst._convertPositionTo( "relative", {
						top: t,
						left: 0
					} ).top;
				}
				if ( bs ) {
					ui.position.top = inst._convertPositionTo( "relative", {
						top: b - inst.helperProportions.height,
						left: 0
					} ).top;
				}
				if ( ls ) {
					ui.position.left = inst._convertPositionTo( "relative", {
						top: 0,
						left: l
					} ).left;
				}
				if ( rs ) {
					ui.position.left = inst._convertPositionTo( "relative", {
						top: 0,
						left: r - inst.helperProportions.width
					} ).left;
				}
			}

			if ( !inst.snapElements[ i ].snapping && ( ts || bs || ls || rs || first ) ) {
				if ( inst.options.snap.snap ) {
					inst.options.snap.snap.call(
						inst.element,
						event,
						$.extend( inst._uiHash(), {
							snapItem: inst.snapElements[ i ].item
						} ) );
				}
			}
			inst.snapElements[ i ].snapping = ( ts || bs || ls || rs || first );

		}

	}
} );

$.ui.plugin.add( "draggable", "stack", {
	start: function( event, ui, instance ) {
		var min,
			o = instance.options,
			group = $.makeArray( $( o.stack ) ).sort( function( a, b ) {
				return ( parseInt( $( a ).css( "zIndex" ), 10 ) || 0 ) -
					( parseInt( $( b ).css( "zIndex" ), 10 ) || 0 );
			} );

		if ( !group.length ) {
			return;
		}

		min = parseInt( $( group[ 0 ] ).css( "zIndex" ), 10 ) || 0;
		$( group ).each( function( i ) {
			$( this ).css( "zIndex", min + i );
		} );
		this.css( "zIndex", ( min + group.length ) );
	}
} );

$.ui.plugin.add( "draggable", "zIndex", {
	start: function( event, ui, instance ) {
		var t = $( ui.helper ),
			o = instance.options;

		if ( t.css( "zIndex" ) ) {
			o._zIndex = t.css( "zIndex" );
		}
		t.css( "zIndex", o.zIndex );
	},
	stop: function( event, ui, instance ) {
		var o = instance.options;

		if ( o._zIndex ) {
			$( ui.helper ).css( "zIndex", o._zIndex );
		}
	}
} );

var widgetsDraggable = $.ui.draggable;


/*!
 * jQuery UI Resizable 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Resizable
//>>group: Interactions
//>>description: Enables resize functionality for any element.
//>>docs: http://api.jqueryui.com/resizable/
//>>demos: http://jqueryui.com/resizable/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/resizable.css
//>>css.theme: ../../themes/base/theme.css


$.widget( "ui.resizable", $.ui.mouse, {
	version: "1.13.2",
	widgetEventPrefix: "resize",
	options: {
		alsoResize: false,
		animate: false,
		animateDuration: "slow",
		animateEasing: "swing",
		aspectRatio: false,
		autoHide: false,
		classes: {
			"ui-resizable-se": "ui-icon ui-icon-gripsmall-diagonal-se"
		},
		containment: false,
		ghost: false,
		grid: false,
		handles: "e,s,se",
		helper: false,
		maxHeight: null,
		maxWidth: null,
		minHeight: 10,
		minWidth: 10,

		// See #7960
		zIndex: 90,

		// Callbacks
		resize: null,
		start: null,
		stop: null
	},

	_num: function( value ) {
		return parseFloat( value ) || 0;
	},

	_isNumber: function( value ) {
		return !isNaN( parseFloat( value ) );
	},

	_hasScroll: function( el, a ) {

		if ( $( el ).css( "overflow" ) === "hidden" ) {
			return false;
		}

		var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
			has = false;

		if ( el[ scroll ] > 0 ) {
			return true;
		}

		// TODO: determine which cases actually cause this to happen
		// if the element doesn't have the scroll set, see if it's possible to
		// set the scroll
		try {
			el[ scroll ] = 1;
			has = ( el[ scroll ] > 0 );
			el[ scroll ] = 0;
		} catch ( e ) {

			// `el` might be a string, then setting `scroll` will throw
			// an error in strict mode; ignore it.
		}
		return has;
	},

	_create: function() {

		var margins,
			o = this.options,
			that = this;
		this._addClass( "ui-resizable" );

		$.extend( this, {
			_aspectRatio: !!( o.aspectRatio ),
			aspectRatio: o.aspectRatio,
			originalElement: this.element,
			_proportionallyResizeElements: [],
			_helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null
		} );

		// Wrap the element if it cannot hold child nodes
		if ( this.element[ 0 ].nodeName.match( /^(canvas|textarea|input|select|button|img)$/i ) ) {

			this.element.wrap(
				$( "<div class='ui-wrapper'></div>" ).css( {
					overflow: "hidden",
					position: this.element.css( "position" ),
					width: this.element.outerWidth(),
					height: this.element.outerHeight(),
					top: this.element.css( "top" ),
					left: this.element.css( "left" )
				} )
			);

			this.element = this.element.parent().data(
				"ui-resizable", this.element.resizable( "instance" )
			);

			this.elementIsWrapper = true;

			margins = {
				marginTop: this.originalElement.css( "marginTop" ),
				marginRight: this.originalElement.css( "marginRight" ),
				marginBottom: this.originalElement.css( "marginBottom" ),
				marginLeft: this.originalElement.css( "marginLeft" )
			};

			this.element.css( margins );
			this.originalElement.css( "margin", 0 );

			// support: Safari
			// Prevent Safari textarea resize
			this.originalResizeStyle = this.originalElement.css( "resize" );
			this.originalElement.css( "resize", "none" );

			this._proportionallyResizeElements.push( this.originalElement.css( {
				position: "static",
				zoom: 1,
				display: "block"
			} ) );

			// Support: IE9
			// avoid IE jump (hard set the margin)
			this.originalElement.css( margins );

			this._proportionallyResize();
		}

		this._setupHandles();

		if ( o.autoHide ) {
			$( this.element )
				.on( "mouseenter", function() {
					if ( o.disabled ) {
						return;
					}
					that._removeClass( "ui-resizable-autohide" );
					that._handles.show();
				} )
				.on( "mouseleave", function() {
					if ( o.disabled ) {
						return;
					}
					if ( !that.resizing ) {
						that._addClass( "ui-resizable-autohide" );
						that._handles.hide();
					}
				} );
		}

		this._mouseInit();
	},

	_destroy: function() {

		this._mouseDestroy();
		this._addedHandles.remove();

		var wrapper,
			_destroy = function( exp ) {
				$( exp )
					.removeData( "resizable" )
					.removeData( "ui-resizable" )
					.off( ".resizable" );
			};

		// TODO: Unwrap at same DOM position
		if ( this.elementIsWrapper ) {
			_destroy( this.element );
			wrapper = this.element;
			this.originalElement.css( {
				position: wrapper.css( "position" ),
				width: wrapper.outerWidth(),
				height: wrapper.outerHeight(),
				top: wrapper.css( "top" ),
				left: wrapper.css( "left" )
			} ).insertAfter( wrapper );
			wrapper.remove();
		}

		this.originalElement.css( "resize", this.originalResizeStyle );
		_destroy( this.originalElement );

		return this;
	},

	_setOption: function( key, value ) {
		this._super( key, value );

		switch ( key ) {
		case "handles":
			this._removeHandles();
			this._setupHandles();
			break;
		case "aspectRatio":
			this._aspectRatio = !!value;
			break;
		default:
			break;
		}
	},

	_setupHandles: function() {
		var o = this.options, handle, i, n, hname, axis, that = this;
		this.handles = o.handles ||
			( !$( ".ui-resizable-handle", this.element ).length ?
				"e,s,se" : {
					n: ".ui-resizable-n",
					e: ".ui-resizable-e",
					s: ".ui-resizable-s",
					w: ".ui-resizable-w",
					se: ".ui-resizable-se",
					sw: ".ui-resizable-sw",
					ne: ".ui-resizable-ne",
					nw: ".ui-resizable-nw"
				} );

		this._handles = $();
		this._addedHandles = $();
		if ( this.handles.constructor === String ) {

			if ( this.handles === "all" ) {
				this.handles = "n,e,s,w,se,sw,ne,nw";
			}

			n = this.handles.split( "," );
			this.handles = {};

			for ( i = 0; i < n.length; i++ ) {

				handle = String.prototype.trim.call( n[ i ] );
				hname = "ui-resizable-" + handle;
				axis = $( "<div>" );
				this._addClass( axis, "ui-resizable-handle " + hname );

				axis.css( { zIndex: o.zIndex } );

				this.handles[ handle ] = ".ui-resizable-" + handle;
				if ( !this.element.children( this.handles[ handle ] ).length ) {
					this.element.append( axis );
					this._addedHandles = this._addedHandles.add( axis );
				}
			}

		}

		this._renderAxis = function( target ) {

			var i, axis, padPos, padWrapper;

			target = target || this.element;

			for ( i in this.handles ) {

				if ( this.handles[ i ].constructor === String ) {
					this.handles[ i ] = this.element.children( this.handles[ i ] ).first().show();
				} else if ( this.handles[ i ].jquery || this.handles[ i ].nodeType ) {
					this.handles[ i ] = $( this.handles[ i ] );
					this._on( this.handles[ i ], { "mousedown": that._mouseDown } );
				}

				if ( this.elementIsWrapper &&
						this.originalElement[ 0 ]
							.nodeName
							.match( /^(textarea|input|select|button)$/i ) ) {
					axis = $( this.handles[ i ], this.element );

					padWrapper = /sw|ne|nw|se|n|s/.test( i ) ?
						axis.outerHeight() :
						axis.outerWidth();

					padPos = [ "padding",
						/ne|nw|n/.test( i ) ? "Top" :
						/se|sw|s/.test( i ) ? "Bottom" :
						/^e$/.test( i ) ? "Right" : "Left" ].join( "" );

					target.css( padPos, padWrapper );

					this._proportionallyResize();
				}

				this._handles = this._handles.add( this.handles[ i ] );
			}
		};

		// TODO: make renderAxis a prototype function
		this._renderAxis( this.element );

		this._handles = this._handles.add( this.element.find( ".ui-resizable-handle" ) );
		this._handles.disableSelection();

		this._handles.on( "mouseover", function() {
			if ( !that.resizing ) {
				if ( this.className ) {
					axis = this.className.match( /ui-resizable-(se|sw|ne|nw|n|e|s|w)/i );
				}
				that.axis = axis && axis[ 1 ] ? axis[ 1 ] : "se";
			}
		} );

		if ( o.autoHide ) {
			this._handles.hide();
			this._addClass( "ui-resizable-autohide" );
		}
	},

	_removeHandles: function() {
		this._addedHandles.remove();
	},

	_mouseCapture: function( event ) {
		var i, handle,
			capture = false;

		for ( i in this.handles ) {
			handle = $( this.handles[ i ] )[ 0 ];
			if ( handle === event.target || $.contains( handle, event.target ) ) {
				capture = true;
			}
		}

		return !this.options.disabled && capture;
	},

	_mouseStart: function( event ) {

		var curleft, curtop, cursor,
			o = this.options,
			el = this.element;

		this.resizing = true;

		this._renderProxy();

		curleft = this._num( this.helper.css( "left" ) );
		curtop = this._num( this.helper.css( "top" ) );

		if ( o.containment ) {
			curleft += $( o.containment ).scrollLeft() || 0;
			curtop += $( o.containment ).scrollTop() || 0;
		}

		this.offset = this.helper.offset();
		this.position = { left: curleft, top: curtop };

		this.size = this._helper ? {
				width: this.helper.width(),
				height: this.helper.height()
			} : {
				width: el.width(),
				height: el.height()
			};

		this.originalSize = this._helper ? {
				width: el.outerWidth(),
				height: el.outerHeight()
			} : {
				width: el.width(),
				height: el.height()
			};

		this.sizeDiff = {
			width: el.outerWidth() - el.width(),
			height: el.outerHeight() - el.height()
		};

		this.originalPosition = { left: curleft, top: curtop };
		this.originalMousePosition = { left: event.pageX, top: event.pageY };

		this.aspectRatio = ( typeof o.aspectRatio === "number" ) ?
			o.aspectRatio :
			( ( this.originalSize.width / this.originalSize.height ) || 1 );

		cursor = $( ".ui-resizable-" + this.axis ).css( "cursor" );
		$( "body" ).css( "cursor", cursor === "auto" ? this.axis + "-resize" : cursor );

		this._addClass( "ui-resizable-resizing" );
		this._propagate( "start", event );
		return true;
	},

	_mouseDrag: function( event ) {

		var data, props,
			smp = this.originalMousePosition,
			a = this.axis,
			dx = ( event.pageX - smp.left ) || 0,
			dy = ( event.pageY - smp.top ) || 0,
			trigger = this._change[ a ];

		this._updatePrevProperties();

		if ( !trigger ) {
			return false;
		}

		data = trigger.apply( this, [ event, dx, dy ] );

		this._updateVirtualBoundaries( event.shiftKey );
		if ( this._aspectRatio || event.shiftKey ) {
			data = this._updateRatio( data, event );
		}

		data = this._respectSize( data, event );

		this._updateCache( data );

		this._propagate( "resize", event );

		props = this._applyChanges();

		if ( !this._helper && this._proportionallyResizeElements.length ) {
			this._proportionallyResize();
		}

		if ( !$.isEmptyObject( props ) ) {
			this._updatePrevProperties();
			this._trigger( "resize", event, this.ui() );
			this._applyChanges();
		}

		return false;
	},

	_mouseStop: function( event ) {

		this.resizing = false;
		var pr, ista, soffseth, soffsetw, s, left, top,
			o = this.options, that = this;

		if ( this._helper ) {

			pr = this._proportionallyResizeElements;
			ista = pr.length && ( /textarea/i ).test( pr[ 0 ].nodeName );
			soffseth = ista && this._hasScroll( pr[ 0 ], "left" ) ? 0 : that.sizeDiff.height;
			soffsetw = ista ? 0 : that.sizeDiff.width;

			s = {
				width: ( that.helper.width()  - soffsetw ),
				height: ( that.helper.height() - soffseth )
			};
			left = ( parseFloat( that.element.css( "left" ) ) +
				( that.position.left - that.originalPosition.left ) ) || null;
			top = ( parseFloat( that.element.css( "top" ) ) +
				( that.position.top - that.originalPosition.top ) ) || null;

			if ( !o.animate ) {
				this.element.css( $.extend( s, { top: top, left: left } ) );
			}

			that.helper.height( that.size.height );
			that.helper.width( that.size.width );

			if ( this._helper && !o.animate ) {
				this._proportionallyResize();
			}
		}

		$( "body" ).css( "cursor", "auto" );

		this._removeClass( "ui-resizable-resizing" );

		this._propagate( "stop", event );

		if ( this._helper ) {
			this.helper.remove();
		}

		return false;

	},

	_updatePrevProperties: function() {
		this.prevPosition = {
			top: this.position.top,
			left: this.position.left
		};
		this.prevSize = {
			width: this.size.width,
			height: this.size.height
		};
	},

	_applyChanges: function() {
		var props = {};

		if ( this.position.top !== this.prevPosition.top ) {
			props.top = this.position.top + "px";
		}
		if ( this.position.left !== this.prevPosition.left ) {
			props.left = this.position.left + "px";
		}
		if ( this.size.width !== this.prevSize.width ) {
			props.width = this.size.width + "px";
		}
		if ( this.size.height !== this.prevSize.height ) {
			props.height = this.size.height + "px";
		}

		this.helper.css( props );

		return props;
	},

	_updateVirtualBoundaries: function( forceAspectRatio ) {
		var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b,
			o = this.options;

		b = {
			minWidth: this._isNumber( o.minWidth ) ? o.minWidth : 0,
			maxWidth: this._isNumber( o.maxWidth ) ? o.maxWidth : Infinity,
			minHeight: this._isNumber( o.minHeight ) ? o.minHeight : 0,
			maxHeight: this._isNumber( o.maxHeight ) ? o.maxHeight : Infinity
		};

		if ( this._aspectRatio || forceAspectRatio ) {
			pMinWidth = b.minHeight * this.aspectRatio;
			pMinHeight = b.minWidth / this.aspectRatio;
			pMaxWidth = b.maxHeight * this.aspectRatio;
			pMaxHeight = b.maxWidth / this.aspectRatio;

			if ( pMinWidth > b.minWidth ) {
				b.minWidth = pMinWidth;
			}
			if ( pMinHeight > b.minHeight ) {
				b.minHeight = pMinHeight;
			}
			if ( pMaxWidth < b.maxWidth ) {
				b.maxWidth = pMaxWidth;
			}
			if ( pMaxHeight < b.maxHeight ) {
				b.maxHeight = pMaxHeight;
			}
		}
		this._vBoundaries = b;
	},

	_updateCache: function( data ) {
		this.offset = this.helper.offset();
		if ( this._isNumber( data.left ) ) {
			this.position.left = data.left;
		}
		if ( this._isNumber( data.top ) ) {
			this.position.top = data.top;
		}
		if ( this._isNumber( data.height ) ) {
			this.size.height = data.height;
		}
		if ( this._isNumber( data.width ) ) {
			this.size.width = data.width;
		}
	},

	_updateRatio: function( data ) {

		var cpos = this.position,
			csize = this.size,
			a = this.axis;

		if ( this._isNumber( data.height ) ) {
			data.width = ( data.height * this.aspectRatio );
		} else if ( this._isNumber( data.width ) ) {
			data.height = ( data.width / this.aspectRatio );
		}

		if ( a === "sw" ) {
			data.left = cpos.left + ( csize.width - data.width );
			data.top = null;
		}
		if ( a === "nw" ) {
			data.top = cpos.top + ( csize.height - data.height );
			data.left = cpos.left + ( csize.width - data.width );
		}

		return data;
	},

	_respectSize: function( data ) {

		var o = this._vBoundaries,
			a = this.axis,
			ismaxw = this._isNumber( data.width ) && o.maxWidth && ( o.maxWidth < data.width ),
			ismaxh = this._isNumber( data.height ) && o.maxHeight && ( o.maxHeight < data.height ),
			isminw = this._isNumber( data.width ) && o.minWidth && ( o.minWidth > data.width ),
			isminh = this._isNumber( data.height ) && o.minHeight && ( o.minHeight > data.height ),
			dw = this.originalPosition.left + this.originalSize.width,
			dh = this.originalPosition.top + this.originalSize.height,
			cw = /sw|nw|w/.test( a ), ch = /nw|ne|n/.test( a );
		if ( isminw ) {
			data.width = o.minWidth;
		}
		if ( isminh ) {
			data.height = o.minHeight;
		}
		if ( ismaxw ) {
			data.width = o.maxWidth;
		}
		if ( ismaxh ) {
			data.height = o.maxHeight;
		}

		if ( isminw && cw ) {
			data.left = dw - o.minWidth;
		}
		if ( ismaxw && cw ) {
			data.left = dw - o.maxWidth;
		}
		if ( isminh && ch ) {
			data.top = dh - o.minHeight;
		}
		if ( ismaxh && ch ) {
			data.top = dh - o.maxHeight;
		}

		// Fixing jump error on top/left - bug #2330
		if ( !data.width && !data.height && !data.left && data.top ) {
			data.top = null;
		} else if ( !data.width && !data.height && !data.top && data.left ) {
			data.left = null;
		}

		return data;
	},

	_getPaddingPlusBorderDimensions: function( element ) {
		var i = 0,
			widths = [],
			borders = [
				element.css( "borderTopWidth" ),
				element.css( "borderRightWidth" ),
				element.css( "borderBottomWidth" ),
				element.css( "borderLeftWidth" )
			],
			paddings = [
				element.css( "paddingTop" ),
				element.css( "paddingRight" ),
				element.css( "paddingBottom" ),
				element.css( "paddingLeft" )
			];

		for ( ; i < 4; i++ ) {
			widths[ i ] = ( parseFloat( borders[ i ] ) || 0 );
			widths[ i ] += ( parseFloat( paddings[ i ] ) || 0 );
		}

		return {
			height: widths[ 0 ] + widths[ 2 ],
			width: widths[ 1 ] + widths[ 3 ]
		};
	},

	_proportionallyResize: function() {

		if ( !this._proportionallyResizeElements.length ) {
			return;
		}

		var prel,
			i = 0,
			element = this.helper || this.element;

		for ( ; i < this._proportionallyResizeElements.length; i++ ) {

			prel = this._proportionallyResizeElements[ i ];

			// TODO: Seems like a bug to cache this.outerDimensions
			// considering that we are in a loop.
			if ( !this.outerDimensions ) {
				this.outerDimensions = this._getPaddingPlusBorderDimensions( prel );
			}

			prel.css( {
				height: ( element.height() - this.outerDimensions.height ) || 0,
				width: ( element.width() - this.outerDimensions.width ) || 0
			} );

		}

	},

	_renderProxy: function() {

		var el = this.element, o = this.options;
		this.elementOffset = el.offset();

		if ( this._helper ) {

			this.helper = this.helper || $( "<div></div>" ).css( { overflow: "hidden" } );

			this._addClass( this.helper, this._helper );
			this.helper.css( {
				width: this.element.outerWidth(),
				height: this.element.outerHeight(),
				position: "absolute",
				left: this.elementOffset.left + "px",
				top: this.elementOffset.top + "px",
				zIndex: ++o.zIndex //TODO: Don't modify option
			} );

			this.helper
				.appendTo( "body" )
				.disableSelection();

		} else {
			this.helper = this.element;
		}

	},

	_change: {
		e: function( event, dx ) {
			return { width: this.originalSize.width + dx };
		},
		w: function( event, dx ) {
			var cs = this.originalSize, sp = this.originalPosition;
			return { left: sp.left + dx, width: cs.width - dx };
		},
		n: function( event, dx, dy ) {
			var cs = this.originalSize, sp = this.originalPosition;
			return { top: sp.top + dy, height: cs.height - dy };
		},
		s: function( event, dx, dy ) {
			return { height: this.originalSize.height + dy };
		},
		se: function( event, dx, dy ) {
			return $.extend( this._change.s.apply( this, arguments ),
				this._change.e.apply( this, [ event, dx, dy ] ) );
		},
		sw: function( event, dx, dy ) {
			return $.extend( this._change.s.apply( this, arguments ),
				this._change.w.apply( this, [ event, dx, dy ] ) );
		},
		ne: function( event, dx, dy ) {
			return $.extend( this._change.n.apply( this, arguments ),
				this._change.e.apply( this, [ event, dx, dy ] ) );
		},
		nw: function( event, dx, dy ) {
			return $.extend( this._change.n.apply( this, arguments ),
				this._change.w.apply( this, [ event, dx, dy ] ) );
		}
	},

	_propagate: function( n, event ) {
		$.ui.plugin.call( this, n, [ event, this.ui() ] );
		if ( n !== "resize" ) {
			this._trigger( n, event, this.ui() );
		}
	},

	plugins: {},

	ui: function() {
		return {
			originalElement: this.originalElement,
			element: this.element,
			helper: this.helper,
			position: this.position,
			size: this.size,
			originalSize: this.originalSize,
			originalPosition: this.originalPosition
		};
	}

} );

/*
 * Resizable Extensions
 */

$.ui.plugin.add( "resizable", "animate", {

	stop: function( event ) {
		var that = $( this ).resizable( "instance" ),
			o = that.options,
			pr = that._proportionallyResizeElements,
			ista = pr.length && ( /textarea/i ).test( pr[ 0 ].nodeName ),
			soffseth = ista && that._hasScroll( pr[ 0 ], "left" ) ? 0 : that.sizeDiff.height,
			soffsetw = ista ? 0 : that.sizeDiff.width,
			style = {
				width: ( that.size.width - soffsetw ),
				height: ( that.size.height - soffseth )
			},
			left = ( parseFloat( that.element.css( "left" ) ) +
				( that.position.left - that.originalPosition.left ) ) || null,
			top = ( parseFloat( that.element.css( "top" ) ) +
				( that.position.top - that.originalPosition.top ) ) || null;

		that.element.animate(
			$.extend( style, top && left ? { top: top, left: left } : {} ), {
				duration: o.animateDuration,
				easing: o.animateEasing,
				step: function() {

					var data = {
						width: parseFloat( that.element.css( "width" ) ),
						height: parseFloat( that.element.css( "height" ) ),
						top: parseFloat( that.element.css( "top" ) ),
						left: parseFloat( that.element.css( "left" ) )
					};

					if ( pr && pr.length ) {
						$( pr[ 0 ] ).css( { width: data.width, height: data.height } );
					}

					// Propagating resize, and updating values for each animation step
					that._updateCache( data );
					that._propagate( "resize", event );

				}
			}
		);
	}

} );

$.ui.plugin.add( "resizable", "containment", {

	start: function() {
		var element, p, co, ch, cw, width, height,
			that = $( this ).resizable( "instance" ),
			o = that.options,
			el = that.element,
			oc = o.containment,
			ce = ( oc instanceof $ ) ?
				oc.get( 0 ) :
				( /parent/.test( oc ) ) ? el.parent().get( 0 ) : oc;

		if ( !ce ) {
			return;
		}

		that.containerElement = $( ce );

		if ( /document/.test( oc ) || oc === document ) {
			that.containerOffset = {
				left: 0,
				top: 0
			};
			that.containerPosition = {
				left: 0,
				top: 0
			};

			that.parentData = {
				element: $( document ),
				left: 0,
				top: 0,
				width: $( document ).width(),
				height: $( document ).height() || document.body.parentNode.scrollHeight
			};
		} else {
			element = $( ce );
			p = [];
			$( [ "Top", "Right", "Left", "Bottom" ] ).each( function( i, name ) {
				p[ i ] = that._num( element.css( "padding" + name ) );
			} );

			that.containerOffset = element.offset();
			that.containerPosition = element.position();
			that.containerSize = {
				height: ( element.innerHeight() - p[ 3 ] ),
				width: ( element.innerWidth() - p[ 1 ] )
			};

			co = that.containerOffset;
			ch = that.containerSize.height;
			cw = that.containerSize.width;
			width = ( that._hasScroll( ce, "left" ) ? ce.scrollWidth : cw );
			height = ( that._hasScroll( ce ) ? ce.scrollHeight : ch );

			that.parentData = {
				element: ce,
				left: co.left,
				top: co.top,
				width: width,
				height: height
			};
		}
	},

	resize: function( event ) {
		var woset, hoset, isParent, isOffsetRelative,
			that = $( this ).resizable( "instance" ),
			o = that.options,
			co = that.containerOffset,
			cp = that.position,
			pRatio = that._aspectRatio || event.shiftKey,
			cop = {
				top: 0,
				left: 0
			},
			ce = that.containerElement,
			continueResize = true;

		if ( ce[ 0 ] !== document && ( /static/ ).test( ce.css( "position" ) ) ) {
			cop = co;
		}

		if ( cp.left < ( that._helper ? co.left : 0 ) ) {
			that.size.width = that.size.width +
				( that._helper ?
					( that.position.left - co.left ) :
					( that.position.left - cop.left ) );

			if ( pRatio ) {
				that.size.height = that.size.width / that.aspectRatio;
				continueResize = false;
			}
			that.position.left = o.helper ? co.left : 0;
		}

		if ( cp.top < ( that._helper ? co.top : 0 ) ) {
			that.size.height = that.size.height +
				( that._helper ?
					( that.position.top - co.top ) :
					that.position.top );

			if ( pRatio ) {
				that.size.width = that.size.height * that.aspectRatio;
				continueResize = false;
			}
			that.position.top = that._helper ? co.top : 0;
		}

		isParent = that.containerElement.get( 0 ) === that.element.parent().get( 0 );
		isOffsetRelative = /relative|absolute/.test( that.containerElement.css( "position" ) );

		if ( isParent && isOffsetRelative ) {
			that.offset.left = that.parentData.left + that.position.left;
			that.offset.top = that.parentData.top + that.position.top;
		} else {
			that.offset.left = that.element.offset().left;
			that.offset.top = that.element.offset().top;
		}

		woset = Math.abs( that.sizeDiff.width +
			( that._helper ?
				that.offset.left - cop.left :
				( that.offset.left - co.left ) ) );

		hoset = Math.abs( that.sizeDiff.height +
			( that._helper ?
				that.offset.top - cop.top :
				( that.offset.top - co.top ) ) );

		if ( woset + that.size.width >= that.parentData.width ) {
			that.size.width = that.parentData.width - woset;
			if ( pRatio ) {
				that.size.height = that.size.width / that.aspectRatio;
				continueResize = false;
			}
		}

		if ( hoset + that.size.height >= that.parentData.height ) {
			that.size.height = that.parentData.height - hoset;
			if ( pRatio ) {
				that.size.width = that.size.height * that.aspectRatio;
				continueResize = false;
			}
		}

		if ( !continueResize ) {
			that.position.left = that.prevPosition.left;
			that.position.top = that.prevPosition.top;
			that.size.width = that.prevSize.width;
			that.size.height = that.prevSize.height;
		}
	},

	stop: function() {
		var that = $( this ).resizable( "instance" ),
			o = that.options,
			co = that.containerOffset,
			cop = that.containerPosition,
			ce = that.containerElement,
			helper = $( that.helper ),
			ho = helper.offset(),
			w = helper.outerWidth() - that.sizeDiff.width,
			h = helper.outerHeight() - that.sizeDiff.height;

		if ( that._helper && !o.animate && ( /relative/ ).test( ce.css( "position" ) ) ) {
			$( this ).css( {
				left: ho.left - cop.left - co.left,
				width: w,
				height: h
			} );
		}

		if ( that._helper && !o.animate && ( /static/ ).test( ce.css( "position" ) ) ) {
			$( this ).css( {
				left: ho.left - cop.left - co.left,
				width: w,
				height: h
			} );
		}
	}
} );

$.ui.plugin.add( "resizable", "alsoResize", {

	start: function() {
		var that = $( this ).resizable( "instance" ),
			o = that.options;

		$( o.alsoResize ).each( function() {
			var el = $( this );
			el.data( "ui-resizable-alsoresize", {
				width: parseFloat( el.width() ), height: parseFloat( el.height() ),
				left: parseFloat( el.css( "left" ) ), top: parseFloat( el.css( "top" ) )
			} );
		} );
	},

	resize: function( event, ui ) {
		var that = $( this ).resizable( "instance" ),
			o = that.options,
			os = that.originalSize,
			op = that.originalPosition,
			delta = {
				height: ( that.size.height - os.height ) || 0,
				width: ( that.size.width - os.width ) || 0,
				top: ( that.position.top - op.top ) || 0,
				left: ( that.position.left - op.left ) || 0
			};

			$( o.alsoResize ).each( function() {
				var el = $( this ), start = $( this ).data( "ui-resizable-alsoresize" ), style = {},
					css = el.parents( ui.originalElement[ 0 ] ).length ?
							[ "width", "height" ] :
							[ "width", "height", "top", "left" ];

				$.each( css, function( i, prop ) {
					var sum = ( start[ prop ] || 0 ) + ( delta[ prop ] || 0 );
					if ( sum && sum >= 0 ) {
						style[ prop ] = sum || null;
					}
				} );

				el.css( style );
			} );
	},

	stop: function() {
		$( this ).removeData( "ui-resizable-alsoresize" );
	}
} );

$.ui.plugin.add( "resizable", "ghost", {

	start: function() {

		var that = $( this ).resizable( "instance" ), cs = that.size;

		that.ghost = that.originalElement.clone();
		that.ghost.css( {
			opacity: 0.25,
			display: "block",
			position: "relative",
			height: cs.height,
			width: cs.width,
			margin: 0,
			left: 0,
			top: 0
		} );

		that._addClass( that.ghost, "ui-resizable-ghost" );

		// DEPRECATED
		// TODO: remove after 1.12
		if ( $.uiBackCompat !== false && typeof that.options.ghost === "string" ) {

			// Ghost option
			that.ghost.addClass( this.options.ghost );
		}

		that.ghost.appendTo( that.helper );

	},

	resize: function() {
		var that = $( this ).resizable( "instance" );
		if ( that.ghost ) {
			that.ghost.css( {
				position: "relative",
				height: that.size.height,
				width: that.size.width
			} );
		}
	},

	stop: function() {
		var that = $( this ).resizable( "instance" );
		if ( that.ghost && that.helper ) {
			that.helper.get( 0 ).removeChild( that.ghost.get( 0 ) );
		}
	}

} );

$.ui.plugin.add( "resizable", "grid", {

	resize: function() {
		var outerDimensions,
			that = $( this ).resizable( "instance" ),
			o = that.options,
			cs = that.size,
			os = that.originalSize,
			op = that.originalPosition,
			a = that.axis,
			grid = typeof o.grid === "number" ? [ o.grid, o.grid ] : o.grid,
			gridX = ( grid[ 0 ] || 1 ),
			gridY = ( grid[ 1 ] || 1 ),
			ox = Math.round( ( cs.width - os.width ) / gridX ) * gridX,
			oy = Math.round( ( cs.height - os.height ) / gridY ) * gridY,
			newWidth = os.width + ox,
			newHeight = os.height + oy,
			isMaxWidth = o.maxWidth && ( o.maxWidth < newWidth ),
			isMaxHeight = o.maxHeight && ( o.maxHeight < newHeight ),
			isMinWidth = o.minWidth && ( o.minWidth > newWidth ),
			isMinHeight = o.minHeight && ( o.minHeight > newHeight );

		o.grid = grid;

		if ( isMinWidth ) {
			newWidth += gridX;
		}
		if ( isMinHeight ) {
			newHeight += gridY;
		}
		if ( isMaxWidth ) {
			newWidth -= gridX;
		}
		if ( isMaxHeight ) {
			newHeight -= gridY;
		}

		if ( /^(se|s|e)$/.test( a ) ) {
			that.size.width = newWidth;
			that.size.height = newHeight;
		} else if ( /^(ne)$/.test( a ) ) {
			that.size.width = newWidth;
			that.size.height = newHeight;
			that.position.top = op.top - oy;
		} else if ( /^(sw)$/.test( a ) ) {
			that.size.width = newWidth;
			that.size.height = newHeight;
			that.position.left = op.left - ox;
		} else {
			if ( newHeight - gridY <= 0 || newWidth - gridX <= 0 ) {
				outerDimensions = that._getPaddingPlusBorderDimensions( this );
			}

			if ( newHeight - gridY > 0 ) {
				that.size.height = newHeight;
				that.position.top = op.top - oy;
			} else {
				newHeight = gridY - outerDimensions.height;
				that.size.height = newHeight;
				that.position.top = op.top + os.height - newHeight;
			}
			if ( newWidth - gridX > 0 ) {
				that.size.width = newWidth;
				that.position.left = op.left - ox;
			} else {
				newWidth = gridX - outerDimensions.width;
				that.size.width = newWidth;
				that.position.left = op.left + os.width - newWidth;
			}
		}
	}

} );

var widgetsResizable = $.ui.resizable;


/*!
 * jQuery UI Dialog 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Dialog
//>>group: Widgets
//>>description: Displays customizable dialog windows.
//>>docs: http://api.jqueryui.com/dialog/
//>>demos: http://jqueryui.com/dialog/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/dialog.css
//>>css.theme: ../../themes/base/theme.css


$.widget( "ui.dialog", {
	version: "1.13.2",
	options: {
		appendTo: "body",
		autoOpen: true,
		buttons: [],
		classes: {
			"ui-dialog": "ui-corner-all",
			"ui-dialog-titlebar": "ui-corner-all"
		},
		closeOnEscape: true,
		closeText: "Close",
		draggable: true,
		hide: null,
		height: "auto",
		maxHeight: null,
		maxWidth: null,
		minHeight: 150,
		minWidth: 150,
		modal: false,
		position: {
			my: "center",
			at: "center",
			of: window,
			collision: "fit",

			// Ensure the titlebar is always visible
			using: function( pos ) {
				var topOffset = $( this ).css( pos ).offset().top;
				if ( topOffset < 0 ) {
					$( this ).css( "top", pos.top - topOffset );
				}
			}
		},
		resizable: true,
		show: null,
		title: null,
		width: 300,

		// Callbacks
		beforeClose: null,
		close: null,
		drag: null,
		dragStart: null,
		dragStop: null,
		focus: null,
		open: null,
		resize: null,
		resizeStart: null,
		resizeStop: null
	},

	sizeRelatedOptions: {
		buttons: true,
		height: true,
		maxHeight: true,
		maxWidth: true,
		minHeight: true,
		minWidth: true,
		width: true
	},

	resizableRelatedOptions: {
		maxHeight: true,
		maxWidth: true,
		minHeight: true,
		minWidth: true
	},

	_create: function() {
		this.originalCss = {
			display: this.element[ 0 ].style.display,
			width: this.element[ 0 ].style.width,
			minHeight: this.element[ 0 ].style.minHeight,
			maxHeight: this.element[ 0 ].style.maxHeight,
			height: this.element[ 0 ].style.height
		};
		this.originalPosition = {
			parent: this.element.parent(),
			index: this.element.parent().children().index( this.element )
		};
		this.originalTitle = this.element.attr( "title" );
		if ( this.options.title == null && this.originalTitle != null ) {
			this.options.title = this.originalTitle;
		}

		// Dialogs can't be disabled
		if ( this.options.disabled ) {
			this.options.disabled = false;
		}

		this._createWrapper();

		this.element
			.show()
			.removeAttr( "title" )
			.appendTo( this.uiDialog );

		this._addClass( "ui-dialog-content", "ui-widget-content" );

		this._createTitlebar();
		this._createButtonPane();

		if ( this.options.draggable && $.fn.draggable ) {
			this._makeDraggable();
		}
		if ( this.options.resizable && $.fn.resizable ) {
			this._makeResizable();
		}

		this._isOpen = false;

		this._trackFocus();
	},

	_init: function() {
		if ( this.options.autoOpen ) {
			this.open();
		}
	},

	_appendTo: function() {
		var element = this.options.appendTo;
		if ( element && ( element.jquery || element.nodeType ) ) {
			return $( element );
		}
		return this.document.find( element || "body" ).eq( 0 );
	},

	_destroy: function() {
		var next,
			originalPosition = this.originalPosition;

		this._untrackInstance();
		this._destroyOverlay();

		this.element
			.removeUniqueId()
			.css( this.originalCss )

			// Without detaching first, the following becomes really slow
			.detach();

		this.uiDialog.remove();

		if ( this.originalTitle ) {
			this.element.attr( "title", this.originalTitle );
		}

		next = originalPosition.parent.children().eq( originalPosition.index );

		// Don't try to place the dialog next to itself (#8613)
		if ( next.length && next[ 0 ] !== this.element[ 0 ] ) {
			next.before( this.element );
		} else {
			originalPosition.parent.append( this.element );
		}
	},

	widget: function() {
		return this.uiDialog;
	},

	disable: $.noop,
	enable: $.noop,

	close: function( event ) {
		var that = this;

		if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) {
			return;
		}

		this._isOpen = false;
		this._focusedElement = null;
		this._destroyOverlay();
		this._untrackInstance();

		if ( !this.opener.filter( ":focusable" ).trigger( "focus" ).length ) {

			// Hiding a focused element doesn't trigger blur in WebKit
			// so in case we have nothing to focus on, explicitly blur the active element
			// https://bugs.webkit.org/show_bug.cgi?id=47182
			$.ui.safeBlur( $.ui.safeActiveElement( this.document[ 0 ] ) );
		}

		this._hide( this.uiDialog, this.options.hide, function() {
			that._trigger( "close", event );
		} );
	},

	isOpen: function() {
		return this._isOpen;
	},

	moveToTop: function() {
		this._moveToTop();
	},

	_moveToTop: function( event, silent ) {
		var moved = false,
			zIndices = this.uiDialog.siblings( ".ui-front:visible" ).map( function() {
				return +$( this ).css( "z-index" );
			} ).get(),
			zIndexMax = Math.max.apply( null, zIndices );

		if ( zIndexMax >= +this.uiDialog.css( "z-index" ) ) {
			this.uiDialog.css( "z-index", zIndexMax + 1 );
			moved = true;
		}

		if ( moved && !silent ) {
			this._trigger( "focus", event );
		}
		return moved;
	},

	open: function() {
		var that = this;
		if ( this._isOpen ) {
			if ( this._moveToTop() ) {
				this._focusTabbable();
			}
			return;
		}

		this._isOpen = true;
		this.opener = $( $.ui.safeActiveElement( this.document[ 0 ] ) );

		this._size();
		this._position();
		this._createOverlay();
		this._moveToTop( null, true );

		// Ensure the overlay is moved to the top with the dialog, but only when
		// opening. The overlay shouldn't move after the dialog is open so that
		// modeless dialogs opened after the modal dialog stack properly.
		if ( this.overlay ) {
			this.overlay.css( "z-index", this.uiDialog.css( "z-index" ) - 1 );
		}

		this._show( this.uiDialog, this.options.show, function() {
			that._focusTabbable();
			that._trigger( "focus" );
		} );

		// Track the dialog immediately upon opening in case a focus event
		// somehow occurs outside of the dialog before an element inside the
		// dialog is focused (#10152)
		this._makeFocusTarget();

		this._trigger( "open" );
	},

	_focusTabbable: function() {

		// Set focus to the first match:
		// 1. An element that was focused previously
		// 2. First element inside the dialog matching [autofocus]
		// 3. Tabbable element inside the content element
		// 4. Tabbable element inside the buttonpane
		// 5. The close button
		// 6. The dialog itself
		var hasFocus = this._focusedElement;
		if ( !hasFocus ) {
			hasFocus = this.element.find( "[autofocus]" );
		}
		if ( !hasFocus.length ) {
			hasFocus = this.element.find( ":tabbable" );
		}
		if ( !hasFocus.length ) {
			hasFocus = this.uiDialogButtonPane.find( ":tabbable" );
		}
		if ( !hasFocus.length ) {
			hasFocus = this.uiDialogTitlebarClose.filter( ":tabbable" );
		}
		if ( !hasFocus.length ) {
			hasFocus = this.uiDialog;
		}
		hasFocus.eq( 0 ).trigger( "focus" );
	},

	_restoreTabbableFocus: function() {
		var activeElement = $.ui.safeActiveElement( this.document[ 0 ] ),
			isActive = this.uiDialog[ 0 ] === activeElement ||
				$.contains( this.uiDialog[ 0 ], activeElement );
		if ( !isActive ) {
			this._focusTabbable();
		}
	},

	_keepFocus: function( event ) {
		event.preventDefault();
		this._restoreTabbableFocus();

		// support: IE
		// IE <= 8 doesn't prevent moving focus even with event.preventDefault()
		// so we check again later
		this._delay( this._restoreTabbableFocus );
	},

	_createWrapper: function() {
		this.uiDialog = $( "<div>" )
			.hide()
			.attr( {

				// Setting tabIndex makes the div focusable
				tabIndex: -1,
				role: "dialog"
			} )
			.appendTo( this._appendTo() );

		this._addClass( this.uiDialog, "ui-dialog", "ui-widget ui-widget-content ui-front" );
		this._on( this.uiDialog, {
			keydown: function( event ) {
				if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
						event.keyCode === $.ui.keyCode.ESCAPE ) {
					event.preventDefault();
					this.close( event );
					return;
				}

				// Prevent tabbing out of dialogs
				if ( event.keyCode !== $.ui.keyCode.TAB || event.isDefaultPrevented() ) {
					return;
				}
				var tabbables = this.uiDialog.find( ":tabbable" ),
					first = tabbables.first(),
					last = tabbables.last();

				if ( ( event.target === last[ 0 ] || event.target === this.uiDialog[ 0 ] ) &&
						!event.shiftKey ) {
					this._delay( function() {
						first.trigger( "focus" );
					} );
					event.preventDefault();
				} else if ( ( event.target === first[ 0 ] ||
						event.target === this.uiDialog[ 0 ] ) && event.shiftKey ) {
					this._delay( function() {
						last.trigger( "focus" );
					} );
					event.preventDefault();
				}
			},
			mousedown: function( event ) {
				if ( this._moveToTop( event ) ) {
					this._focusTabbable();
				}
			}
		} );

		// We assume that any existing aria-describedby attribute means
		// that the dialog content is marked up properly
		// otherwise we brute force the content as the description
		if ( !this.element.find( "[aria-describedby]" ).length ) {
			this.uiDialog.attr( {
				"aria-describedby": this.element.uniqueId().attr( "id" )
			} );
		}
	},

	_createTitlebar: function() {
		var uiDialogTitle;

		this.uiDialogTitlebar = $( "<div>" );
		this._addClass( this.uiDialogTitlebar,
			"ui-dialog-titlebar", "ui-widget-header ui-helper-clearfix" );
		this._on( this.uiDialogTitlebar, {
			mousedown: function( event ) {

				// Don't prevent click on close button (#8838)
				// Focusing a dialog that is partially scrolled out of view
				// causes the browser to scroll it into view, preventing the click event
				if ( !$( event.target ).closest( ".ui-dialog-titlebar-close" ) ) {

					// Dialog isn't getting focus when dragging (#8063)
					this.uiDialog.trigger( "focus" );
				}
			}
		} );

		// Support: IE
		// Use type="button" to prevent enter keypresses in textboxes from closing the
		// dialog in IE (#9312)
		this.uiDialogTitlebarClose = $( "<button type='button'></button>" )
			.button( {
				label: $( "<a>" ).text( this.options.closeText ).html(),
				icon: "ui-icon-closethick",
				showLabel: false
			} )
			.appendTo( this.uiDialogTitlebar );

		this._addClass( this.uiDialogTitlebarClose, "ui-dialog-titlebar-close" );
		this._on( this.uiDialogTitlebarClose, {
			click: function( event ) {
				event.preventDefault();
				this.close( event );
			}
		} );

		uiDialogTitle = $( "<span>" ).uniqueId().prependTo( this.uiDialogTitlebar );
		this._addClass( uiDialogTitle, "ui-dialog-title" );
		this._title( uiDialogTitle );

		this.uiDialogTitlebar.prependTo( this.uiDialog );

		this.uiDialog.attr( {
			"aria-labelledby": uiDialogTitle.attr( "id" )
		} );
	},

	_title: function( title ) {
		if ( this.options.title ) {
			title.text( this.options.title );
		} else {
			title.html( "&#160;" );
		}
	},

	_createButtonPane: function() {
		this.uiDialogButtonPane = $( "<div>" );
		this._addClass( this.uiDialogButtonPane, "ui-dialog-buttonpane",
			"ui-widget-content ui-helper-clearfix" );

		this.uiButtonSet = $( "<div>" )
			.appendTo( this.uiDialogButtonPane );
		this._addClass( this.uiButtonSet, "ui-dialog-buttonset" );

		this._createButtons();
	},

	_createButtons: function() {
		var that = this,
			buttons = this.options.buttons;

		// If we already have a button pane, remove it
		this.uiDialogButtonPane.remove();
		this.uiButtonSet.empty();

		if ( $.isEmptyObject( buttons ) || ( Array.isArray( buttons ) && !buttons.length ) ) {
			this._removeClass( this.uiDialog, "ui-dialog-buttons" );
			return;
		}

		$.each( buttons, function( name, props ) {
			var click, buttonOptions;
			props = typeof props === "function" ?
				{ click: props, text: name } :
				props;

			// Default to a non-submitting button
			props = $.extend( { type: "button" }, props );

			// Change the context for the click callback to be the main element
			click = props.click;
			buttonOptions = {
				icon: props.icon,
				iconPosition: props.iconPosition,
				showLabel: props.showLabel,

				// Deprecated options
				icons: props.icons,
				text: props.text
			};

			delete props.click;
			delete props.icon;
			delete props.iconPosition;
			delete props.showLabel;

			// Deprecated options
			delete props.icons;
			if ( typeof props.text === "boolean" ) {
				delete props.text;
			}

			$( "<button></button>", props )
				.button( buttonOptions )
				.appendTo( that.uiButtonSet )
				.on( "click", function() {
					click.apply( that.element[ 0 ], arguments );
				} );
		} );
		this._addClass( this.uiDialog, "ui-dialog-buttons" );
		this.uiDialogButtonPane.appendTo( this.uiDialog );
	},

	_makeDraggable: function() {
		var that = this,
			options = this.options;

		function filteredUi( ui ) {
			return {
				position: ui.position,
				offset: ui.offset
			};
		}

		this.uiDialog.draggable( {
			cancel: ".ui-dialog-content, .ui-dialog-titlebar-close",
			handle: ".ui-dialog-titlebar",
			containment: "document",
			start: function( event, ui ) {
				that._addClass( $( this ), "ui-dialog-dragging" );
				that._blockFrames();
				that._trigger( "dragStart", event, filteredUi( ui ) );
			},
			drag: function( event, ui ) {
				that._trigger( "drag", event, filteredUi( ui ) );
			},
			stop: function( event, ui ) {
				var left = ui.offset.left - that.document.scrollLeft(),
					top = ui.offset.top - that.document.scrollTop();

				options.position = {
					my: "left top",
					at: "left" + ( left >= 0 ? "+" : "" ) + left + " " +
						"top" + ( top >= 0 ? "+" : "" ) + top,
					of: that.window
				};
				that._removeClass( $( this ), "ui-dialog-dragging" );
				that._unblockFrames();
				that._trigger( "dragStop", event, filteredUi( ui ) );
			}
		} );
	},

	_makeResizable: function() {
		var that = this,
			options = this.options,
			handles = options.resizable,

			// .ui-resizable has position: relative defined in the stylesheet
			// but dialogs have to use absolute or fixed positioning
			position = this.uiDialog.css( "position" ),
			resizeHandles = typeof handles === "string" ?
				handles :
				"n,e,s,w,se,sw,ne,nw";

		function filteredUi( ui ) {
			return {
				originalPosition: ui.originalPosition,
				originalSize: ui.originalSize,
				position: ui.position,
				size: ui.size
			};
		}

		this.uiDialog.resizable( {
			cancel: ".ui-dialog-content",
			containment: "document",
			alsoResize: this.element,
			maxWidth: options.maxWidth,
			maxHeight: options.maxHeight,
			minWidth: options.minWidth,
			minHeight: this._minHeight(),
			handles: resizeHandles,
			start: function( event, ui ) {
				that._addClass( $( this ), "ui-dialog-resizing" );
				that._blockFrames();
				that._trigger( "resizeStart", event, filteredUi( ui ) );
			},
			resize: function( event, ui ) {
				that._trigger( "resize", event, filteredUi( ui ) );
			},
			stop: function( event, ui ) {
				var offset = that.uiDialog.offset(),
					left = offset.left - that.document.scrollLeft(),
					top = offset.top - that.document.scrollTop();

				options.height = that.uiDialog.height();
				options.width = that.uiDialog.width();
				options.position = {
					my: "left top",
					at: "left" + ( left >= 0 ? "+" : "" ) + left + " " +
						"top" + ( top >= 0 ? "+" : "" ) + top,
					of: that.window
				};
				that._removeClass( $( this ), "ui-dialog-resizing" );
				that._unblockFrames();
				that._trigger( "resizeStop", event, filteredUi( ui ) );
			}
		} )
			.css( "position", position );
	},

	_trackFocus: function() {
		this._on( this.widget(), {
			focusin: function( event ) {
				this._makeFocusTarget();
				this._focusedElement = $( event.target );
			}
		} );
	},

	_makeFocusTarget: function() {
		this._untrackInstance();
		this._trackingInstances().unshift( this );
	},

	_untrackInstance: function() {
		var instances = this._trackingInstances(),
			exists = $.inArray( this, instances );
		if ( exists !== -1 ) {
			instances.splice( exists, 1 );
		}
	},

	_trackingInstances: function() {
		var instances = this.document.data( "ui-dialog-instances" );
		if ( !instances ) {
			instances = [];
			this.document.data( "ui-dialog-instances", instances );
		}
		return instances;
	},

	_minHeight: function() {
		var options = this.options;

		return options.height === "auto" ?
			options.minHeight :
			Math.min( options.minHeight, options.height );
	},

	_position: function() {

		// Need to show the dialog to get the actual offset in the position plugin
		var isVisible = this.uiDialog.is( ":visible" );
		if ( !isVisible ) {
			this.uiDialog.show();
		}
		this.uiDialog.position( this.options.position );
		if ( !isVisible ) {
			this.uiDialog.hide();
		}
	},

	_setOptions: function( options ) {
		var that = this,
			resize = false,
			resizableOptions = {};

		$.each( options, function( key, value ) {
			that._setOption( key, value );

			if ( key in that.sizeRelatedOptions ) {
				resize = true;
			}
			if ( key in that.resizableRelatedOptions ) {
				resizableOptions[ key ] = value;
			}
		} );

		if ( resize ) {
			this._size();
			this._position();
		}
		if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
			this.uiDialog.resizable( "option", resizableOptions );
		}
	},

	_setOption: function( key, value ) {
		var isDraggable, isResizable,
			uiDialog = this.uiDialog;

		if ( key === "disabled" ) {
			return;
		}

		this._super( key, value );

		if ( key === "appendTo" ) {
			this.uiDialog.appendTo( this._appendTo() );
		}

		if ( key === "buttons" ) {
			this._createButtons();
		}

		if ( key === "closeText" ) {
			this.uiDialogTitlebarClose.button( {

				// Ensure that we always pass a string
				label: $( "<a>" ).text( "" + this.options.closeText ).html()
			} );
		}

		if ( key === "draggable" ) {
			isDraggable = uiDialog.is( ":data(ui-draggable)" );
			if ( isDraggable && !value ) {
				uiDialog.draggable( "destroy" );
			}

			if ( !isDraggable && value ) {
				this._makeDraggable();
			}
		}

		if ( key === "position" ) {
			this._position();
		}

		if ( key === "resizable" ) {

			// currently resizable, becoming non-resizable
			isResizable = uiDialog.is( ":data(ui-resizable)" );
			if ( isResizable && !value ) {
				uiDialog.resizable( "destroy" );
			}

			// Currently resizable, changing handles
			if ( isResizable && typeof value === "string" ) {
				uiDialog.resizable( "option", "handles", value );
			}

			// Currently non-resizable, becoming resizable
			if ( !isResizable && value !== false ) {
				this._makeResizable();
			}
		}

		if ( key === "title" ) {
			this._title( this.uiDialogTitlebar.find( ".ui-dialog-title" ) );
		}
	},

	_size: function() {

		// If the user has resized the dialog, the .ui-dialog and .ui-dialog-content
		// divs will both have width and height set, so we need to reset them
		var nonContentHeight, minContentHeight, maxContentHeight,
			options = this.options;

		// Reset content sizing
		this.element.show().css( {
			width: "auto",
			minHeight: 0,
			maxHeight: "none",
			height: 0
		} );

		if ( options.minWidth > options.width ) {
			options.width = options.minWidth;
		}

		// Reset wrapper sizing
		// determine the height of all the non-content elements
		nonContentHeight = this.uiDialog.css( {
			height: "auto",
			width: options.width
		} )
			.outerHeight();
		minContentHeight = Math.max( 0, options.minHeight - nonContentHeight );
		maxContentHeight = typeof options.maxHeight === "number" ?
			Math.max( 0, options.maxHeight - nonContentHeight ) :
			"none";

		if ( options.height === "auto" ) {
			this.element.css( {
				minHeight: minContentHeight,
				maxHeight: maxContentHeight,
				height: "auto"
			} );
		} else {
			this.element.height( Math.max( 0, options.height - nonContentHeight ) );
		}

		if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
			this.uiDialog.resizable( "option", "minHeight", this._minHeight() );
		}
	},

	_blockFrames: function() {
		this.iframeBlocks = this.document.find( "iframe" ).map( function() {
			var iframe = $( this );

			return $( "<div>" )
				.css( {
					position: "absolute",
					width: iframe.outerWidth(),
					height: iframe.outerHeight()
				} )
				.appendTo( iframe.parent() )
				.offset( iframe.offset() )[ 0 ];
		} );
	},

	_unblockFrames: function() {
		if ( this.iframeBlocks ) {
			this.iframeBlocks.remove();
			delete this.iframeBlocks;
		}
	},

	_allowInteraction: function( event ) {
		if ( $( event.target ).closest( ".ui-dialog" ).length ) {
			return true;
		}

		// TODO: Remove hack when datepicker implements
		// the .ui-front logic (#8989)
		return !!$( event.target ).closest( ".ui-datepicker" ).length;
	},

	_createOverlay: function() {
		if ( !this.options.modal ) {
			return;
		}

		var jqMinor = $.fn.jquery.substring( 0, 4 );

		// We use a delay in case the overlay is created from an
		// event that we're going to be cancelling (#2804)
		var isOpening = true;
		this._delay( function() {
			isOpening = false;
		} );

		if ( !this.document.data( "ui-dialog-overlays" ) ) {

			// Prevent use of anchors and inputs
			// This doesn't use `_on()` because it is a shared event handler
			// across all open modal dialogs.
			this.document.on( "focusin.ui-dialog", function( event ) {
				if ( isOpening ) {
					return;
				}

				var instance = this._trackingInstances()[ 0 ];
				if ( !instance._allowInteraction( event ) ) {
					event.preventDefault();
					instance._focusTabbable();

					// Support: jQuery >=3.4 <3.6 only
					// Focus re-triggering in jQuery 3.4/3.5 makes the original element
					// have its focus event propagated last, breaking the re-targeting.
					// Trigger focus in a delay in addition if needed to avoid the issue
					// See https://github.com/jquery/jquery/issues/4382
					if ( jqMinor === "3.4." || jqMinor === "3.5." ) {
						instance._delay( instance._restoreTabbableFocus );
					}
				}
			}.bind( this ) );
		}

		this.overlay = $( "<div>" )
			.appendTo( this._appendTo() );

		this._addClass( this.overlay, null, "ui-widget-overlay ui-front" );
		this._on( this.overlay, {
			mousedown: "_keepFocus"
		} );
		this.document.data( "ui-dialog-overlays",
			( this.document.data( "ui-dialog-overlays" ) || 0 ) + 1 );
	},

	_destroyOverlay: function() {
		if ( !this.options.modal ) {
			return;
		}

		if ( this.overlay ) {
			var overlays = this.document.data( "ui-dialog-overlays" ) - 1;

			if ( !overlays ) {
				this.document.off( "focusin.ui-dialog" );
				this.document.removeData( "ui-dialog-overlays" );
			} else {
				this.document.data( "ui-dialog-overlays", overlays );
			}

			this.overlay.remove();
			this.overlay = null;
		}
	}
} );

// DEPRECATED
// TODO: switch return back to widget declaration at top of file when this is removed
if ( $.uiBackCompat !== false ) {

	// Backcompat for dialogClass option
	$.widget( "ui.dialog", $.ui.dialog, {
		options: {
			dialogClass: ""
		},
		_createWrapper: function() {
			this._super();
			this.uiDialog.addClass( this.options.dialogClass );
		},
		_setOption: function( key, value ) {
			if ( key === "dialogClass" ) {
				this.uiDialog
					.removeClass( this.options.dialogClass )
					.addClass( value );
			}
			this._superApply( arguments );
		}
	} );
}

var widgetsDialog = $.ui.dialog;


/*!
 * jQuery UI Droppable 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Droppable
//>>group: Interactions
//>>description: Enables drop targets for draggable elements.
//>>docs: http://api.jqueryui.com/droppable/
//>>demos: http://jqueryui.com/droppable/


$.widget( "ui.droppable", {
	version: "1.13.2",
	widgetEventPrefix: "drop",
	options: {
		accept: "*",
		addClasses: true,
		greedy: false,
		scope: "default",
		tolerance: "intersect",

		// Callbacks
		activate: null,
		deactivate: null,
		drop: null,
		out: null,
		over: null
	},
	_create: function() {

		var proportions,
			o = this.options,
			accept = o.accept;

		this.isover = false;
		this.isout = true;

		this.accept = typeof accept === "function" ? accept : function( d ) {
			return d.is( accept );
		};

		this.proportions = function( /* valueToWrite */ ) {
			if ( arguments.length ) {

				// Store the droppable's proportions
				proportions = arguments[ 0 ];
			} else {

				// Retrieve or derive the droppable's proportions
				return proportions ?
					proportions :
					proportions = {
						width: this.element[ 0 ].offsetWidth,
						height: this.element[ 0 ].offsetHeight
					};
			}
		};

		this._addToManager( o.scope );

		if ( o.addClasses ) {
			this._addClass( "ui-droppable" );
		}

	},

	_addToManager: function( scope ) {

		// Add the reference and positions to the manager
		$.ui.ddmanager.droppables[ scope ] = $.ui.ddmanager.droppables[ scope ] || [];
		$.ui.ddmanager.droppables[ scope ].push( this );
	},

	_splice: function( drop ) {
		var i = 0;
		for ( ; i < drop.length; i++ ) {
			if ( drop[ i ] === this ) {
				drop.splice( i, 1 );
			}
		}
	},

	_destroy: function() {
		var drop = $.ui.ddmanager.droppables[ this.options.scope ];

		this._splice( drop );
	},

	_setOption: function( key, value ) {

		if ( key === "accept" ) {
			this.accept = typeof value === "function" ? value : function( d ) {
				return d.is( value );
			};
		} else if ( key === "scope" ) {
			var drop = $.ui.ddmanager.droppables[ this.options.scope ];

			this._splice( drop );
			this._addToManager( value );
		}

		this._super( key, value );
	},

	_activate: function( event ) {
		var draggable = $.ui.ddmanager.current;

		this._addActiveClass();
		if ( draggable ) {
			this._trigger( "activate", event, this.ui( draggable ) );
		}
	},

	_deactivate: function( event ) {
		var draggable = $.ui.ddmanager.current;

		this._removeActiveClass();
		if ( draggable ) {
			this._trigger( "deactivate", event, this.ui( draggable ) );
		}
	},

	_over: function( event ) {

		var draggable = $.ui.ddmanager.current;

		// Bail if draggable and droppable are same element
		if ( !draggable || ( draggable.currentItem ||
				draggable.element )[ 0 ] === this.element[ 0 ] ) {
			return;
		}

		if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem ||
				draggable.element ) ) ) {
			this._addHoverClass();
			this._trigger( "over", event, this.ui( draggable ) );
		}

	},

	_out: function( event ) {

		var draggable = $.ui.ddmanager.current;

		// Bail if draggable and droppable are same element
		if ( !draggable || ( draggable.currentItem ||
				draggable.element )[ 0 ] === this.element[ 0 ] ) {
			return;
		}

		if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem ||
				draggable.element ) ) ) {
			this._removeHoverClass();
			this._trigger( "out", event, this.ui( draggable ) );
		}

	},

	_drop: function( event, custom ) {

		var draggable = custom || $.ui.ddmanager.current,
			childrenIntersection = false;

		// Bail if draggable and droppable are same element
		if ( !draggable || ( draggable.currentItem ||
				draggable.element )[ 0 ] === this.element[ 0 ] ) {
			return false;
		}

		this.element
			.find( ":data(ui-droppable)" )
			.not( ".ui-draggable-dragging" )
			.each( function() {
				var inst = $( this ).droppable( "instance" );
				if (
					inst.options.greedy &&
					!inst.options.disabled &&
					inst.options.scope === draggable.options.scope &&
					inst.accept.call(
						inst.element[ 0 ], ( draggable.currentItem || draggable.element )
					) &&
					$.ui.intersect(
						draggable,
						$.extend( inst, { offset: inst.element.offset() } ),
						inst.options.tolerance, event
					)
				) {
					childrenIntersection = true;
					return false;
				}
			} );
		if ( childrenIntersection ) {
			return false;
		}

		if ( this.accept.call( this.element[ 0 ],
				( draggable.currentItem || draggable.element ) ) ) {
			this._removeActiveClass();
			this._removeHoverClass();

			this._trigger( "drop", event, this.ui( draggable ) );
			return this.element;
		}

		return false;

	},

	ui: function( c ) {
		return {
			draggable: ( c.currentItem || c.element ),
			helper: c.helper,
			position: c.position,
			offset: c.positionAbs
		};
	},

	// Extension points just to make backcompat sane and avoid duplicating logic
	// TODO: Remove in 1.14 along with call to it below
	_addHoverClass: function() {
		this._addClass( "ui-droppable-hover" );
	},

	_removeHoverClass: function() {
		this._removeClass( "ui-droppable-hover" );
	},

	_addActiveClass: function() {
		this._addClass( "ui-droppable-active" );
	},

	_removeActiveClass: function() {
		this._removeClass( "ui-droppable-active" );
	}
} );

$.ui.intersect = ( function() {
	function isOverAxis( x, reference, size ) {
		return ( x >= reference ) && ( x < ( reference + size ) );
	}

	return function( draggable, droppable, toleranceMode, event ) {

		if ( !droppable.offset ) {
			return false;
		}

		var x1 = ( draggable.positionAbs ||
				draggable.position.absolute ).left + draggable.margins.left,
			y1 = ( draggable.positionAbs ||
				draggable.position.absolute ).top + draggable.margins.top,
			x2 = x1 + draggable.helperProportions.width,
			y2 = y1 + draggable.helperProportions.height,
			l = droppable.offset.left,
			t = droppable.offset.top,
			r = l + droppable.proportions().width,
			b = t + droppable.proportions().height;

		switch ( toleranceMode ) {
		case "fit":
			return ( l <= x1 && x2 <= r && t <= y1 && y2 <= b );
		case "intersect":
			return ( l < x1 + ( draggable.helperProportions.width / 2 ) && // Right Half
				x2 - ( draggable.helperProportions.width / 2 ) < r && // Left Half
				t < y1 + ( draggable.helperProportions.height / 2 ) && // Bottom Half
				y2 - ( draggable.helperProportions.height / 2 ) < b ); // Top Half
		case "pointer":
			return isOverAxis( event.pageY, t, droppable.proportions().height ) &&
				isOverAxis( event.pageX, l, droppable.proportions().width );
		case "touch":
			return (
				( y1 >= t && y1 <= b ) || // Top edge touching
				( y2 >= t && y2 <= b ) || // Bottom edge touching
				( y1 < t && y2 > b ) // Surrounded vertically
			) && (
				( x1 >= l && x1 <= r ) || // Left edge touching
				( x2 >= l && x2 <= r ) || // Right edge touching
				( x1 < l && x2 > r ) // Surrounded horizontally
			);
		default:
			return false;
		}
	};
} )();

/*
	This manager tracks offsets of draggables and droppables
*/
$.ui.ddmanager = {
	current: null,
	droppables: { "default": [] },
	prepareOffsets: function( t, event ) {

		var i, j,
			m = $.ui.ddmanager.droppables[ t.options.scope ] || [],
			type = event ? event.type : null, // workaround for #2317
			list = ( t.currentItem || t.element ).find( ":data(ui-droppable)" ).addBack();

		droppablesLoop: for ( i = 0; i < m.length; i++ ) {

			// No disabled and non-accepted
			if ( m[ i ].options.disabled || ( t && !m[ i ].accept.call( m[ i ].element[ 0 ],
					( t.currentItem || t.element ) ) ) ) {
				continue;
			}

			// Filter out elements in the current dragged item
			for ( j = 0; j < list.length; j++ ) {
				if ( list[ j ] === m[ i ].element[ 0 ] ) {
					m[ i ].proportions().height = 0;
					continue droppablesLoop;
				}
			}

			m[ i ].visible = m[ i ].element.css( "display" ) !== "none";
			if ( !m[ i ].visible ) {
				continue;
			}

			// Activate the droppable if used directly from draggables
			if ( type === "mousedown" ) {
				m[ i ]._activate.call( m[ i ], event );
			}

			m[ i ].offset = m[ i ].element.offset();
			m[ i ].proportions( {
				width: m[ i ].element[ 0 ].offsetWidth,
				height: m[ i ].element[ 0 ].offsetHeight
			} );

		}

	},
	drop: function( draggable, event ) {

		var dropped = false;

		// Create a copy of the droppables in case the list changes during the drop (#9116)
		$.each( ( $.ui.ddmanager.droppables[ draggable.options.scope ] || [] ).slice(), function() {

			if ( !this.options ) {
				return;
			}
			if ( !this.options.disabled && this.visible &&
					$.ui.intersect( draggable, this, this.options.tolerance, event ) ) {
				dropped = this._drop.call( this, event ) || dropped;
			}

			if ( !this.options.disabled && this.visible && this.accept.call( this.element[ 0 ],
					( draggable.currentItem || draggable.element ) ) ) {
				this.isout = true;
				this.isover = false;
				this._deactivate.call( this, event );
			}

		} );
		return dropped;

	},
	dragStart: function( draggable, event ) {

		// Listen for scrolling so that if the dragging causes scrolling the position of the
		// droppables can be recalculated (see #5003)
		draggable.element.parentsUntil( "body" ).on( "scroll.droppable", function() {
			if ( !draggable.options.refreshPositions ) {
				$.ui.ddmanager.prepareOffsets( draggable, event );
			}
		} );
	},
	drag: function( draggable, event ) {

		// If you have a highly dynamic page, you might try this option. It renders positions
		// every time you move the mouse.
		if ( draggable.options.refreshPositions ) {
			$.ui.ddmanager.prepareOffsets( draggable, event );
		}

		// Run through all droppables and check their positions based on specific tolerance options
		$.each( $.ui.ddmanager.droppables[ draggable.options.scope ] || [], function() {

			if ( this.options.disabled || this.greedyChild || !this.visible ) {
				return;
			}

			var parentInstance, scope, parent,
				intersects = $.ui.intersect( draggable, this, this.options.tolerance, event ),
				c = !intersects && this.isover ?
					"isout" :
					( intersects && !this.isover ? "isover" : null );
			if ( !c ) {
				return;
			}

			if ( this.options.greedy ) {

				// find droppable parents with same scope
				scope = this.options.scope;
				parent = this.element.parents( ":data(ui-droppable)" ).filter( function() {
					return $( this ).droppable( "instance" ).options.scope === scope;
				} );

				if ( parent.length ) {
					parentInstance = $( parent[ 0 ] ).droppable( "instance" );
					parentInstance.greedyChild = ( c === "isover" );
				}
			}

			// We just moved into a greedy child
			if ( parentInstance && c === "isover" ) {
				parentInstance.isover = false;
				parentInstance.isout = true;
				parentInstance._out.call( parentInstance, event );
			}

			this[ c ] = true;
			this[ c === "isout" ? "isover" : "isout" ] = false;
			this[ c === "isover" ? "_over" : "_out" ].call( this, event );

			// We just moved out of a greedy child
			if ( parentInstance && c === "isout" ) {
				parentInstance.isout = false;
				parentInstance.isover = true;
				parentInstance._over.call( parentInstance, event );
			}
		} );

	},
	dragStop: function( draggable, event ) {
		draggable.element.parentsUntil( "body" ).off( "scroll.droppable" );

		// Call prepareOffsets one final time since IE does not fire return scroll events when
		// overflow was caused by drag (see #5003)
		if ( !draggable.options.refreshPositions ) {
			$.ui.ddmanager.prepareOffsets( draggable, event );
		}
	}
};

// DEPRECATED
// TODO: switch return back to widget declaration at top of file when this is removed
if ( $.uiBackCompat !== false ) {

	// Backcompat for activeClass and hoverClass options
	$.widget( "ui.droppable", $.ui.droppable, {
		options: {
			hoverClass: false,
			activeClass: false
		},
		_addActiveClass: function() {
			this._super();
			if ( this.options.activeClass ) {
				this.element.addClass( this.options.activeClass );
			}
		},
		_removeActiveClass: function() {
			this._super();
			if ( this.options.activeClass ) {
				this.element.removeClass( this.options.activeClass );
			}
		},
		_addHoverClass: function() {
			this._super();
			if ( this.options.hoverClass ) {
				this.element.addClass( this.options.hoverClass );
			}
		},
		_removeHoverClass: function() {
			this._super();
			if ( this.options.hoverClass ) {
				this.element.removeClass( this.options.hoverClass );
			}
		}
	} );
}

var widgetsDroppable = $.ui.droppable;


/*!
 * jQuery UI Progressbar 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Progressbar
//>>group: Widgets
/* eslint-disable max-len */
//>>description: Displays a status indicator for loading state, standard percentage, and other progress indicators.
/* eslint-enable max-len */
//>>docs: http://api.jqueryui.com/progressbar/
//>>demos: http://jqueryui.com/progressbar/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/progressbar.css
//>>css.theme: ../../themes/base/theme.css


var widgetsProgressbar = $.widget( "ui.progressbar", {
	version: "1.13.2",
	options: {
		classes: {
			"ui-progressbar": "ui-corner-all",
			"ui-progressbar-value": "ui-corner-left",
			"ui-progressbar-complete": "ui-corner-right"
		},
		max: 100,
		value: 0,

		change: null,
		complete: null
	},

	min: 0,

	_create: function() {

		// Constrain initial value
		this.oldValue = this.options.value = this._constrainedValue();

		this.element.attr( {

			// Only set static values; aria-valuenow and aria-valuemax are
			// set inside _refreshValue()
			role: "progressbar",
			"aria-valuemin": this.min
		} );
		this._addClass( "ui-progressbar", "ui-widget ui-widget-content" );

		this.valueDiv = $( "<div>" ).appendTo( this.element );
		this._addClass( this.valueDiv, "ui-progressbar-value", "ui-widget-header" );
		this._refreshValue();
	},

	_destroy: function() {
		this.element.removeAttr( "role aria-valuemin aria-valuemax aria-valuenow" );

		this.valueDiv.remove();
	},

	value: function( newValue ) {
		if ( newValue === undefined ) {
			return this.options.value;
		}

		this.options.value = this._constrainedValue( newValue );
		this._refreshValue();
	},

	_constrainedValue: function( newValue ) {
		if ( newValue === undefined ) {
			newValue = this.options.value;
		}

		this.indeterminate = newValue === false;

		// Sanitize value
		if ( typeof newValue !== "number" ) {
			newValue = 0;
		}

		return this.indeterminate ? false :
			Math.min( this.options.max, Math.max( this.min, newValue ) );
	},

	_setOptions: function( options ) {

		// Ensure "value" option is set after other values (like max)
		var value = options.value;
		delete options.value;

		this._super( options );

		this.options.value = this._constrainedValue( value );
		this._refreshValue();
	},

	_setOption: function( key, value ) {
		if ( key === "max" ) {

			// Don't allow a max less than min
			value = Math.max( this.min, value );
		}
		this._super( key, value );
	},

	_setOptionDisabled: function( value ) {
		this._super( value );

		this.element.attr( "aria-disabled", value );
		this._toggleClass( null, "ui-state-disabled", !!value );
	},

	_percentage: function() {
		return this.indeterminate ?
			100 :
			100 * ( this.options.value - this.min ) / ( this.options.max - this.min );
	},

	_refreshValue: function() {
		var value = this.options.value,
			percentage = this._percentage();

		this.valueDiv
			.toggle( this.indeterminate || value > this.min )
			.width( percentage.toFixed( 0 ) + "%" );

		this
			._toggleClass( this.valueDiv, "ui-progressbar-complete", null,
				value === this.options.max )
			._toggleClass( "ui-progressbar-indeterminate", null, this.indeterminate );

		if ( this.indeterminate ) {
			this.element.removeAttr( "aria-valuenow" );
			if ( !this.overlayDiv ) {
				this.overlayDiv = $( "<div>" ).appendTo( this.valueDiv );
				this._addClass( this.overlayDiv, "ui-progressbar-overlay" );
			}
		} else {
			this.element.attr( {
				"aria-valuemax": this.options.max,
				"aria-valuenow": value
			} );
			if ( this.overlayDiv ) {
				this.overlayDiv.remove();
				this.overlayDiv = null;
			}
		}

		if ( this.oldValue !== value ) {
			this.oldValue = value;
			this._trigger( "change" );
		}
		if ( value === this.options.max ) {
			this._trigger( "complete" );
		}
	}
} );


/*!
 * jQuery UI Selectable 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Selectable
//>>group: Interactions
//>>description: Allows groups of elements to be selected with the mouse.
//>>docs: http://api.jqueryui.com/selectable/
//>>demos: http://jqueryui.com/selectable/
//>>css.structure: ../../themes/base/selectable.css


var widgetsSelectable = $.widget( "ui.selectable", $.ui.mouse, {
	version: "1.13.2",
	options: {
		appendTo: "body",
		autoRefresh: true,
		distance: 0,
		filter: "*",
		tolerance: "touch",

		// Callbacks
		selected: null,
		selecting: null,
		start: null,
		stop: null,
		unselected: null,
		unselecting: null
	},
	_create: function() {
		var that = this;

		this._addClass( "ui-selectable" );

		this.dragged = false;

		// Cache selectee children based on filter
		this.refresh = function() {
			that.elementPos = $( that.element[ 0 ] ).offset();
			that.selectees = $( that.options.filter, that.element[ 0 ] );
			that._addClass( that.selectees, "ui-selectee" );
			that.selectees.each( function() {
				var $this = $( this ),
					selecteeOffset = $this.offset(),
					pos = {
						left: selecteeOffset.left - that.elementPos.left,
						top: selecteeOffset.top - that.elementPos.top
					};
				$.data( this, "selectable-item", {
					element: this,
					$element: $this,
					left: pos.left,
					top: pos.top,
					right: pos.left + $this.outerWidth(),
					bottom: pos.top + $this.outerHeight(),
					startselected: false,
					selected: $this.hasClass( "ui-selected" ),
					selecting: $this.hasClass( "ui-selecting" ),
					unselecting: $this.hasClass( "ui-unselecting" )
				} );
			} );
		};
		this.refresh();

		this._mouseInit();

		this.helper = $( "<div>" );
		this._addClass( this.helper, "ui-selectable-helper" );
	},

	_destroy: function() {
		this.selectees.removeData( "selectable-item" );
		this._mouseDestroy();
	},

	_mouseStart: function( event ) {
		var that = this,
			options = this.options;

		this.opos = [ event.pageX, event.pageY ];
		this.elementPos = $( this.element[ 0 ] ).offset();

		if ( this.options.disabled ) {
			return;
		}

		this.selectees = $( options.filter, this.element[ 0 ] );

		this._trigger( "start", event );

		$( options.appendTo ).append( this.helper );

		// position helper (lasso)
		this.helper.css( {
			"left": event.pageX,
			"top": event.pageY,
			"width": 0,
			"height": 0
		} );

		if ( options.autoRefresh ) {
			this.refresh();
		}

		this.selectees.filter( ".ui-selected" ).each( function() {
			var selectee = $.data( this, "selectable-item" );
			selectee.startselected = true;
			if ( !event.metaKey && !event.ctrlKey ) {
				that._removeClass( selectee.$element, "ui-selected" );
				selectee.selected = false;
				that._addClass( selectee.$element, "ui-unselecting" );
				selectee.unselecting = true;

				// selectable UNSELECTING callback
				that._trigger( "unselecting", event, {
					unselecting: selectee.element
				} );
			}
		} );

		$( event.target ).parents().addBack().each( function() {
			var doSelect,
				selectee = $.data( this, "selectable-item" );
			if ( selectee ) {
				doSelect = ( !event.metaKey && !event.ctrlKey ) ||
					!selectee.$element.hasClass( "ui-selected" );
				that._removeClass( selectee.$element, doSelect ? "ui-unselecting" : "ui-selected" )
					._addClass( selectee.$element, doSelect ? "ui-selecting" : "ui-unselecting" );
				selectee.unselecting = !doSelect;
				selectee.selecting = doSelect;
				selectee.selected = doSelect;

				// selectable (UN)SELECTING callback
				if ( doSelect ) {
					that._trigger( "selecting", event, {
						selecting: selectee.element
					} );
				} else {
					that._trigger( "unselecting", event, {
						unselecting: selectee.element
					} );
				}
				return false;
			}
		} );

	},

	_mouseDrag: function( event ) {

		this.dragged = true;

		if ( this.options.disabled ) {
			return;
		}

		var tmp,
			that = this,
			options = this.options,
			x1 = this.opos[ 0 ],
			y1 = this.opos[ 1 ],
			x2 = event.pageX,
			y2 = event.pageY;

		if ( x1 > x2 ) {
			tmp = x2; x2 = x1; x1 = tmp;
		}
		if ( y1 > y2 ) {
			tmp = y2; y2 = y1; y1 = tmp;
		}
		this.helper.css( { left: x1, top: y1, width: x2 - x1, height: y2 - y1 } );

		this.selectees.each( function() {
			var selectee = $.data( this, "selectable-item" ),
				hit = false,
				offset = {};

			//prevent helper from being selected if appendTo: selectable
			if ( !selectee || selectee.element === that.element[ 0 ] ) {
				return;
			}

			offset.left   = selectee.left   + that.elementPos.left;
			offset.right  = selectee.right  + that.elementPos.left;
			offset.top    = selectee.top    + that.elementPos.top;
			offset.bottom = selectee.bottom + that.elementPos.top;

			if ( options.tolerance === "touch" ) {
				hit = ( !( offset.left > x2 || offset.right < x1 || offset.top > y2 ||
                    offset.bottom < y1 ) );
			} else if ( options.tolerance === "fit" ) {
				hit = ( offset.left > x1 && offset.right < x2 && offset.top > y1 &&
                    offset.bottom < y2 );
			}

			if ( hit ) {

				// SELECT
				if ( selectee.selected ) {
					that._removeClass( selectee.$element, "ui-selected" );
					selectee.selected = false;
				}
				if ( selectee.unselecting ) {
					that._removeClass( selectee.$element, "ui-unselecting" );
					selectee.unselecting = false;
				}
				if ( !selectee.selecting ) {
					that._addClass( selectee.$element, "ui-selecting" );
					selectee.selecting = true;

					// selectable SELECTING callback
					that._trigger( "selecting", event, {
						selecting: selectee.element
					} );
				}
			} else {

				// UNSELECT
				if ( selectee.selecting ) {
					if ( ( event.metaKey || event.ctrlKey ) && selectee.startselected ) {
						that._removeClass( selectee.$element, "ui-selecting" );
						selectee.selecting = false;
						that._addClass( selectee.$element, "ui-selected" );
						selectee.selected = true;
					} else {
						that._removeClass( selectee.$element, "ui-selecting" );
						selectee.selecting = false;
						if ( selectee.startselected ) {
							that._addClass( selectee.$element, "ui-unselecting" );
							selectee.unselecting = true;
						}

						// selectable UNSELECTING callback
						that._trigger( "unselecting", event, {
							unselecting: selectee.element
						} );
					}
				}
				if ( selectee.selected ) {
					if ( !event.metaKey && !event.ctrlKey && !selectee.startselected ) {
						that._removeClass( selectee.$element, "ui-selected" );
						selectee.selected = false;

						that._addClass( selectee.$element, "ui-unselecting" );
						selectee.unselecting = true;

						// selectable UNSELECTING callback
						that._trigger( "unselecting", event, {
							unselecting: selectee.element
						} );
					}
				}
			}
		} );

		return false;
	},

	_mouseStop: function( event ) {
		var that = this;

		this.dragged = false;

		$( ".ui-unselecting", this.element[ 0 ] ).each( function() {
			var selectee = $.data( this, "selectable-item" );
			that._removeClass( selectee.$element, "ui-unselecting" );
			selectee.unselecting = false;
			selectee.startselected = false;
			that._trigger( "unselected", event, {
				unselected: selectee.element
			} );
		} );
		$( ".ui-selecting", this.element[ 0 ] ).each( function() {
			var selectee = $.data( this, "selectable-item" );
			that._removeClass( selectee.$element, "ui-selecting" )
				._addClass( selectee.$element, "ui-selected" );
			selectee.selecting = false;
			selectee.selected = true;
			selectee.startselected = true;
			that._trigger( "selected", event, {
				selected: selectee.element
			} );
		} );
		this._trigger( "stop", event );

		this.helper.remove();

		return false;
	}

} );


/*!
 * jQuery UI Selectmenu 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Selectmenu
//>>group: Widgets
/* eslint-disable max-len */
//>>description: Duplicates and extends the functionality of a native HTML select element, allowing it to be customizable in behavior and appearance far beyond the limitations of a native select.
/* eslint-enable max-len */
//>>docs: http://api.jqueryui.com/selectmenu/
//>>demos: http://jqueryui.com/selectmenu/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/selectmenu.css, ../../themes/base/button.css
//>>css.theme: ../../themes/base/theme.css


var widgetsSelectmenu = $.widget( "ui.selectmenu", [ $.ui.formResetMixin, {
	version: "1.13.2",
	defaultElement: "<select>",
	options: {
		appendTo: null,
		classes: {
			"ui-selectmenu-button-open": "ui-corner-top",
			"ui-selectmenu-button-closed": "ui-corner-all"
		},
		disabled: null,
		icons: {
			button: "ui-icon-triangle-1-s"
		},
		position: {
			my: "left top",
			at: "left bottom",
			collision: "none"
		},
		width: false,

		// Callbacks
		change: null,
		close: null,
		focus: null,
		open: null,
		select: null
	},

	_create: function() {
		var selectmenuId = this.element.uniqueId().attr( "id" );
		this.ids = {
			element: selectmenuId,
			button: selectmenuId + "-button",
			menu: selectmenuId + "-menu"
		};

		this._drawButton();
		this._drawMenu();
		this._bindFormResetHandler();

		this._rendered = false;
		this.menuItems = $();
	},

	_drawButton: function() {
		var icon,
			that = this,
			item = this._parseOption(
				this.element.find( "option:selected" ),
				this.element[ 0 ].selectedIndex
			);

		// Associate existing label with the new button
		this.labels = this.element.labels().attr( "for", this.ids.button );
		this._on( this.labels, {
			click: function( event ) {
				this.button.trigger( "focus" );
				event.preventDefault();
			}
		} );

		// Hide original select element
		this.element.hide();

		// Create button
		this.button = $( "<span>", {
			tabindex: this.options.disabled ? -1 : 0,
			id: this.ids.button,
			role: "combobox",
			"aria-expanded": "false",
			"aria-autocomplete": "list",
			"aria-owns": this.ids.menu,
			"aria-haspopup": "true",
			title: this.element.attr( "title" )
		} )
			.insertAfter( this.element );

		this._addClass( this.button, "ui-selectmenu-button ui-selectmenu-button-closed",
			"ui-button ui-widget" );

		icon = $( "<span>" ).appendTo( this.button );
		this._addClass( icon, "ui-selectmenu-icon", "ui-icon " + this.options.icons.button );
		this.buttonItem = this._renderButtonItem( item )
			.appendTo( this.button );

		if ( this.options.width !== false ) {
			this._resizeButton();
		}

		this._on( this.button, this._buttonEvents );
		this.button.one( "focusin", function() {

			// Delay rendering the menu items until the button receives focus.
			// The menu may have already been rendered via a programmatic open.
			if ( !that._rendered ) {
				that._refreshMenu();
			}
		} );
	},

	_drawMenu: function() {
		var that = this;

		// Create menu
		this.menu = $( "<ul>", {
			"aria-hidden": "true",
			"aria-labelledby": this.ids.button,
			id: this.ids.menu
		} );

		// Wrap menu
		this.menuWrap = $( "<div>" ).append( this.menu );
		this._addClass( this.menuWrap, "ui-selectmenu-menu", "ui-front" );
		this.menuWrap.appendTo( this._appendTo() );

		// Initialize menu widget
		this.menuInstance = this.menu
			.menu( {
				classes: {
					"ui-menu": "ui-corner-bottom"
				},
				role: "listbox",
				select: function( event, ui ) {
					event.preventDefault();

					// Support: IE8
					// If the item was selected via a click, the text selection
					// will be destroyed in IE
					that._setSelection();

					that._select( ui.item.data( "ui-selectmenu-item" ), event );
				},
				focus: function( event, ui ) {
					var item = ui.item.data( "ui-selectmenu-item" );

					// Prevent inital focus from firing and check if its a newly focused item
					if ( that.focusIndex != null && item.index !== that.focusIndex ) {
						that._trigger( "focus", event, { item: item } );
						if ( !that.isOpen ) {
							that._select( item, event );
						}
					}
					that.focusIndex = item.index;

					that.button.attr( "aria-activedescendant",
						that.menuItems.eq( item.index ).attr( "id" ) );
				}
			} )
			.menu( "instance" );

		// Don't close the menu on mouseleave
		this.menuInstance._off( this.menu, "mouseleave" );

		// Cancel the menu's collapseAll on document click
		this.menuInstance._closeOnDocumentClick = function() {
			return false;
		};

		// Selects often contain empty items, but never contain dividers
		this.menuInstance._isDivider = function() {
			return false;
		};
	},

	refresh: function() {
		this._refreshMenu();
		this.buttonItem.replaceWith(
			this.buttonItem = this._renderButtonItem(

				// Fall back to an empty object in case there are no options
				this._getSelectedItem().data( "ui-selectmenu-item" ) || {}
			)
		);
		if ( this.options.width === null ) {
			this._resizeButton();
		}
	},

	_refreshMenu: function() {
		var item,
			options = this.element.find( "option" );

		this.menu.empty();

		this._parseOptions( options );
		this._renderMenu( this.menu, this.items );

		this.menuInstance.refresh();
		this.menuItems = this.menu.find( "li" )
			.not( ".ui-selectmenu-optgroup" )
				.find( ".ui-menu-item-wrapper" );

		this._rendered = true;

		if ( !options.length ) {
			return;
		}

		item = this._getSelectedItem();

		// Update the menu to have the correct item focused
		this.menuInstance.focus( null, item );
		this._setAria( item.data( "ui-selectmenu-item" ) );

		// Set disabled state
		this._setOption( "disabled", this.element.prop( "disabled" ) );
	},

	open: function( event ) {
		if ( this.options.disabled ) {
			return;
		}

		// If this is the first time the menu is being opened, render the items
		if ( !this._rendered ) {
			this._refreshMenu();
		} else {

			// Menu clears focus on close, reset focus to selected item
			this._removeClass( this.menu.find( ".ui-state-active" ), null, "ui-state-active" );
			this.menuInstance.focus( null, this._getSelectedItem() );
		}

		// If there are no options, don't open the menu
		if ( !this.menuItems.length ) {
			return;
		}

		this.isOpen = true;
		this._toggleAttr();
		this._resizeMenu();
		this._position();

		this._on( this.document, this._documentClick );

		this._trigger( "open", event );
	},

	_position: function() {
		this.menuWrap.position( $.extend( { of: this.button }, this.options.position ) );
	},

	close: function( event ) {
		if ( !this.isOpen ) {
			return;
		}

		this.isOpen = false;
		this._toggleAttr();

		this.range = null;
		this._off( this.document );

		this._trigger( "close", event );
	},

	widget: function() {
		return this.button;
	},

	menuWidget: function() {
		return this.menu;
	},

	_renderButtonItem: function( item ) {
		var buttonItem = $( "<span>" );

		this._setText( buttonItem, item.label );
		this._addClass( buttonItem, "ui-selectmenu-text" );

		return buttonItem;
	},

	_renderMenu: function( ul, items ) {
		var that = this,
			currentOptgroup = "";

		$.each( items, function( index, item ) {
			var li;

			if ( item.optgroup !== currentOptgroup ) {
				li = $( "<li>", {
					text: item.optgroup
				} );
				that._addClass( li, "ui-selectmenu-optgroup", "ui-menu-divider" +
					( item.element.parent( "optgroup" ).prop( "disabled" ) ?
						" ui-state-disabled" :
						"" ) );

				li.appendTo( ul );

				currentOptgroup = item.optgroup;
			}

			that._renderItemData( ul, item );
		} );
	},

	_renderItemData: function( ul, item ) {
		return this._renderItem( ul, item ).data( "ui-selectmenu-item", item );
	},

	_renderItem: function( ul, item ) {
		var li = $( "<li>" ),
			wrapper = $( "<div>", {
				title: item.element.attr( "title" )
			} );

		if ( item.disabled ) {
			this._addClass( li, null, "ui-state-disabled" );
		}
		this._setText( wrapper, item.label );

		return li.append( wrapper ).appendTo( ul );
	},

	_setText: function( element, value ) {
		if ( value ) {
			element.text( value );
		} else {
			element.html( "&#160;" );
		}
	},

	_move: function( direction, event ) {
		var item, next,
			filter = ".ui-menu-item";

		if ( this.isOpen ) {
			item = this.menuItems.eq( this.focusIndex ).parent( "li" );
		} else {
			item = this.menuItems.eq( this.element[ 0 ].selectedIndex ).parent( "li" );
			filter += ":not(.ui-state-disabled)";
		}

		if ( direction === "first" || direction === "last" ) {
			next = item[ direction === "first" ? "prevAll" : "nextAll" ]( filter ).eq( -1 );
		} else {
			next = item[ direction + "All" ]( filter ).eq( 0 );
		}

		if ( next.length ) {
			this.menuInstance.focus( event, next );
		}
	},

	_getSelectedItem: function() {
		return this.menuItems.eq( this.element[ 0 ].selectedIndex ).parent( "li" );
	},

	_toggle: function( event ) {
		this[ this.isOpen ? "close" : "open" ]( event );
	},

	_setSelection: function() {
		var selection;

		if ( !this.range ) {
			return;
		}

		if ( window.getSelection ) {
			selection = window.getSelection();
			selection.removeAllRanges();
			selection.addRange( this.range );

		// Support: IE8
		} else {
			this.range.select();
		}

		// Support: IE
		// Setting the text selection kills the button focus in IE, but
		// restoring the focus doesn't kill the selection.
		this.button.trigger( "focus" );
	},

	_documentClick: {
		mousedown: function( event ) {
			if ( !this.isOpen ) {
				return;
			}

			if ( !$( event.target ).closest( ".ui-selectmenu-menu, #" +
				$.escapeSelector( this.ids.button ) ).length ) {
				this.close( event );
			}
		}
	},

	_buttonEvents: {

		// Prevent text selection from being reset when interacting with the selectmenu (#10144)
		mousedown: function() {
			var selection;

			if ( window.getSelection ) {
				selection = window.getSelection();
				if ( selection.rangeCount ) {
					this.range = selection.getRangeAt( 0 );
				}

			// Support: IE8
			} else {
				this.range = document.selection.createRange();
			}
		},

		click: function( event ) {
			this._setSelection();
			this._toggle( event );
		},

		keydown: function( event ) {
			var preventDefault = true;
			switch ( event.keyCode ) {
			case $.ui.keyCode.TAB:
			case $.ui.keyCode.ESCAPE:
				this.close( event );
				preventDefault = false;
				break;
			case $.ui.keyCode.ENTER:
				if ( this.isOpen ) {
					this._selectFocusedItem( event );
				}
				break;
			case $.ui.keyCode.UP:
				if ( event.altKey ) {
					this._toggle( event );
				} else {
					this._move( "prev", event );
				}
				break;
			case $.ui.keyCode.DOWN:
				if ( event.altKey ) {
					this._toggle( event );
				} else {
					this._move( "next", event );
				}
				break;
			case $.ui.keyCode.SPACE:
				if ( this.isOpen ) {
					this._selectFocusedItem( event );
				} else {
					this._toggle( event );
				}
				break;
			case $.ui.keyCode.LEFT:
				this._move( "prev", event );
				break;
			case $.ui.keyCode.RIGHT:
				this._move( "next", event );
				break;
			case $.ui.keyCode.HOME:
			case $.ui.keyCode.PAGE_UP:
				this._move( "first", event );
				break;
			case $.ui.keyCode.END:
			case $.ui.keyCode.PAGE_DOWN:
				this._move( "last", event );
				break;
			default:
				this.menu.trigger( event );
				preventDefault = false;
			}

			if ( preventDefault ) {
				event.preventDefault();
			}
		}
	},

	_selectFocusedItem: function( event ) {
		var item = this.menuItems.eq( this.focusIndex ).parent( "li" );
		if ( !item.hasClass( "ui-state-disabled" ) ) {
			this._select( item.data( "ui-selectmenu-item" ), event );
		}
	},

	_select: function( item, event ) {
		var oldIndex = this.element[ 0 ].selectedIndex;

		// Change native select element
		this.element[ 0 ].selectedIndex = item.index;
		this.buttonItem.replaceWith( this.buttonItem = this._renderButtonItem( item ) );
		this._setAria( item );
		this._trigger( "select", event, { item: item } );

		if ( item.index !== oldIndex ) {
			this._trigger( "change", event, { item: item } );
		}

		this.close( event );
	},

	_setAria: function( item ) {
		var id = this.menuItems.eq( item.index ).attr( "id" );

		this.button.attr( {
			"aria-labelledby": id,
			"aria-activedescendant": id
		} );
		this.menu.attr( "aria-activedescendant", id );
	},

	_setOption: function( key, value ) {
		if ( key === "icons" ) {
			var icon = this.button.find( "span.ui-icon" );
			this._removeClass( icon, null, this.options.icons.button )
				._addClass( icon, null, value.button );
		}

		this._super( key, value );

		if ( key === "appendTo" ) {
			this.menuWrap.appendTo( this._appendTo() );
		}

		if ( key === "width" ) {
			this._resizeButton();
		}
	},

	_setOptionDisabled: function( value ) {
		this._super( value );

		this.menuInstance.option( "disabled", value );
		this.button.attr( "aria-disabled", value );
		this._toggleClass( this.button, null, "ui-state-disabled", value );

		this.element.prop( "disabled", value );
		if ( value ) {
			this.button.attr( "tabindex", -1 );
			this.close();
		} else {
			this.button.attr( "tabindex", 0 );
		}
	},

	_appendTo: function() {
		var element = this.options.appendTo;

		if ( element ) {
			element = element.jquery || element.nodeType ?
				$( element ) :
				this.document.find( element ).eq( 0 );
		}

		if ( !element || !element[ 0 ] ) {
			element = this.element.closest( ".ui-front, dialog" );
		}

		if ( !element.length ) {
			element = this.document[ 0 ].body;
		}

		return element;
	},

	_toggleAttr: function() {
		this.button.attr( "aria-expanded", this.isOpen );

		// We can't use two _toggleClass() calls here, because we need to make sure
		// we always remove classes first and add them second, otherwise if both classes have the
		// same theme class, it will be removed after we add it.
		this._removeClass( this.button, "ui-selectmenu-button-" +
			( this.isOpen ? "closed" : "open" ) )
			._addClass( this.button, "ui-selectmenu-button-" +
				( this.isOpen ? "open" : "closed" ) )
			._toggleClass( this.menuWrap, "ui-selectmenu-open", null, this.isOpen );

		this.menu.attr( "aria-hidden", !this.isOpen );
	},

	_resizeButton: function() {
		var width = this.options.width;

		// For `width: false`, just remove inline style and stop
		if ( width === false ) {
			this.button.css( "width", "" );
			return;
		}

		// For `width: null`, match the width of the original element
		if ( width === null ) {
			width = this.element.show().outerWidth();
			this.element.hide();
		}

		this.button.outerWidth( width );
	},

	_resizeMenu: function() {
		this.menu.outerWidth( Math.max(
			this.button.outerWidth(),

			// Support: IE10
			// IE10 wraps long text (possibly a rounding bug)
			// so we add 1px to avoid the wrapping
			this.menu.width( "" ).outerWidth() + 1
		) );
	},

	_getCreateOptions: function() {
		var options = this._super();

		options.disabled = this.element.prop( "disabled" );

		return options;
	},

	_parseOptions: function( options ) {
		var that = this,
			data = [];
		options.each( function( index, item ) {
			if ( item.hidden ) {
				return;
			}

			data.push( that._parseOption( $( item ), index ) );
		} );
		this.items = data;
	},

	_parseOption: function( option, index ) {
		var optgroup = option.parent( "optgroup" );

		return {
			element: option,
			index: index,
			value: option.val(),
			label: option.text(),
			optgroup: optgroup.attr( "label" ) || "",
			disabled: optgroup.prop( "disabled" ) || option.prop( "disabled" )
		};
	},

	_destroy: function() {
		this._unbindFormResetHandler();
		this.menuWrap.remove();
		this.button.remove();
		this.element.show();
		this.element.removeUniqueId();
		this.labels.attr( "for", this.ids.element );
	}
} ] );


/*!
 * jQuery UI Slider 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Slider
//>>group: Widgets
//>>description: Displays a flexible slider with ranges and accessibility via keyboard.
//>>docs: http://api.jqueryui.com/slider/
//>>demos: http://jqueryui.com/slider/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/slider.css
//>>css.theme: ../../themes/base/theme.css


var widgetsSlider = $.widget( "ui.slider", $.ui.mouse, {
	version: "1.13.2",
	widgetEventPrefix: "slide",

	options: {
		animate: false,
		classes: {
			"ui-slider": "ui-corner-all",
			"ui-slider-handle": "ui-corner-all",

			// Note: ui-widget-header isn't the most fittingly semantic framework class for this
			// element, but worked best visually with a variety of themes
			"ui-slider-range": "ui-corner-all ui-widget-header"
		},
		distance: 0,
		max: 100,
		min: 0,
		orientation: "horizontal",
		range: false,
		step: 1,
		value: 0,
		values: null,

		// Callbacks
		change: null,
		slide: null,
		start: null,
		stop: null
	},

	// Number of pages in a slider
	// (how many times can you page up/down to go through the whole range)
	numPages: 5,

	_create: function() {
		this._keySliding = false;
		this._mouseSliding = false;
		this._animateOff = true;
		this._handleIndex = null;
		this._detectOrientation();
		this._mouseInit();
		this._calculateNewMax();

		this._addClass( "ui-slider ui-slider-" + this.orientation,
			"ui-widget ui-widget-content" );

		this._refresh();

		this._animateOff = false;
	},

	_refresh: function() {
		this._createRange();
		this._createHandles();
		this._setupEvents();
		this._refreshValue();
	},

	_createHandles: function() {
		var i, handleCount,
			options = this.options,
			existingHandles = this.element.find( ".ui-slider-handle" ),
			handle = "<span tabindex='0'></span>",
			handles = [];

		handleCount = ( options.values && options.values.length ) || 1;

		if ( existingHandles.length > handleCount ) {
			existingHandles.slice( handleCount ).remove();
			existingHandles = existingHandles.slice( 0, handleCount );
		}

		for ( i = existingHandles.length; i < handleCount; i++ ) {
			handles.push( handle );
		}

		this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) );

		this._addClass( this.handles, "ui-slider-handle", "ui-state-default" );

		this.handle = this.handles.eq( 0 );

		this.handles.each( function( i ) {
			$( this )
				.data( "ui-slider-handle-index", i )
				.attr( "tabIndex", 0 );
		} );
	},

	_createRange: function() {
		var options = this.options;

		if ( options.range ) {
			if ( options.range === true ) {
				if ( !options.values ) {
					options.values = [ this._valueMin(), this._valueMin() ];
				} else if ( options.values.length && options.values.length !== 2 ) {
					options.values = [ options.values[ 0 ], options.values[ 0 ] ];
				} else if ( Array.isArray( options.values ) ) {
					options.values = options.values.slice( 0 );
				}
			}

			if ( !this.range || !this.range.length ) {
				this.range = $( "<div>" )
					.appendTo( this.element );

				this._addClass( this.range, "ui-slider-range" );
			} else {
				this._removeClass( this.range, "ui-slider-range-min ui-slider-range-max" );

				// Handle range switching from true to min/max
				this.range.css( {
					"left": "",
					"bottom": ""
				} );
			}
			if ( options.range === "min" || options.range === "max" ) {
				this._addClass( this.range, "ui-slider-range-" + options.range );
			}
		} else {
			if ( this.range ) {
				this.range.remove();
			}
			this.range = null;
		}
	},

	_setupEvents: function() {
		this._off( this.handles );
		this._on( this.handles, this._handleEvents );
		this._hoverable( this.handles );
		this._focusable( this.handles );
	},

	_destroy: function() {
		this.handles.remove();
		if ( this.range ) {
			this.range.remove();
		}

		this._mouseDestroy();
	},

	_mouseCapture: function( event ) {
		var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle,
			that = this,
			o = this.options;

		if ( o.disabled ) {
			return false;
		}

		this.elementSize = {
			width: this.element.outerWidth(),
			height: this.element.outerHeight()
		};
		this.elementOffset = this.element.offset();

		position = { x: event.pageX, y: event.pageY };
		normValue = this._normValueFromMouse( position );
		distance = this._valueMax() - this._valueMin() + 1;
		this.handles.each( function( i ) {
			var thisDistance = Math.abs( normValue - that.values( i ) );
			if ( ( distance > thisDistance ) ||
				( distance === thisDistance &&
					( i === that._lastChangedValue || that.values( i ) === o.min ) ) ) {
				distance = thisDistance;
				closestHandle = $( this );
				index = i;
			}
		} );

		allowed = this._start( event, index );
		if ( allowed === false ) {
			return false;
		}
		this._mouseSliding = true;

		this._handleIndex = index;

		this._addClass( closestHandle, null, "ui-state-active" );
		closestHandle.trigger( "focus" );

		offset = closestHandle.offset();
		mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" );
		this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
			left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
			top: event.pageY - offset.top -
				( closestHandle.height() / 2 ) -
				( parseInt( closestHandle.css( "borderTopWidth" ), 10 ) || 0 ) -
				( parseInt( closestHandle.css( "borderBottomWidth" ), 10 ) || 0 ) +
				( parseInt( closestHandle.css( "marginTop" ), 10 ) || 0 )
		};

		if ( !this.handles.hasClass( "ui-state-hover" ) ) {
			this._slide( event, index, normValue );
		}
		this._animateOff = true;
		return true;
	},

	_mouseStart: function() {
		return true;
	},

	_mouseDrag: function( event ) {
		var position = { x: event.pageX, y: event.pageY },
			normValue = this._normValueFromMouse( position );

		this._slide( event, this._handleIndex, normValue );

		return false;
	},

	_mouseStop: function( event ) {
		this._removeClass( this.handles, null, "ui-state-active" );
		this._mouseSliding = false;

		this._stop( event, this._handleIndex );
		this._change( event, this._handleIndex );

		this._handleIndex = null;
		this._clickOffset = null;
		this._animateOff = false;

		return false;
	},

	_detectOrientation: function() {
		this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
	},

	_normValueFromMouse: function( position ) {
		var pixelTotal,
			pixelMouse,
			percentMouse,
			valueTotal,
			valueMouse;

		if ( this.orientation === "horizontal" ) {
			pixelTotal = this.elementSize.width;
			pixelMouse = position.x - this.elementOffset.left -
				( this._clickOffset ? this._clickOffset.left : 0 );
		} else {
			pixelTotal = this.elementSize.height;
			pixelMouse = position.y - this.elementOffset.top -
				( this._clickOffset ? this._clickOffset.top : 0 );
		}

		percentMouse = ( pixelMouse / pixelTotal );
		if ( percentMouse > 1 ) {
			percentMouse = 1;
		}
		if ( percentMouse < 0 ) {
			percentMouse = 0;
		}
		if ( this.orientation === "vertical" ) {
			percentMouse = 1 - percentMouse;
		}

		valueTotal = this._valueMax() - this._valueMin();
		valueMouse = this._valueMin() + percentMouse * valueTotal;

		return this._trimAlignValue( valueMouse );
	},

	_uiHash: function( index, value, values ) {
		var uiHash = {
			handle: this.handles[ index ],
			handleIndex: index,
			value: value !== undefined ? value : this.value()
		};

		if ( this._hasMultipleValues() ) {
			uiHash.value = value !== undefined ? value : this.values( index );
			uiHash.values = values || this.values();
		}

		return uiHash;
	},

	_hasMultipleValues: function() {
		return this.options.values && this.options.values.length;
	},

	_start: function( event, index ) {
		return this._trigger( "start", event, this._uiHash( index ) );
	},

	_slide: function( event, index, newVal ) {
		var allowed, otherVal,
			currentValue = this.value(),
			newValues = this.values();

		if ( this._hasMultipleValues() ) {
			otherVal = this.values( index ? 0 : 1 );
			currentValue = this.values( index );

			if ( this.options.values.length === 2 && this.options.range === true ) {
				newVal =  index === 0 ? Math.min( otherVal, newVal ) : Math.max( otherVal, newVal );
			}

			newValues[ index ] = newVal;
		}

		if ( newVal === currentValue ) {
			return;
		}

		allowed = this._trigger( "slide", event, this._uiHash( index, newVal, newValues ) );

		// A slide can be canceled by returning false from the slide callback
		if ( allowed === false ) {
			return;
		}

		if ( this._hasMultipleValues() ) {
			this.values( index, newVal );
		} else {
			this.value( newVal );
		}
	},

	_stop: function( event, index ) {
		this._trigger( "stop", event, this._uiHash( index ) );
	},

	_change: function( event, index ) {
		if ( !this._keySliding && !this._mouseSliding ) {

			//store the last changed value index for reference when handles overlap
			this._lastChangedValue = index;
			this._trigger( "change", event, this._uiHash( index ) );
		}
	},

	value: function( newValue ) {
		if ( arguments.length ) {
			this.options.value = this._trimAlignValue( newValue );
			this._refreshValue();
			this._change( null, 0 );
			return;
		}

		return this._value();
	},

	values: function( index, newValue ) {
		var vals,
			newValues,
			i;

		if ( arguments.length > 1 ) {
			this.options.values[ index ] = this._trimAlignValue( newValue );
			this._refreshValue();
			this._change( null, index );
			return;
		}

		if ( arguments.length ) {
			if ( Array.isArray( arguments[ 0 ] ) ) {
				vals = this.options.values;
				newValues = arguments[ 0 ];
				for ( i = 0; i < vals.length; i += 1 ) {
					vals[ i ] = this._trimAlignValue( newValues[ i ] );
					this._change( null, i );
				}
				this._refreshValue();
			} else {
				if ( this._hasMultipleValues() ) {
					return this._values( index );
				} else {
					return this.value();
				}
			}
		} else {
			return this._values();
		}
	},

	_setOption: function( key, value ) {
		var i,
			valsLength = 0;

		if ( key === "range" && this.options.range === true ) {
			if ( value === "min" ) {
				this.options.value = this._values( 0 );
				this.options.values = null;
			} else if ( value === "max" ) {
				this.options.value = this._values( this.options.values.length - 1 );
				this.options.values = null;
			}
		}

		if ( Array.isArray( this.options.values ) ) {
			valsLength = this.options.values.length;
		}

		this._super( key, value );

		switch ( key ) {
			case "orientation":
				this._detectOrientation();
				this._removeClass( "ui-slider-horizontal ui-slider-vertical" )
					._addClass( "ui-slider-" + this.orientation );
				this._refreshValue();
				if ( this.options.range ) {
					this._refreshRange( value );
				}

				// Reset positioning from previous orientation
				this.handles.css( value === "horizontal" ? "bottom" : "left", "" );
				break;
			case "value":
				this._animateOff = true;
				this._refreshValue();
				this._change( null, 0 );
				this._animateOff = false;
				break;
			case "values":
				this._animateOff = true;
				this._refreshValue();

				// Start from the last handle to prevent unreachable handles (#9046)
				for ( i = valsLength - 1; i >= 0; i-- ) {
					this._change( null, i );
				}
				this._animateOff = false;
				break;
			case "step":
			case "min":
			case "max":
				this._animateOff = true;
				this._calculateNewMax();
				this._refreshValue();
				this._animateOff = false;
				break;
			case "range":
				this._animateOff = true;
				this._refresh();
				this._animateOff = false;
				break;
		}
	},

	_setOptionDisabled: function( value ) {
		this._super( value );

		this._toggleClass( null, "ui-state-disabled", !!value );
	},

	//internal value getter
	// _value() returns value trimmed by min and max, aligned by step
	_value: function() {
		var val = this.options.value;
		val = this._trimAlignValue( val );

		return val;
	},

	//internal values getter
	// _values() returns array of values trimmed by min and max, aligned by step
	// _values( index ) returns single value trimmed by min and max, aligned by step
	_values: function( index ) {
		var val,
			vals,
			i;

		if ( arguments.length ) {
			val = this.options.values[ index ];
			val = this._trimAlignValue( val );

			return val;
		} else if ( this._hasMultipleValues() ) {

			// .slice() creates a copy of the array
			// this copy gets trimmed by min and max and then returned
			vals = this.options.values.slice();
			for ( i = 0; i < vals.length; i += 1 ) {
				vals[ i ] = this._trimAlignValue( vals[ i ] );
			}

			return vals;
		} else {
			return [];
		}
	},

	// Returns the step-aligned value that val is closest to, between (inclusive) min and max
	_trimAlignValue: function( val ) {
		if ( val <= this._valueMin() ) {
			return this._valueMin();
		}
		if ( val >= this._valueMax() ) {
			return this._valueMax();
		}
		var step = ( this.options.step > 0 ) ? this.options.step : 1,
			valModStep = ( val - this._valueMin() ) % step,
			alignValue = val - valModStep;

		if ( Math.abs( valModStep ) * 2 >= step ) {
			alignValue += ( valModStep > 0 ) ? step : ( -step );
		}

		// Since JavaScript has problems with large floats, round
		// the final value to 5 digits after the decimal point (see #4124)
		return parseFloat( alignValue.toFixed( 5 ) );
	},

	_calculateNewMax: function() {
		var max = this.options.max,
			min = this._valueMin(),
			step = this.options.step,
			aboveMin = Math.round( ( max - min ) / step ) * step;
		max = aboveMin + min;
		if ( max > this.options.max ) {

			//If max is not divisible by step, rounding off may increase its value
			max -= step;
		}
		this.max = parseFloat( max.toFixed( this._precision() ) );
	},

	_precision: function() {
		var precision = this._precisionOf( this.options.step );
		if ( this.options.min !== null ) {
			precision = Math.max( precision, this._precisionOf( this.options.min ) );
		}
		return precision;
	},

	_precisionOf: function( num ) {
		var str = num.toString(),
			decimal = str.indexOf( "." );
		return decimal === -1 ? 0 : str.length - decimal - 1;
	},

	_valueMin: function() {
		return this.options.min;
	},

	_valueMax: function() {
		return this.max;
	},

	_refreshRange: function( orientation ) {
		if ( orientation === "vertical" ) {
			this.range.css( { "width": "", "left": "" } );
		}
		if ( orientation === "horizontal" ) {
			this.range.css( { "height": "", "bottom": "" } );
		}
	},

	_refreshValue: function() {
		var lastValPercent, valPercent, value, valueMin, valueMax,
			oRange = this.options.range,
			o = this.options,
			that = this,
			animate = ( !this._animateOff ) ? o.animate : false,
			_set = {};

		if ( this._hasMultipleValues() ) {
			this.handles.each( function( i ) {
				valPercent = ( that.values( i ) - that._valueMin() ) / ( that._valueMax() -
					that._valueMin() ) * 100;
				_set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
				$( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
				if ( that.options.range === true ) {
					if ( that.orientation === "horizontal" ) {
						if ( i === 0 ) {
							that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
								left: valPercent + "%"
							}, o.animate );
						}
						if ( i === 1 ) {
							that.range[ animate ? "animate" : "css" ]( {
								width: ( valPercent - lastValPercent ) + "%"
							}, {
								queue: false,
								duration: o.animate
							} );
						}
					} else {
						if ( i === 0 ) {
							that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
								bottom: ( valPercent ) + "%"
							}, o.animate );
						}
						if ( i === 1 ) {
							that.range[ animate ? "animate" : "css" ]( {
								height: ( valPercent - lastValPercent ) + "%"
							}, {
								queue: false,
								duration: o.animate
							} );
						}
					}
				}
				lastValPercent = valPercent;
			} );
		} else {
			value = this.value();
			valueMin = this._valueMin();
			valueMax = this._valueMax();
			valPercent = ( valueMax !== valueMin ) ?
					( value - valueMin ) / ( valueMax - valueMin ) * 100 :
					0;
			_set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
			this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );

			if ( oRange === "min" && this.orientation === "horizontal" ) {
				this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
					width: valPercent + "%"
				}, o.animate );
			}
			if ( oRange === "max" && this.orientation === "horizontal" ) {
				this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
					width: ( 100 - valPercent ) + "%"
				}, o.animate );
			}
			if ( oRange === "min" && this.orientation === "vertical" ) {
				this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
					height: valPercent + "%"
				}, o.animate );
			}
			if ( oRange === "max" && this.orientation === "vertical" ) {
				this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
					height: ( 100 - valPercent ) + "%"
				}, o.animate );
			}
		}
	},

	_handleEvents: {
		keydown: function( event ) {
			var allowed, curVal, newVal, step,
				index = $( event.target ).data( "ui-slider-handle-index" );

			switch ( event.keyCode ) {
				case $.ui.keyCode.HOME:
				case $.ui.keyCode.END:
				case $.ui.keyCode.PAGE_UP:
				case $.ui.keyCode.PAGE_DOWN:
				case $.ui.keyCode.UP:
				case $.ui.keyCode.RIGHT:
				case $.ui.keyCode.DOWN:
				case $.ui.keyCode.LEFT:
					event.preventDefault();
					if ( !this._keySliding ) {
						this._keySliding = true;
						this._addClass( $( event.target ), null, "ui-state-active" );
						allowed = this._start( event, index );
						if ( allowed === false ) {
							return;
						}
					}
					break;
			}

			step = this.options.step;
			if ( this._hasMultipleValues() ) {
				curVal = newVal = this.values( index );
			} else {
				curVal = newVal = this.value();
			}

			switch ( event.keyCode ) {
				case $.ui.keyCode.HOME:
					newVal = this._valueMin();
					break;
				case $.ui.keyCode.END:
					newVal = this._valueMax();
					break;
				case $.ui.keyCode.PAGE_UP:
					newVal = this._trimAlignValue(
						curVal + ( ( this._valueMax() - this._valueMin() ) / this.numPages )
					);
					break;
				case $.ui.keyCode.PAGE_DOWN:
					newVal = this._trimAlignValue(
						curVal - ( ( this._valueMax() - this._valueMin() ) / this.numPages ) );
					break;
				case $.ui.keyCode.UP:
				case $.ui.keyCode.RIGHT:
					if ( curVal === this._valueMax() ) {
						return;
					}
					newVal = this._trimAlignValue( curVal + step );
					break;
				case $.ui.keyCode.DOWN:
				case $.ui.keyCode.LEFT:
					if ( curVal === this._valueMin() ) {
						return;
					}
					newVal = this._trimAlignValue( curVal - step );
					break;
			}

			this._slide( event, index, newVal );
		},
		keyup: function( event ) {
			var index = $( event.target ).data( "ui-slider-handle-index" );

			if ( this._keySliding ) {
				this._keySliding = false;
				this._stop( event, index );
				this._change( event, index );
				this._removeClass( $( event.target ), null, "ui-state-active" );
			}
		}
	}
} );


/*!
 * jQuery UI Sortable 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Sortable
//>>group: Interactions
//>>description: Enables items in a list to be sorted using the mouse.
//>>docs: http://api.jqueryui.com/sortable/
//>>demos: http://jqueryui.com/sortable/
//>>css.structure: ../../themes/base/sortable.css


var widgetsSortable = $.widget( "ui.sortable", $.ui.mouse, {
	version: "1.13.2",
	widgetEventPrefix: "sort",
	ready: false,
	options: {
		appendTo: "parent",
		axis: false,
		connectWith: false,
		containment: false,
		cursor: "auto",
		cursorAt: false,
		dropOnEmpty: true,
		forcePlaceholderSize: false,
		forceHelperSize: false,
		grid: false,
		handle: false,
		helper: "original",
		items: "> *",
		opacity: false,
		placeholder: false,
		revert: false,
		scroll: true,
		scrollSensitivity: 20,
		scrollSpeed: 20,
		scope: "default",
		tolerance: "intersect",
		zIndex: 1000,

		// Callbacks
		activate: null,
		beforeStop: null,
		change: null,
		deactivate: null,
		out: null,
		over: null,
		receive: null,
		remove: null,
		sort: null,
		start: null,
		stop: null,
		update: null
	},

	_isOverAxis: function( x, reference, size ) {
		return ( x >= reference ) && ( x < ( reference + size ) );
	},

	_isFloating: function( item ) {
		return ( /left|right/ ).test( item.css( "float" ) ) ||
			( /inline|table-cell/ ).test( item.css( "display" ) );
	},

	_create: function() {
		this.containerCache = {};
		this._addClass( "ui-sortable" );

		//Get the items
		this.refresh();

		//Let's determine the parent's offset
		this.offset = this.element.offset();

		//Initialize mouse events for interaction
		this._mouseInit();

		this._setHandleClassName();

		//We're ready to go
		this.ready = true;

	},

	_setOption: function( key, value ) {
		this._super( key, value );

		if ( key === "handle" ) {
			this._setHandleClassName();
		}
	},

	_setHandleClassName: function() {
		var that = this;
		this._removeClass( this.element.find( ".ui-sortable-handle" ), "ui-sortable-handle" );
		$.each( this.items, function() {
			that._addClass(
				this.instance.options.handle ?
					this.item.find( this.instance.options.handle ) :
					this.item,
				"ui-sortable-handle"
			);
		} );
	},

	_destroy: function() {
		this._mouseDestroy();

		for ( var i = this.items.length - 1; i >= 0; i-- ) {
			this.items[ i ].item.removeData( this.widgetName + "-item" );
		}

		return this;
	},

	_mouseCapture: function( event, overrideHandle ) {
		var currentItem = null,
			validHandle = false,
			that = this;

		if ( this.reverting ) {
			return false;
		}

		if ( this.options.disabled || this.options.type === "static" ) {
			return false;
		}

		//We have to refresh the items data once first
		this._refreshItems( event );

		//Find out if the clicked node (or one of its parents) is a actual item in this.items
		$( event.target ).parents().each( function() {
			if ( $.data( this, that.widgetName + "-item" ) === that ) {
				currentItem = $( this );
				return false;
			}
		} );
		if ( $.data( event.target, that.widgetName + "-item" ) === that ) {
			currentItem = $( event.target );
		}

		if ( !currentItem ) {
			return false;
		}
		if ( this.options.handle && !overrideHandle ) {
			$( this.options.handle, currentItem ).find( "*" ).addBack().each( function() {
				if ( this === event.target ) {
					validHandle = true;
				}
			} );
			if ( !validHandle ) {
				return false;
			}
		}

		this.currentItem = currentItem;
		this._removeCurrentsFromItems();
		return true;

	},

	_mouseStart: function( event, overrideHandle, noActivation ) {

		var i, body,
			o = this.options;

		this.currentContainer = this;

		//We only need to call refreshPositions, because the refreshItems call has been moved to
		// mouseCapture
		this.refreshPositions();

		//Prepare the dragged items parent
		this.appendTo = $( o.appendTo !== "parent" ?
				o.appendTo :
				this.currentItem.parent() );

		//Create and append the visible helper
		this.helper = this._createHelper( event );

		//Cache the helper size
		this._cacheHelperProportions();

		/*
		 * - Position generation -
		 * This block generates everything position related - it's the core of draggables.
		 */

		//Cache the margins of the original element
		this._cacheMargins();

		//The element's absolute position on the page minus margins
		this.offset = this.currentItem.offset();
		this.offset = {
			top: this.offset.top - this.margins.top,
			left: this.offset.left - this.margins.left
		};

		$.extend( this.offset, {
			click: { //Where the click happened, relative to the element
				left: event.pageX - this.offset.left,
				top: event.pageY - this.offset.top
			},

			// This is a relative to absolute position minus the actual position calculation -
			// only used for relative positioned helper
			relative: this._getRelativeOffset()
		} );

		// After we get the helper offset, but before we get the parent offset we can
		// change the helper's position to absolute
		// TODO: Still need to figure out a way to make relative sorting possible
		this.helper.css( "position", "absolute" );
		this.cssPosition = this.helper.css( "position" );

		//Adjust the mouse offset relative to the helper if "cursorAt" is supplied
		if ( o.cursorAt ) {
			this._adjustOffsetFromHelper( o.cursorAt );
		}

		//Cache the former DOM position
		this.domPosition = {
			prev: this.currentItem.prev()[ 0 ],
			parent: this.currentItem.parent()[ 0 ]
		};

		// If the helper is not the original, hide the original so it's not playing any role during
		// the drag, won't cause anything bad this way
		if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
			this.currentItem.hide();
		}

		//Create the placeholder
		this._createPlaceholder();

		//Get the next scrolling parent
		this.scrollParent = this.placeholder.scrollParent();

		$.extend( this.offset, {
			parent: this._getParentOffset()
		} );

		//Set a containment if given in the options
		if ( o.containment ) {
			this._setContainment();
		}

		if ( o.cursor && o.cursor !== "auto" ) { // cursor option
			body = this.document.find( "body" );

			// Support: IE
			this.storedCursor = body.css( "cursor" );
			body.css( "cursor", o.cursor );

			this.storedStylesheet =
				$( "<style>*{ cursor: " + o.cursor + " !important; }</style>" ).appendTo( body );
		}

		// We need to make sure to grab the zIndex before setting the
		// opacity, because setting the opacity to anything lower than 1
		// causes the zIndex to change from "auto" to 0.
		if ( o.zIndex ) { // zIndex option
			if ( this.helper.css( "zIndex" ) ) {
				this._storedZIndex = this.helper.css( "zIndex" );
			}
			this.helper.css( "zIndex", o.zIndex );
		}

		if ( o.opacity ) { // opacity option
			if ( this.helper.css( "opacity" ) ) {
				this._storedOpacity = this.helper.css( "opacity" );
			}
			this.helper.css( "opacity", o.opacity );
		}

		//Prepare scrolling
		if ( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
				this.scrollParent[ 0 ].tagName !== "HTML" ) {
			this.overflowOffset = this.scrollParent.offset();
		}

		//Call callbacks
		this._trigger( "start", event, this._uiHash() );

		//Recache the helper size
		if ( !this._preserveHelperProportions ) {
			this._cacheHelperProportions();
		}

		//Post "activate" events to possible containers
		if ( !noActivation ) {
			for ( i = this.containers.length - 1; i >= 0; i-- ) {
				this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) );
			}
		}

		//Prepare possible droppables
		if ( $.ui.ddmanager ) {
			$.ui.ddmanager.current = this;
		}

		if ( $.ui.ddmanager && !o.dropBehaviour ) {
			$.ui.ddmanager.prepareOffsets( this, event );
		}

		this.dragging = true;

		this._addClass( this.helper, "ui-sortable-helper" );

		//Move the helper, if needed
		if ( !this.helper.parent().is( this.appendTo ) ) {
			this.helper.detach().appendTo( this.appendTo );

			//Update position
			this.offset.parent = this._getParentOffset();
		}

		//Generate the original position
		this.position = this.originalPosition = this._generatePosition( event );
		this.originalPageX = event.pageX;
		this.originalPageY = event.pageY;
		this.lastPositionAbs = this.positionAbs = this._convertPositionTo( "absolute" );

		this._mouseDrag( event );

		return true;

	},

	_scroll: function( event ) {
		var o = this.options,
			scrolled = false;

		if ( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
				this.scrollParent[ 0 ].tagName !== "HTML" ) {

			if ( ( this.overflowOffset.top + this.scrollParent[ 0 ].offsetHeight ) -
					event.pageY < o.scrollSensitivity ) {
				this.scrollParent[ 0 ].scrollTop =
					scrolled = this.scrollParent[ 0 ].scrollTop + o.scrollSpeed;
			} else if ( event.pageY - this.overflowOffset.top < o.scrollSensitivity ) {
				this.scrollParent[ 0 ].scrollTop =
					scrolled = this.scrollParent[ 0 ].scrollTop - o.scrollSpeed;
			}

			if ( ( this.overflowOffset.left + this.scrollParent[ 0 ].offsetWidth ) -
					event.pageX < o.scrollSensitivity ) {
				this.scrollParent[ 0 ].scrollLeft = scrolled =
					this.scrollParent[ 0 ].scrollLeft + o.scrollSpeed;
			} else if ( event.pageX - this.overflowOffset.left < o.scrollSensitivity ) {
				this.scrollParent[ 0 ].scrollLeft = scrolled =
					this.scrollParent[ 0 ].scrollLeft - o.scrollSpeed;
			}

		} else {

			if ( event.pageY - this.document.scrollTop() < o.scrollSensitivity ) {
				scrolled = this.document.scrollTop( this.document.scrollTop() - o.scrollSpeed );
			} else if ( this.window.height() - ( event.pageY - this.document.scrollTop() ) <
					o.scrollSensitivity ) {
				scrolled = this.document.scrollTop( this.document.scrollTop() + o.scrollSpeed );
			}

			if ( event.pageX - this.document.scrollLeft() < o.scrollSensitivity ) {
				scrolled = this.document.scrollLeft(
					this.document.scrollLeft() - o.scrollSpeed
				);
			} else if ( this.window.width() - ( event.pageX - this.document.scrollLeft() ) <
					o.scrollSensitivity ) {
				scrolled = this.document.scrollLeft(
					this.document.scrollLeft() + o.scrollSpeed
				);
			}

		}

		return scrolled;
	},

	_mouseDrag: function( event ) {
		var i, item, itemElement, intersection,
			o = this.options;

		//Compute the helpers position
		this.position = this._generatePosition( event );
		this.positionAbs = this._convertPositionTo( "absolute" );

		//Set the helper position
		if ( !this.options.axis || this.options.axis !== "y" ) {
			this.helper[ 0 ].style.left = this.position.left + "px";
		}
		if ( !this.options.axis || this.options.axis !== "x" ) {
			this.helper[ 0 ].style.top = this.position.top + "px";
		}

		//Do scrolling
		if ( o.scroll ) {
			if ( this._scroll( event ) !== false ) {

				//Update item positions used in position checks
				this._refreshItemPositions( true );

				if ( $.ui.ddmanager && !o.dropBehaviour ) {
					$.ui.ddmanager.prepareOffsets( this, event );
				}
			}
		}

		this.dragDirection = {
			vertical: this._getDragVerticalDirection(),
			horizontal: this._getDragHorizontalDirection()
		};

		//Rearrange
		for ( i = this.items.length - 1; i >= 0; i-- ) {

			//Cache variables and intersection, continue if no intersection
			item = this.items[ i ];
			itemElement = item.item[ 0 ];
			intersection = this._intersectsWithPointer( item );
			if ( !intersection ) {
				continue;
			}

			// Only put the placeholder inside the current Container, skip all
			// items from other containers. This works because when moving
			// an item from one container to another the
			// currentContainer is switched before the placeholder is moved.
			//
			// Without this, moving items in "sub-sortables" can cause
			// the placeholder to jitter between the outer and inner container.
			if ( item.instance !== this.currentContainer ) {
				continue;
			}

			// Cannot intersect with itself
			// no useless actions that have been done before
			// no action if the item moved is the parent of the item checked
			if ( itemElement !== this.currentItem[ 0 ] &&
				this.placeholder[ intersection === 1 ?
				"next" : "prev" ]()[ 0 ] !== itemElement &&
				!$.contains( this.placeholder[ 0 ], itemElement ) &&
				( this.options.type === "semi-dynamic" ?
					!$.contains( this.element[ 0 ], itemElement ) :
					true
				)
			) {

				this.direction = intersection === 1 ? "down" : "up";

				if ( this.options.tolerance === "pointer" ||
						this._intersectsWithSides( item ) ) {
					this._rearrange( event, item );
				} else {
					break;
				}

				this._trigger( "change", event, this._uiHash() );
				break;
			}
		}

		//Post events to containers
		this._contactContainers( event );

		//Interconnect with droppables
		if ( $.ui.ddmanager ) {
			$.ui.ddmanager.drag( this, event );
		}

		//Call callbacks
		this._trigger( "sort", event, this._uiHash() );

		this.lastPositionAbs = this.positionAbs;
		return false;

	},

	_mouseStop: function( event, noPropagation ) {

		if ( !event ) {
			return;
		}

		//If we are using droppables, inform the manager about the drop
		if ( $.ui.ddmanager && !this.options.dropBehaviour ) {
			$.ui.ddmanager.drop( this, event );
		}

		if ( this.options.revert ) {
			var that = this,
				cur = this.placeholder.offset(),
				axis = this.options.axis,
				animation = {};

			if ( !axis || axis === "x" ) {
				animation.left = cur.left - this.offset.parent.left - this.margins.left +
					( this.offsetParent[ 0 ] === this.document[ 0 ].body ?
						0 :
						this.offsetParent[ 0 ].scrollLeft
					);
			}
			if ( !axis || axis === "y" ) {
				animation.top = cur.top - this.offset.parent.top - this.margins.top +
					( this.offsetParent[ 0 ] === this.document[ 0 ].body ?
						0 :
						this.offsetParent[ 0 ].scrollTop
					);
			}
			this.reverting = true;
			$( this.helper ).animate(
				animation,
				parseInt( this.options.revert, 10 ) || 500,
				function() {
					that._clear( event );
				}
			);
		} else {
			this._clear( event, noPropagation );
		}

		return false;

	},

	cancel: function() {

		if ( this.dragging ) {

			this._mouseUp( new $.Event( "mouseup", { target: null } ) );

			if ( this.options.helper === "original" ) {
				this.currentItem.css( this._storedCSS );
				this._removeClass( this.currentItem, "ui-sortable-helper" );
			} else {
				this.currentItem.show();
			}

			//Post deactivating events to containers
			for ( var i = this.containers.length - 1; i >= 0; i-- ) {
				this.containers[ i ]._trigger( "deactivate", null, this._uiHash( this ) );
				if ( this.containers[ i ].containerCache.over ) {
					this.containers[ i ]._trigger( "out", null, this._uiHash( this ) );
					this.containers[ i ].containerCache.over = 0;
				}
			}

		}

		if ( this.placeholder ) {

			//$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately,
			// it unbinds ALL events from the original node!
			if ( this.placeholder[ 0 ].parentNode ) {
				this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] );
			}
			if ( this.options.helper !== "original" && this.helper &&
					this.helper[ 0 ].parentNode ) {
				this.helper.remove();
			}

			$.extend( this, {
				helper: null,
				dragging: false,
				reverting: false,
				_noFinalSort: null
			} );

			if ( this.domPosition.prev ) {
				$( this.domPosition.prev ).after( this.currentItem );
			} else {
				$( this.domPosition.parent ).prepend( this.currentItem );
			}
		}

		return this;

	},

	serialize: function( o ) {

		var items = this._getItemsAsjQuery( o && o.connected ),
			str = [];
		o = o || {};

		$( items ).each( function() {
			var res = ( $( o.item || this ).attr( o.attribute || "id" ) || "" )
				.match( o.expression || ( /(.+)[\-=_](.+)/ ) );
			if ( res ) {
				str.push(
					( o.key || res[ 1 ] + "[]" ) +
					"=" + ( o.key && o.expression ? res[ 1 ] : res[ 2 ] ) );
			}
		} );

		if ( !str.length && o.key ) {
			str.push( o.key + "=" );
		}

		return str.join( "&" );

	},

	toArray: function( o ) {

		var items = this._getItemsAsjQuery( o && o.connected ),
			ret = [];

		o = o || {};

		items.each( function() {
			ret.push( $( o.item || this ).attr( o.attribute || "id" ) || "" );
		} );
		return ret;

	},

	/* Be careful with the following core functions */
	_intersectsWith: function( item ) {

		var x1 = this.positionAbs.left,
			x2 = x1 + this.helperProportions.width,
			y1 = this.positionAbs.top,
			y2 = y1 + this.helperProportions.height,
			l = item.left,
			r = l + item.width,
			t = item.top,
			b = t + item.height,
			dyClick = this.offset.click.top,
			dxClick = this.offset.click.left,
			isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t &&
				( y1 + dyClick ) < b ),
			isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l &&
				( x1 + dxClick ) < r ),
			isOverElement = isOverElementHeight && isOverElementWidth;

		if ( this.options.tolerance === "pointer" ||
			this.options.forcePointerForContainers ||
			( this.options.tolerance !== "pointer" &&
				this.helperProportions[ this.floating ? "width" : "height" ] >
				item[ this.floating ? "width" : "height" ] )
		) {
			return isOverElement;
		} else {

			return ( l < x1 + ( this.helperProportions.width / 2 ) && // Right Half
				x2 - ( this.helperProportions.width / 2 ) < r && // Left Half
				t < y1 + ( this.helperProportions.height / 2 ) && // Bottom Half
				y2 - ( this.helperProportions.height / 2 ) < b ); // Top Half

		}
	},

	_intersectsWithPointer: function( item ) {
		var verticalDirection, horizontalDirection,
			isOverElementHeight = ( this.options.axis === "x" ) ||
				this._isOverAxis(
					this.positionAbs.top + this.offset.click.top, item.top, item.height ),
			isOverElementWidth = ( this.options.axis === "y" ) ||
				this._isOverAxis(
					this.positionAbs.left + this.offset.click.left, item.left, item.width ),
			isOverElement = isOverElementHeight && isOverElementWidth;

		if ( !isOverElement ) {
			return false;
		}

		verticalDirection = this.dragDirection.vertical;
		horizontalDirection = this.dragDirection.horizontal;

		return this.floating ?
			( ( horizontalDirection === "right" || verticalDirection === "down" ) ? 2 : 1 ) :
			( verticalDirection && ( verticalDirection === "down" ? 2 : 1 ) );

	},

	_intersectsWithSides: function( item ) {

		var isOverBottomHalf = this._isOverAxis( this.positionAbs.top +
				this.offset.click.top, item.top + ( item.height / 2 ), item.height ),
			isOverRightHalf = this._isOverAxis( this.positionAbs.left +
				this.offset.click.left, item.left + ( item.width / 2 ), item.width ),
			verticalDirection = this.dragDirection.vertical,
			horizontalDirection = this.dragDirection.horizontal;

		if ( this.floating && horizontalDirection ) {
			return ( ( horizontalDirection === "right" && isOverRightHalf ) ||
				( horizontalDirection === "left" && !isOverRightHalf ) );
		} else {
			return verticalDirection && ( ( verticalDirection === "down" && isOverBottomHalf ) ||
				( verticalDirection === "up" && !isOverBottomHalf ) );
		}

	},

	_getDragVerticalDirection: function() {
		var delta = this.positionAbs.top - this.lastPositionAbs.top;
		return delta !== 0 && ( delta > 0 ? "down" : "up" );
	},

	_getDragHorizontalDirection: function() {
		var delta = this.positionAbs.left - this.lastPositionAbs.left;
		return delta !== 0 && ( delta > 0 ? "right" : "left" );
	},

	refresh: function( event ) {
		this._refreshItems( event );
		this._setHandleClassName();
		this.refreshPositions();
		return this;
	},

	_connectWith: function() {
		var options = this.options;
		return options.connectWith.constructor === String ?
			[ options.connectWith ] :
			options.connectWith;
	},

	_getItemsAsjQuery: function( connected ) {

		var i, j, cur, inst,
			items = [],
			queries = [],
			connectWith = this._connectWith();

		if ( connectWith && connected ) {
			for ( i = connectWith.length - 1; i >= 0; i-- ) {
				cur = $( connectWith[ i ], this.document[ 0 ] );
				for ( j = cur.length - 1; j >= 0; j-- ) {
					inst = $.data( cur[ j ], this.widgetFullName );
					if ( inst && inst !== this && !inst.options.disabled ) {
						queries.push( [ typeof inst.options.items === "function" ?
							inst.options.items.call( inst.element ) :
							$( inst.options.items, inst.element )
								.not( ".ui-sortable-helper" )
								.not( ".ui-sortable-placeholder" ), inst ] );
					}
				}
			}
		}

		queries.push( [ typeof this.options.items === "function" ?
			this.options.items
				.call( this.element, null, { options: this.options, item: this.currentItem } ) :
			$( this.options.items, this.element )
				.not( ".ui-sortable-helper" )
				.not( ".ui-sortable-placeholder" ), this ] );

		function addItems() {
			items.push( this );
		}
		for ( i = queries.length - 1; i >= 0; i-- ) {
			queries[ i ][ 0 ].each( addItems );
		}

		return $( items );

	},

	_removeCurrentsFromItems: function() {

		var list = this.currentItem.find( ":data(" + this.widgetName + "-item)" );

		this.items = $.grep( this.items, function( item ) {
			for ( var j = 0; j < list.length; j++ ) {
				if ( list[ j ] === item.item[ 0 ] ) {
					return false;
				}
			}
			return true;
		} );

	},

	_refreshItems: function( event ) {

		this.items = [];
		this.containers = [ this ];

		var i, j, cur, inst, targetData, _queries, item, queriesLength,
			items = this.items,
			queries = [ [ typeof this.options.items === "function" ?
				this.options.items.call( this.element[ 0 ], event, { item: this.currentItem } ) :
				$( this.options.items, this.element ), this ] ],
			connectWith = this._connectWith();

		//Shouldn't be run the first time through due to massive slow-down
		if ( connectWith && this.ready ) {
			for ( i = connectWith.length - 1; i >= 0; i-- ) {
				cur = $( connectWith[ i ], this.document[ 0 ] );
				for ( j = cur.length - 1; j >= 0; j-- ) {
					inst = $.data( cur[ j ], this.widgetFullName );
					if ( inst && inst !== this && !inst.options.disabled ) {
						queries.push( [ typeof inst.options.items === "function" ?
							inst.options.items
								.call( inst.element[ 0 ], event, { item: this.currentItem } ) :
							$( inst.options.items, inst.element ), inst ] );
						this.containers.push( inst );
					}
				}
			}
		}

		for ( i = queries.length - 1; i >= 0; i-- ) {
			targetData = queries[ i ][ 1 ];
			_queries = queries[ i ][ 0 ];

			for ( j = 0, queriesLength = _queries.length; j < queriesLength; j++ ) {
				item = $( _queries[ j ] );

				// Data for target checking (mouse manager)
				item.data( this.widgetName + "-item", targetData );

				items.push( {
					item: item,
					instance: targetData,
					width: 0, height: 0,
					left: 0, top: 0
				} );
			}
		}

	},

	_refreshItemPositions: function( fast ) {
		var i, item, t, p;

		for ( i = this.items.length - 1; i >= 0; i-- ) {
			item = this.items[ i ];

			//We ignore calculating positions of all connected containers when we're not over them
			if ( this.currentContainer && item.instance !== this.currentContainer &&
					item.item[ 0 ] !== this.currentItem[ 0 ] ) {
				continue;
			}

			t = this.options.toleranceElement ?
				$( this.options.toleranceElement, item.item ) :
				item.item;

			if ( !fast ) {
				item.width = t.outerWidth();
				item.height = t.outerHeight();
			}

			p = t.offset();
			item.left = p.left;
			item.top = p.top;
		}
	},

	refreshPositions: function( fast ) {

		// Determine whether items are being displayed horizontally
		this.floating = this.items.length ?
			this.options.axis === "x" || this._isFloating( this.items[ 0 ].item ) :
			false;

		// This has to be redone because due to the item being moved out/into the offsetParent,
		// the offsetParent's position will change
		if ( this.offsetParent && this.helper ) {
			this.offset.parent = this._getParentOffset();
		}

		this._refreshItemPositions( fast );

		var i, p;

		if ( this.options.custom && this.options.custom.refreshContainers ) {
			this.options.custom.refreshContainers.call( this );
		} else {
			for ( i = this.containers.length - 1; i >= 0; i-- ) {
				p = this.containers[ i ].element.offset();
				this.containers[ i ].containerCache.left = p.left;
				this.containers[ i ].containerCache.top = p.top;
				this.containers[ i ].containerCache.width =
					this.containers[ i ].element.outerWidth();
				this.containers[ i ].containerCache.height =
					this.containers[ i ].element.outerHeight();
			}
		}

		return this;
	},

	_createPlaceholder: function( that ) {
		that = that || this;
		var className, nodeName,
			o = that.options;

		if ( !o.placeholder || o.placeholder.constructor === String ) {
			className = o.placeholder;
			nodeName = that.currentItem[ 0 ].nodeName.toLowerCase();
			o.placeholder = {
				element: function() {

					var element = $( "<" + nodeName + ">", that.document[ 0 ] );

					that._addClass( element, "ui-sortable-placeholder",
							className || that.currentItem[ 0 ].className )
						._removeClass( element, "ui-sortable-helper" );

					if ( nodeName === "tbody" ) {
						that._createTrPlaceholder(
							that.currentItem.find( "tr" ).eq( 0 ),
							$( "<tr>", that.document[ 0 ] ).appendTo( element )
						);
					} else if ( nodeName === "tr" ) {
						that._createTrPlaceholder( that.currentItem, element );
					} else if ( nodeName === "img" ) {
						element.attr( "src", that.currentItem.attr( "src" ) );
					}

					if ( !className ) {
						element.css( "visibility", "hidden" );
					}

					return element;
				},
				update: function( container, p ) {

					// 1. If a className is set as 'placeholder option, we don't force sizes -
					// the class is responsible for that
					// 2. The option 'forcePlaceholderSize can be enabled to force it even if a
					// class name is specified
					if ( className && !o.forcePlaceholderSize ) {
						return;
					}

					// If the element doesn't have a actual height or width by itself (without
					// styles coming from a stylesheet), it receives the inline height and width
					// from the dragged item. Or, if it's a tbody or tr, it's going to have a height
					// anyway since we're populating them with <td>s above, but they're unlikely to
					// be the correct height on their own if the row heights are dynamic, so we'll
					// always assign the height of the dragged item given forcePlaceholderSize
					// is true.
					if ( !p.height() || ( o.forcePlaceholderSize &&
							( nodeName === "tbody" || nodeName === "tr" ) ) ) {
						p.height(
							that.currentItem.innerHeight() -
							parseInt( that.currentItem.css( "paddingTop" ) || 0, 10 ) -
							parseInt( that.currentItem.css( "paddingBottom" ) || 0, 10 ) );
					}
					if ( !p.width() ) {
						p.width(
							that.currentItem.innerWidth() -
							parseInt( that.currentItem.css( "paddingLeft" ) || 0, 10 ) -
							parseInt( that.currentItem.css( "paddingRight" ) || 0, 10 ) );
					}
				}
			};
		}

		//Create the placeholder
		that.placeholder = $( o.placeholder.element.call( that.element, that.currentItem ) );

		//Append it after the actual current item
		that.currentItem.after( that.placeholder );

		//Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
		o.placeholder.update( that, that.placeholder );

	},

	_createTrPlaceholder: function( sourceTr, targetTr ) {
		var that = this;

		sourceTr.children().each( function() {
			$( "<td>&#160;</td>", that.document[ 0 ] )
				.attr( "colspan", $( this ).attr( "colspan" ) || 1 )
				.appendTo( targetTr );
		} );
	},

	_contactContainers: function( event ) {
		var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, cur, nearBottom,
			floating, axis,
			innermostContainer = null,
			innermostIndex = null;

		// Get innermost container that intersects with item
		for ( i = this.containers.length - 1; i >= 0; i-- ) {

			// Never consider a container that's located within the item itself
			if ( $.contains( this.currentItem[ 0 ], this.containers[ i ].element[ 0 ] ) ) {
				continue;
			}

			if ( this._intersectsWith( this.containers[ i ].containerCache ) ) {

				// If we've already found a container and it's more "inner" than this, then continue
				if ( innermostContainer &&
						$.contains(
							this.containers[ i ].element[ 0 ],
							innermostContainer.element[ 0 ] ) ) {
					continue;
				}

				innermostContainer = this.containers[ i ];
				innermostIndex = i;

			} else {

				// container doesn't intersect. trigger "out" event if necessary
				if ( this.containers[ i ].containerCache.over ) {
					this.containers[ i ]._trigger( "out", event, this._uiHash( this ) );
					this.containers[ i ].containerCache.over = 0;
				}
			}

		}

		// If no intersecting containers found, return
		if ( !innermostContainer ) {
			return;
		}

		// Move the item into the container if it's not there already
		if ( this.containers.length === 1 ) {
			if ( !this.containers[ innermostIndex ].containerCache.over ) {
				this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) );
				this.containers[ innermostIndex ].containerCache.over = 1;
			}
		} else {

			// When entering a new container, we will find the item with the least distance and
			// append our item near it
			dist = 10000;
			itemWithLeastDistance = null;
			floating = innermostContainer.floating || this._isFloating( this.currentItem );
			posProperty = floating ? "left" : "top";
			sizeProperty = floating ? "width" : "height";
			axis = floating ? "pageX" : "pageY";

			for ( j = this.items.length - 1; j >= 0; j-- ) {
				if ( !$.contains(
						this.containers[ innermostIndex ].element[ 0 ], this.items[ j ].item[ 0 ] )
				) {
					continue;
				}
				if ( this.items[ j ].item[ 0 ] === this.currentItem[ 0 ] ) {
					continue;
				}

				cur = this.items[ j ].item.offset()[ posProperty ];
				nearBottom = false;
				if ( event[ axis ] - cur > this.items[ j ][ sizeProperty ] / 2 ) {
					nearBottom = true;
				}

				if ( Math.abs( event[ axis ] - cur ) < dist ) {
					dist = Math.abs( event[ axis ] - cur );
					itemWithLeastDistance = this.items[ j ];
					this.direction = nearBottom ? "up" : "down";
				}
			}

			//Check if dropOnEmpty is enabled
			if ( !itemWithLeastDistance && !this.options.dropOnEmpty ) {
				return;
			}

			if ( this.currentContainer === this.containers[ innermostIndex ] ) {
				if ( !this.currentContainer.containerCache.over ) {
					this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash() );
					this.currentContainer.containerCache.over = 1;
				}
				return;
			}

			if ( itemWithLeastDistance ) {
				this._rearrange( event, itemWithLeastDistance, null, true );
			} else {
				this._rearrange( event, null, this.containers[ innermostIndex ].element, true );
			}
			this._trigger( "change", event, this._uiHash() );
			this.containers[ innermostIndex ]._trigger( "change", event, this._uiHash( this ) );
			this.currentContainer = this.containers[ innermostIndex ];

			//Update the placeholder
			this.options.placeholder.update( this.currentContainer, this.placeholder );

			//Update scrollParent
			this.scrollParent = this.placeholder.scrollParent();

			//Update overflowOffset
			if ( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
					this.scrollParent[ 0 ].tagName !== "HTML" ) {
				this.overflowOffset = this.scrollParent.offset();
			}

			this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) );
			this.containers[ innermostIndex ].containerCache.over = 1;
		}

	},

	_createHelper: function( event ) {

		var o = this.options,
			helper = typeof o.helper === "function" ?
				$( o.helper.apply( this.element[ 0 ], [ event, this.currentItem ] ) ) :
				( o.helper === "clone" ? this.currentItem.clone() : this.currentItem );

		//Add the helper to the DOM if that didn't happen already
		if ( !helper.parents( "body" ).length ) {
			this.appendTo[ 0 ].appendChild( helper[ 0 ] );
		}

		if ( helper[ 0 ] === this.currentItem[ 0 ] ) {
			this._storedCSS = {
				width: this.currentItem[ 0 ].style.width,
				height: this.currentItem[ 0 ].style.height,
				position: this.currentItem.css( "position" ),
				top: this.currentItem.css( "top" ),
				left: this.currentItem.css( "left" )
			};
		}

		if ( !helper[ 0 ].style.width || o.forceHelperSize ) {
			helper.width( this.currentItem.width() );
		}
		if ( !helper[ 0 ].style.height || o.forceHelperSize ) {
			helper.height( this.currentItem.height() );
		}

		return helper;

	},

	_adjustOffsetFromHelper: function( obj ) {
		if ( typeof obj === "string" ) {
			obj = obj.split( " " );
		}
		if ( Array.isArray( obj ) ) {
			obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 };
		}
		if ( "left" in obj ) {
			this.offset.click.left = obj.left + this.margins.left;
		}
		if ( "right" in obj ) {
			this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
		}
		if ( "top" in obj ) {
			this.offset.click.top = obj.top + this.margins.top;
		}
		if ( "bottom" in obj ) {
			this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
		}
	},

	_getParentOffset: function() {

		//Get the offsetParent and cache its position
		this.offsetParent = this.helper.offsetParent();
		var po = this.offsetParent.offset();

		// This is a special case where we need to modify a offset calculated on start, since the
		// following happened:
		// 1. The position of the helper is absolute, so it's position is calculated based on the
		// next positioned parent
		// 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't
		// the document, which means that the scroll is included in the initial calculation of the
		// offset of the parent, and never recalculated upon drag
		if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== this.document[ 0 ] &&
				$.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) {
			po.left += this.scrollParent.scrollLeft();
			po.top += this.scrollParent.scrollTop();
		}

		// This needs to be actually done for all browsers, since pageX/pageY includes this
		// information with an ugly IE fix
		if ( this.offsetParent[ 0 ] === this.document[ 0 ].body ||
				( this.offsetParent[ 0 ].tagName &&
				this.offsetParent[ 0 ].tagName.toLowerCase() === "html" && $.ui.ie ) ) {
			po = { top: 0, left: 0 };
		}

		return {
			top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ),
			left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 )
		};

	},

	_getRelativeOffset: function() {

		if ( this.cssPosition === "relative" ) {
			var p = this.currentItem.position();
			return {
				top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) +
					this.scrollParent.scrollTop(),
				left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) +
					this.scrollParent.scrollLeft()
			};
		} else {
			return { top: 0, left: 0 };
		}

	},

	_cacheMargins: function() {
		this.margins = {
			left: ( parseInt( this.currentItem.css( "marginLeft" ), 10 ) || 0 ),
			top: ( parseInt( this.currentItem.css( "marginTop" ), 10 ) || 0 )
		};
	},

	_cacheHelperProportions: function() {
		this.helperProportions = {
			width: this.helper.outerWidth(),
			height: this.helper.outerHeight()
		};
	},

	_setContainment: function() {

		var ce, co, over,
			o = this.options;
		if ( o.containment === "parent" ) {
			o.containment = this.helper[ 0 ].parentNode;
		}
		if ( o.containment === "document" || o.containment === "window" ) {
			this.containment = [
				0 - this.offset.relative.left - this.offset.parent.left,
				0 - this.offset.relative.top - this.offset.parent.top,
				o.containment === "document" ?
					this.document.width() :
					this.window.width() - this.helperProportions.width - this.margins.left,
				( o.containment === "document" ?
					( this.document.height() || document.body.parentNode.scrollHeight ) :
					this.window.height() || this.document[ 0 ].body.parentNode.scrollHeight
				) - this.helperProportions.height - this.margins.top
			];
		}

		if ( !( /^(document|window|parent)$/ ).test( o.containment ) ) {
			ce = $( o.containment )[ 0 ];
			co = $( o.containment ).offset();
			over = ( $( ce ).css( "overflow" ) !== "hidden" );

			this.containment = [
				co.left + ( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) +
					( parseInt( $( ce ).css( "paddingLeft" ), 10 ) || 0 ) - this.margins.left,
				co.top + ( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) +
					( parseInt( $( ce ).css( "paddingTop" ), 10 ) || 0 ) - this.margins.top,
				co.left + ( over ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) -
					( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) -
					( parseInt( $( ce ).css( "paddingRight" ), 10 ) || 0 ) -
					this.helperProportions.width - this.margins.left,
				co.top + ( over ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) -
					( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) -
					( parseInt( $( ce ).css( "paddingBottom" ), 10 ) || 0 ) -
					this.helperProportions.height - this.margins.top
			];
		}

	},

	_convertPositionTo: function( d, pos ) {

		if ( !pos ) {
			pos = this.position;
		}
		var mod = d === "absolute" ? 1 : -1,
			scroll = this.cssPosition === "absolute" &&
				!( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
				$.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ?
					this.offsetParent :
					this.scrollParent,
			scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName );

		return {
			top: (

				// The absolute mouse position
				pos.top	+

				// Only for relative positioned nodes: Relative offset from element to offset parent
				this.offset.relative.top * mod +

				// The offsetParent's offset without borders (offset + border)
				this.offset.parent.top * mod -
				( ( this.cssPosition === "fixed" ?
					-this.scrollParent.scrollTop() :
					( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod )
			),
			left: (

				// The absolute mouse position
				pos.left +

				// Only for relative positioned nodes: Relative offset from element to offset parent
				this.offset.relative.left * mod +

				// The offsetParent's offset without borders (offset + border)
				this.offset.parent.left * mod	-
				( ( this.cssPosition === "fixed" ?
					-this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 :
					scroll.scrollLeft() ) * mod )
			)
		};

	},

	_generatePosition: function( event ) {

		var top, left,
			o = this.options,
			pageX = event.pageX,
			pageY = event.pageY,
			scroll = this.cssPosition === "absolute" &&
				!( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
				$.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ?
					this.offsetParent :
					this.scrollParent,
				scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName );

		// This is another very weird special case that only happens for relative elements:
		// 1. If the css position is relative
		// 2. and the scroll parent is the document or similar to the offset parent
		// we have to refresh the relative offset during the scroll so there are no jumps
		if ( this.cssPosition === "relative" && !( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
				this.scrollParent[ 0 ] !== this.offsetParent[ 0 ] ) ) {
			this.offset.relative = this._getRelativeOffset();
		}

		/*
		 * - Position constraining -
		 * Constrain the position to a mix of grid, containment.
		 */

		if ( this.originalPosition ) { //If we are not dragging yet, we won't check for options

			if ( this.containment ) {
				if ( event.pageX - this.offset.click.left < this.containment[ 0 ] ) {
					pageX = this.containment[ 0 ] + this.offset.click.left;
				}
				if ( event.pageY - this.offset.click.top < this.containment[ 1 ] ) {
					pageY = this.containment[ 1 ] + this.offset.click.top;
				}
				if ( event.pageX - this.offset.click.left > this.containment[ 2 ] ) {
					pageX = this.containment[ 2 ] + this.offset.click.left;
				}
				if ( event.pageY - this.offset.click.top > this.containment[ 3 ] ) {
					pageY = this.containment[ 3 ] + this.offset.click.top;
				}
			}

			if ( o.grid ) {
				top = this.originalPageY + Math.round( ( pageY - this.originalPageY ) /
					o.grid[ 1 ] ) * o.grid[ 1 ];
				pageY = this.containment ?
					( ( top - this.offset.click.top >= this.containment[ 1 ] &&
						top - this.offset.click.top <= this.containment[ 3 ] ) ?
							top :
							( ( top - this.offset.click.top >= this.containment[ 1 ] ) ?
								top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) :
								top;

				left = this.originalPageX + Math.round( ( pageX - this.originalPageX ) /
					o.grid[ 0 ] ) * o.grid[ 0 ];
				pageX = this.containment ?
					( ( left - this.offset.click.left >= this.containment[ 0 ] &&
						left - this.offset.click.left <= this.containment[ 2 ] ) ?
							left :
							( ( left - this.offset.click.left >= this.containment[ 0 ] ) ?
								left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) :
								left;
			}

		}

		return {
			top: (

				// The absolute mouse position
				pageY -

				// Click offset (relative to the element)
				this.offset.click.top -

				// Only for relative positioned nodes: Relative offset from element to offset parent
				this.offset.relative.top -

				// The offsetParent's offset without borders (offset + border)
				this.offset.parent.top +
				( ( this.cssPosition === "fixed" ?
					-this.scrollParent.scrollTop() :
					( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) )
			),
			left: (

				// The absolute mouse position
				pageX -

				// Click offset (relative to the element)
				this.offset.click.left -

				// Only for relative positioned nodes: Relative offset from element to offset parent
				this.offset.relative.left -

				// The offsetParent's offset without borders (offset + border)
				this.offset.parent.left +
				( ( this.cssPosition === "fixed" ?
					-this.scrollParent.scrollLeft() :
					scrollIsRootNode ? 0 : scroll.scrollLeft() ) )
			)
		};

	},

	_rearrange: function( event, i, a, hardRefresh ) {

		if ( a ) {
			a[ 0 ].appendChild( this.placeholder[ 0 ] );
		} else {
			i.item[ 0 ].parentNode.insertBefore( this.placeholder[ 0 ],
				( this.direction === "down" ? i.item[ 0 ] : i.item[ 0 ].nextSibling ) );
		}

		//Various things done here to improve the performance:
		// 1. we create a setTimeout, that calls refreshPositions
		// 2. on the instance, we have a counter variable, that get's higher after every append
		// 3. on the local scope, we copy the counter variable, and check in the timeout,
		// if it's still the same
		// 4. this lets only the last addition to the timeout stack through
		this.counter = this.counter ? ++this.counter : 1;
		var counter = this.counter;

		this._delay( function() {
			if ( counter === this.counter ) {

				//Precompute after each DOM insertion, NOT on mousemove
				this.refreshPositions( !hardRefresh );
			}
		} );

	},

	_clear: function( event, noPropagation ) {

		this.reverting = false;

		// We delay all events that have to be triggered to after the point where the placeholder
		// has been removed and everything else normalized again
		var i,
			delayedTriggers = [];

		// We first have to update the dom position of the actual currentItem
		// Note: don't do it if the current item is already removed (by a user), or it gets
		// reappended (see #4088)
		if ( !this._noFinalSort && this.currentItem.parent().length ) {
			this.placeholder.before( this.currentItem );
		}
		this._noFinalSort = null;

		if ( this.helper[ 0 ] === this.currentItem[ 0 ] ) {
			for ( i in this._storedCSS ) {
				if ( this._storedCSS[ i ] === "auto" || this._storedCSS[ i ] === "static" ) {
					this._storedCSS[ i ] = "";
				}
			}
			this.currentItem.css( this._storedCSS );
			this._removeClass( this.currentItem, "ui-sortable-helper" );
		} else {
			this.currentItem.show();
		}

		if ( this.fromOutside && !noPropagation ) {
			delayedTriggers.push( function( event ) {
				this._trigger( "receive", event, this._uiHash( this.fromOutside ) );
			} );
		}
		if ( ( this.fromOutside ||
				this.domPosition.prev !==
				this.currentItem.prev().not( ".ui-sortable-helper" )[ 0 ] ||
				this.domPosition.parent !== this.currentItem.parent()[ 0 ] ) && !noPropagation ) {

			// Trigger update callback if the DOM position has changed
			delayedTriggers.push( function( event ) {
				this._trigger( "update", event, this._uiHash() );
			} );
		}

		// Check if the items Container has Changed and trigger appropriate
		// events.
		if ( this !== this.currentContainer ) {
			if ( !noPropagation ) {
				delayedTriggers.push( function( event ) {
					this._trigger( "remove", event, this._uiHash() );
				} );
				delayedTriggers.push( ( function( c ) {
					return function( event ) {
						c._trigger( "receive", event, this._uiHash( this ) );
					};
				} ).call( this, this.currentContainer ) );
				delayedTriggers.push( ( function( c ) {
					return function( event ) {
						c._trigger( "update", event, this._uiHash( this ) );
					};
				} ).call( this, this.currentContainer ) );
			}
		}

		//Post events to containers
		function delayEvent( type, instance, container ) {
			return function( event ) {
				container._trigger( type, event, instance._uiHash( instance ) );
			};
		}
		for ( i = this.containers.length - 1; i >= 0; i-- ) {
			if ( !noPropagation ) {
				delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) );
			}
			if ( this.containers[ i ].containerCache.over ) {
				delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) );
				this.containers[ i ].containerCache.over = 0;
			}
		}

		//Do what was originally in plugins
		if ( this.storedCursor ) {
			this.document.find( "body" ).css( "cursor", this.storedCursor );
			this.storedStylesheet.remove();
		}
		if ( this._storedOpacity ) {
			this.helper.css( "opacity", this._storedOpacity );
		}
		if ( this._storedZIndex ) {
			this.helper.css( "zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex );
		}

		this.dragging = false;

		if ( !noPropagation ) {
			this._trigger( "beforeStop", event, this._uiHash() );
		}

		//$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately,
		// it unbinds ALL events from the original node!
		this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] );

		if ( !this.cancelHelperRemoval ) {
			if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
				this.helper.remove();
			}
			this.helper = null;
		}

		if ( !noPropagation ) {
			for ( i = 0; i < delayedTriggers.length; i++ ) {

				// Trigger all delayed events
				delayedTriggers[ i ].call( this, event );
			}
			this._trigger( "stop", event, this._uiHash() );
		}

		this.fromOutside = false;
		return !this.cancelHelperRemoval;

	},

	_trigger: function() {
		if ( $.Widget.prototype._trigger.apply( this, arguments ) === false ) {
			this.cancel();
		}
	},

	_uiHash: function( _inst ) {
		var inst = _inst || this;
		return {
			helper: inst.helper,
			placeholder: inst.placeholder || $( [] ),
			position: inst.position,
			originalPosition: inst.originalPosition,
			offset: inst.positionAbs,
			item: inst.currentItem,
			sender: _inst ? _inst.element : null
		};
	}

} );


/*!
 * jQuery UI Spinner 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Spinner
//>>group: Widgets
//>>description: Displays buttons to easily input numbers via the keyboard or mouse.
//>>docs: http://api.jqueryui.com/spinner/
//>>demos: http://jqueryui.com/spinner/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/spinner.css
//>>css.theme: ../../themes/base/theme.css


function spinnerModifier( fn ) {
	return function() {
		var previous = this.element.val();
		fn.apply( this, arguments );
		this._refresh();
		if ( previous !== this.element.val() ) {
			this._trigger( "change" );
		}
	};
}

$.widget( "ui.spinner", {
	version: "1.13.2",
	defaultElement: "<input>",
	widgetEventPrefix: "spin",
	options: {
		classes: {
			"ui-spinner": "ui-corner-all",
			"ui-spinner-down": "ui-corner-br",
			"ui-spinner-up": "ui-corner-tr"
		},
		culture: null,
		icons: {
			down: "ui-icon-triangle-1-s",
			up: "ui-icon-triangle-1-n"
		},
		incremental: true,
		max: null,
		min: null,
		numberFormat: null,
		page: 10,
		step: 1,

		change: null,
		spin: null,
		start: null,
		stop: null
	},

	_create: function() {

		// handle string values that need to be parsed
		this._setOption( "max", this.options.max );
		this._setOption( "min", this.options.min );
		this._setOption( "step", this.options.step );

		// Only format if there is a value, prevents the field from being marked
		// as invalid in Firefox, see #9573.
		if ( this.value() !== "" ) {

			// Format the value, but don't constrain.
			this._value( this.element.val(), true );
		}

		this._draw();
		this._on( this._events );
		this._refresh();

		// Turning off autocomplete prevents the browser from remembering the
		// value when navigating through history, so we re-enable autocomplete
		// if the page is unloaded before the widget is destroyed. #7790
		this._on( this.window, {
			beforeunload: function() {
				this.element.removeAttr( "autocomplete" );
			}
		} );
	},

	_getCreateOptions: function() {
		var options = this._super();
		var element = this.element;

		$.each( [ "min", "max", "step" ], function( i, option ) {
			var value = element.attr( option );
			if ( value != null && value.length ) {
				options[ option ] = value;
			}
		} );

		return options;
	},

	_events: {
		keydown: function( event ) {
			if ( this._start( event ) && this._keydown( event ) ) {
				event.preventDefault();
			}
		},
		keyup: "_stop",
		focus: function() {
			this.previous = this.element.val();
		},
		blur: function( event ) {
			if ( this.cancelBlur ) {
				delete this.cancelBlur;
				return;
			}

			this._stop();
			this._refresh();
			if ( this.previous !== this.element.val() ) {
				this._trigger( "change", event );
			}
		},
		mousewheel: function( event, delta ) {
			var activeElement = $.ui.safeActiveElement( this.document[ 0 ] );
			var isActive = this.element[ 0 ] === activeElement;

			if ( !isActive || !delta ) {
				return;
			}

			if ( !this.spinning && !this._start( event ) ) {
				return false;
			}

			this._spin( ( delta > 0 ? 1 : -1 ) * this.options.step, event );
			clearTimeout( this.mousewheelTimer );
			this.mousewheelTimer = this._delay( function() {
				if ( this.spinning ) {
					this._stop( event );
				}
			}, 100 );
			event.preventDefault();
		},
		"mousedown .ui-spinner-button": function( event ) {
			var previous;

			// We never want the buttons to have focus; whenever the user is
			// interacting with the spinner, the focus should be on the input.
			// If the input is focused then this.previous is properly set from
			// when the input first received focus. If the input is not focused
			// then we need to set this.previous based on the value before spinning.
			previous = this.element[ 0 ] === $.ui.safeActiveElement( this.document[ 0 ] ) ?
				this.previous : this.element.val();
			function checkFocus() {
				var isActive = this.element[ 0 ] === $.ui.safeActiveElement( this.document[ 0 ] );
				if ( !isActive ) {
					this.element.trigger( "focus" );
					this.previous = previous;

					// support: IE
					// IE sets focus asynchronously, so we need to check if focus
					// moved off of the input because the user clicked on the button.
					this._delay( function() {
						this.previous = previous;
					} );
				}
			}

			// Ensure focus is on (or stays on) the text field
			event.preventDefault();
			checkFocus.call( this );

			// Support: IE
			// IE doesn't prevent moving focus even with event.preventDefault()
			// so we set a flag to know when we should ignore the blur event
			// and check (again) if focus moved off of the input.
			this.cancelBlur = true;
			this._delay( function() {
				delete this.cancelBlur;
				checkFocus.call( this );
			} );

			if ( this._start( event ) === false ) {
				return;
			}

			this._repeat( null, $( event.currentTarget )
				.hasClass( "ui-spinner-up" ) ? 1 : -1, event );
		},
		"mouseup .ui-spinner-button": "_stop",
		"mouseenter .ui-spinner-button": function( event ) {

			// button will add ui-state-active if mouse was down while mouseleave and kept down
			if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) {
				return;
			}

			if ( this._start( event ) === false ) {
				return false;
			}
			this._repeat( null, $( event.currentTarget )
				.hasClass( "ui-spinner-up" ) ? 1 : -1, event );
		},

		// TODO: do we really want to consider this a stop?
		// shouldn't we just stop the repeater and wait until mouseup before
		// we trigger the stop event?
		"mouseleave .ui-spinner-button": "_stop"
	},

	// Support mobile enhanced option and make backcompat more sane
	_enhance: function() {
		this.uiSpinner = this.element
			.attr( "autocomplete", "off" )
			.wrap( "<span>" )
			.parent()

				// Add buttons
				.append(
					"<a></a><a></a>"
				);
	},

	_draw: function() {
		this._enhance();

		this._addClass( this.uiSpinner, "ui-spinner", "ui-widget ui-widget-content" );
		this._addClass( "ui-spinner-input" );

		this.element.attr( "role", "spinbutton" );

		// Button bindings
		this.buttons = this.uiSpinner.children( "a" )
			.attr( "tabIndex", -1 )
			.attr( "aria-hidden", true )
			.button( {
				classes: {
					"ui-button": ""
				}
			} );

		// TODO: Right now button does not support classes this is already updated in button PR
		this._removeClass( this.buttons, "ui-corner-all" );

		this._addClass( this.buttons.first(), "ui-spinner-button ui-spinner-up" );
		this._addClass( this.buttons.last(), "ui-spinner-button ui-spinner-down" );
		this.buttons.first().button( {
			"icon": this.options.icons.up,
			"showLabel": false
		} );
		this.buttons.last().button( {
			"icon": this.options.icons.down,
			"showLabel": false
		} );

		// IE 6 doesn't understand height: 50% for the buttons
		// unless the wrapper has an explicit height
		if ( this.buttons.height() > Math.ceil( this.uiSpinner.height() * 0.5 ) &&
				this.uiSpinner.height() > 0 ) {
			this.uiSpinner.height( this.uiSpinner.height() );
		}
	},

	_keydown: function( event ) {
		var options = this.options,
			keyCode = $.ui.keyCode;

		switch ( event.keyCode ) {
		case keyCode.UP:
			this._repeat( null, 1, event );
			return true;
		case keyCode.DOWN:
			this._repeat( null, -1, event );
			return true;
		case keyCode.PAGE_UP:
			this._repeat( null, options.page, event );
			return true;
		case keyCode.PAGE_DOWN:
			this._repeat( null, -options.page, event );
			return true;
		}

		return false;
	},

	_start: function( event ) {
		if ( !this.spinning && this._trigger( "start", event ) === false ) {
			return false;
		}

		if ( !this.counter ) {
			this.counter = 1;
		}
		this.spinning = true;
		return true;
	},

	_repeat: function( i, steps, event ) {
		i = i || 500;

		clearTimeout( this.timer );
		this.timer = this._delay( function() {
			this._repeat( 40, steps, event );
		}, i );

		this._spin( steps * this.options.step, event );
	},

	_spin: function( step, event ) {
		var value = this.value() || 0;

		if ( !this.counter ) {
			this.counter = 1;
		}

		value = this._adjustValue( value + step * this._increment( this.counter ) );

		if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false ) {
			this._value( value );
			this.counter++;
		}
	},

	_increment: function( i ) {
		var incremental = this.options.incremental;

		if ( incremental ) {
			return typeof incremental === "function" ?
				incremental( i ) :
				Math.floor( i * i * i / 50000 - i * i / 500 + 17 * i / 200 + 1 );
		}

		return 1;
	},

	_precision: function() {
		var precision = this._precisionOf( this.options.step );
		if ( this.options.min !== null ) {
			precision = Math.max( precision, this._precisionOf( this.options.min ) );
		}
		return precision;
	},

	_precisionOf: function( num ) {
		var str = num.toString(),
			decimal = str.indexOf( "." );
		return decimal === -1 ? 0 : str.length - decimal - 1;
	},

	_adjustValue: function( value ) {
		var base, aboveMin,
			options = this.options;

		// Make sure we're at a valid step
		// - find out where we are relative to the base (min or 0)
		base = options.min !== null ? options.min : 0;
		aboveMin = value - base;

		// - round to the nearest step
		aboveMin = Math.round( aboveMin / options.step ) * options.step;

		// - rounding is based on 0, so adjust back to our base
		value = base + aboveMin;

		// Fix precision from bad JS floating point math
		value = parseFloat( value.toFixed( this._precision() ) );

		// Clamp the value
		if ( options.max !== null && value > options.max ) {
			return options.max;
		}
		if ( options.min !== null && value < options.min ) {
			return options.min;
		}

		return value;
	},

	_stop: function( event ) {
		if ( !this.spinning ) {
			return;
		}

		clearTimeout( this.timer );
		clearTimeout( this.mousewheelTimer );
		this.counter = 0;
		this.spinning = false;
		this._trigger( "stop", event );
	},

	_setOption: function( key, value ) {
		var prevValue, first, last;

		if ( key === "culture" || key === "numberFormat" ) {
			prevValue = this._parse( this.element.val() );
			this.options[ key ] = value;
			this.element.val( this._format( prevValue ) );
			return;
		}

		if ( key === "max" || key === "min" || key === "step" ) {
			if ( typeof value === "string" ) {
				value = this._parse( value );
			}
		}
		if ( key === "icons" ) {
			first = this.buttons.first().find( ".ui-icon" );
			this._removeClass( first, null, this.options.icons.up );
			this._addClass( first, null, value.up );
			last = this.buttons.last().find( ".ui-icon" );
			this._removeClass( last, null, this.options.icons.down );
			this._addClass( last, null, value.down );
		}

		this._super( key, value );
	},

	_setOptionDisabled: function( value ) {
		this._super( value );

		this._toggleClass( this.uiSpinner, null, "ui-state-disabled", !!value );
		this.element.prop( "disabled", !!value );
		this.buttons.button( value ? "disable" : "enable" );
	},

	_setOptions: spinnerModifier( function( options ) {
		this._super( options );
	} ),

	_parse: function( val ) {
		if ( typeof val === "string" && val !== "" ) {
			val = window.Globalize && this.options.numberFormat ?
				Globalize.parseFloat( val, 10, this.options.culture ) : +val;
		}
		return val === "" || isNaN( val ) ? null : val;
	},

	_format: function( value ) {
		if ( value === "" ) {
			return "";
		}
		return window.Globalize && this.options.numberFormat ?
			Globalize.format( value, this.options.numberFormat, this.options.culture ) :
			value;
	},

	_refresh: function() {
		this.element.attr( {
			"aria-valuemin": this.options.min,
			"aria-valuemax": this.options.max,

			// TODO: what should we do with values that can't be parsed?
			"aria-valuenow": this._parse( this.element.val() )
		} );
	},

	isValid: function() {
		var value = this.value();

		// Null is invalid
		if ( value === null ) {
			return false;
		}

		// If value gets adjusted, it's invalid
		return value === this._adjustValue( value );
	},

	// Update the value without triggering change
	_value: function( value, allowAny ) {
		var parsed;
		if ( value !== "" ) {
			parsed = this._parse( value );
			if ( parsed !== null ) {
				if ( !allowAny ) {
					parsed = this._adjustValue( parsed );
				}
				value = this._format( parsed );
			}
		}
		this.element.val( value );
		this._refresh();
	},

	_destroy: function() {
		this.element
			.prop( "disabled", false )
			.removeAttr( "autocomplete role aria-valuemin aria-valuemax aria-valuenow" );

		this.uiSpinner.replaceWith( this.element );
	},

	stepUp: spinnerModifier( function( steps ) {
		this._stepUp( steps );
	} ),
	_stepUp: function( steps ) {
		if ( this._start() ) {
			this._spin( ( steps || 1 ) * this.options.step );
			this._stop();
		}
	},

	stepDown: spinnerModifier( function( steps ) {
		this._stepDown( steps );
	} ),
	_stepDown: function( steps ) {
		if ( this._start() ) {
			this._spin( ( steps || 1 ) * -this.options.step );
			this._stop();
		}
	},

	pageUp: spinnerModifier( function( pages ) {
		this._stepUp( ( pages || 1 ) * this.options.page );
	} ),

	pageDown: spinnerModifier( function( pages ) {
		this._stepDown( ( pages || 1 ) * this.options.page );
	} ),

	value: function( newVal ) {
		if ( !arguments.length ) {
			return this._parse( this.element.val() );
		}
		spinnerModifier( this._value ).call( this, newVal );
	},

	widget: function() {
		return this.uiSpinner;
	}
} );

// DEPRECATED
// TODO: switch return back to widget declaration at top of file when this is removed
if ( $.uiBackCompat !== false ) {

	// Backcompat for spinner html extension points
	$.widget( "ui.spinner", $.ui.spinner, {
		_enhance: function() {
			this.uiSpinner = this.element
				.attr( "autocomplete", "off" )
				.wrap( this._uiSpinnerHtml() )
				.parent()

					// Add buttons
					.append( this._buttonHtml() );
		},
		_uiSpinnerHtml: function() {
			return "<span>";
		},

		_buttonHtml: function() {
			return "<a></a><a></a>";
		}
	} );
}

var widgetsSpinner = $.ui.spinner;


/*!
 * jQuery UI Tabs 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Tabs
//>>group: Widgets
//>>description: Transforms a set of container elements into a tab structure.
//>>docs: http://api.jqueryui.com/tabs/
//>>demos: http://jqueryui.com/tabs/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/tabs.css
//>>css.theme: ../../themes/base/theme.css


$.widget( "ui.tabs", {
	version: "1.13.2",
	delay: 300,
	options: {
		active: null,
		classes: {
			"ui-tabs": "ui-corner-all",
			"ui-tabs-nav": "ui-corner-all",
			"ui-tabs-panel": "ui-corner-bottom",
			"ui-tabs-tab": "ui-corner-top"
		},
		collapsible: false,
		event: "click",
		heightStyle: "content",
		hide: null,
		show: null,

		// Callbacks
		activate: null,
		beforeActivate: null,
		beforeLoad: null,
		load: null
	},

	_isLocal: ( function() {
		var rhash = /#.*$/;

		return function( anchor ) {
			var anchorUrl, locationUrl;

			anchorUrl = anchor.href.replace( rhash, "" );
			locationUrl = location.href.replace( rhash, "" );

			// Decoding may throw an error if the URL isn't UTF-8 (#9518)
			try {
				anchorUrl = decodeURIComponent( anchorUrl );
			} catch ( error ) {}
			try {
				locationUrl = decodeURIComponent( locationUrl );
			} catch ( error ) {}

			return anchor.hash.length > 1 && anchorUrl === locationUrl;
		};
	} )(),

	_create: function() {
		var that = this,
			options = this.options;

		this.running = false;

		this._addClass( "ui-tabs", "ui-widget ui-widget-content" );
		this._toggleClass( "ui-tabs-collapsible", null, options.collapsible );

		this._processTabs();
		options.active = this._initialActive();

		// Take disabling tabs via class attribute from HTML
		// into account and update option properly.
		if ( Array.isArray( options.disabled ) ) {
			options.disabled = $.uniqueSort( options.disabled.concat(
				$.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) {
					return that.tabs.index( li );
				} )
			) ).sort();
		}

		// Check for length avoids error when initializing empty list
		if ( this.options.active !== false && this.anchors.length ) {
			this.active = this._findActive( options.active );
		} else {
			this.active = $();
		}

		this._refresh();

		if ( this.active.length ) {
			this.load( options.active );
		}
	},

	_initialActive: function() {
		var active = this.options.active,
			collapsible = this.options.collapsible,
			locationHash = location.hash.substring( 1 );

		if ( active === null ) {

			// check the fragment identifier in the URL
			if ( locationHash ) {
				this.tabs.each( function( i, tab ) {
					if ( $( tab ).attr( "aria-controls" ) === locationHash ) {
						active = i;
						return false;
					}
				} );
			}

			// Check for a tab marked active via a class
			if ( active === null ) {
				active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) );
			}

			// No active tab, set to false
			if ( active === null || active === -1 ) {
				active = this.tabs.length ? 0 : false;
			}
		}

		// Handle numbers: negative, out of range
		if ( active !== false ) {
			active = this.tabs.index( this.tabs.eq( active ) );
			if ( active === -1 ) {
				active = collapsible ? false : 0;
			}
		}

		// Don't allow collapsible: false and active: false
		if ( !collapsible && active === false && this.anchors.length ) {
			active = 0;
		}

		return active;
	},

	_getCreateEventData: function() {
		return {
			tab: this.active,
			panel: !this.active.length ? $() : this._getPanelForTab( this.active )
		};
	},

	_tabKeydown: function( event ) {
		var focusedTab = $( $.ui.safeActiveElement( this.document[ 0 ] ) ).closest( "li" ),
			selectedIndex = this.tabs.index( focusedTab ),
			goingForward = true;

		if ( this._handlePageNav( event ) ) {
			return;
		}

		switch ( event.keyCode ) {
		case $.ui.keyCode.RIGHT:
		case $.ui.keyCode.DOWN:
			selectedIndex++;
			break;
		case $.ui.keyCode.UP:
		case $.ui.keyCode.LEFT:
			goingForward = false;
			selectedIndex--;
			break;
		case $.ui.keyCode.END:
			selectedIndex = this.anchors.length - 1;
			break;
		case $.ui.keyCode.HOME:
			selectedIndex = 0;
			break;
		case $.ui.keyCode.SPACE:

			// Activate only, no collapsing
			event.preventDefault();
			clearTimeout( this.activating );
			this._activate( selectedIndex );
			return;
		case $.ui.keyCode.ENTER:

			// Toggle (cancel delayed activation, allow collapsing)
			event.preventDefault();
			clearTimeout( this.activating );

			// Determine if we should collapse or activate
			this._activate( selectedIndex === this.options.active ? false : selectedIndex );
			return;
		default:
			return;
		}

		// Focus the appropriate tab, based on which key was pressed
		event.preventDefault();
		clearTimeout( this.activating );
		selectedIndex = this._focusNextTab( selectedIndex, goingForward );

		// Navigating with control/command key will prevent automatic activation
		if ( !event.ctrlKey && !event.metaKey ) {

			// Update aria-selected immediately so that AT think the tab is already selected.
			// Otherwise AT may confuse the user by stating that they need to activate the tab,
			// but the tab will already be activated by the time the announcement finishes.
			focusedTab.attr( "aria-selected", "false" );
			this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" );

			this.activating = this._delay( function() {
				this.option( "active", selectedIndex );
			}, this.delay );
		}
	},

	_panelKeydown: function( event ) {
		if ( this._handlePageNav( event ) ) {
			return;
		}

		// Ctrl+up moves focus to the current tab
		if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) {
			event.preventDefault();
			this.active.trigger( "focus" );
		}
	},

	// Alt+page up/down moves focus to the previous/next tab (and activates)
	_handlePageNav: function( event ) {
		if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) {
			this._activate( this._focusNextTab( this.options.active - 1, false ) );
			return true;
		}
		if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) {
			this._activate( this._focusNextTab( this.options.active + 1, true ) );
			return true;
		}
	},

	_findNextTab: function( index, goingForward ) {
		var lastTabIndex = this.tabs.length - 1;

		function constrain() {
			if ( index > lastTabIndex ) {
				index = 0;
			}
			if ( index < 0 ) {
				index = lastTabIndex;
			}
			return index;
		}

		while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) {
			index = goingForward ? index + 1 : index - 1;
		}

		return index;
	},

	_focusNextTab: function( index, goingForward ) {
		index = this._findNextTab( index, goingForward );
		this.tabs.eq( index ).trigger( "focus" );
		return index;
	},

	_setOption: function( key, value ) {
		if ( key === "active" ) {

			// _activate() will handle invalid values and update this.options
			this._activate( value );
			return;
		}

		this._super( key, value );

		if ( key === "collapsible" ) {
			this._toggleClass( "ui-tabs-collapsible", null, value );

			// Setting collapsible: false while collapsed; open first panel
			if ( !value && this.options.active === false ) {
				this._activate( 0 );
			}
		}

		if ( key === "event" ) {
			this._setupEvents( value );
		}

		if ( key === "heightStyle" ) {
			this._setupHeightStyle( value );
		}
	},

	_sanitizeSelector: function( hash ) {
		return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : "";
	},

	refresh: function() {
		var options = this.options,
			lis = this.tablist.children( ":has(a[href])" );

		// Get disabled tabs from class attribute from HTML
		// this will get converted to a boolean if needed in _refresh()
		options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) {
			return lis.index( tab );
		} );

		this._processTabs();

		// Was collapsed or no tabs
		if ( options.active === false || !this.anchors.length ) {
			options.active = false;
			this.active = $();

		// was active, but active tab is gone
		} else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) {

			// all remaining tabs are disabled
			if ( this.tabs.length === options.disabled.length ) {
				options.active = false;
				this.active = $();

			// activate previous tab
			} else {
				this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) );
			}

		// was active, active tab still exists
		} else {

			// make sure active index is correct
			options.active = this.tabs.index( this.active );
		}

		this._refresh();
	},

	_refresh: function() {
		this._setOptionDisabled( this.options.disabled );
		this._setupEvents( this.options.event );
		this._setupHeightStyle( this.options.heightStyle );

		this.tabs.not( this.active ).attr( {
			"aria-selected": "false",
			"aria-expanded": "false",
			tabIndex: -1
		} );
		this.panels.not( this._getPanelForTab( this.active ) )
			.hide()
			.attr( {
				"aria-hidden": "true"
			} );

		// Make sure one tab is in the tab order
		if ( !this.active.length ) {
			this.tabs.eq( 0 ).attr( "tabIndex", 0 );
		} else {
			this.active
				.attr( {
					"aria-selected": "true",
					"aria-expanded": "true",
					tabIndex: 0
				} );
			this._addClass( this.active, "ui-tabs-active", "ui-state-active" );
			this._getPanelForTab( this.active )
				.show()
				.attr( {
					"aria-hidden": "false"
				} );
		}
	},

	_processTabs: function() {
		var that = this,
			prevTabs = this.tabs,
			prevAnchors = this.anchors,
			prevPanels = this.panels;

		this.tablist = this._getList().attr( "role", "tablist" );
		this._addClass( this.tablist, "ui-tabs-nav",
			"ui-helper-reset ui-helper-clearfix ui-widget-header" );

		// Prevent users from focusing disabled tabs via click
		this.tablist
			.on( "mousedown" + this.eventNamespace, "> li", function( event ) {
				if ( $( this ).is( ".ui-state-disabled" ) ) {
					event.preventDefault();
				}
			} )

			// Support: IE <9
			// Preventing the default action in mousedown doesn't prevent IE
			// from focusing the element, so if the anchor gets focused, blur.
			// We don't have to worry about focusing the previously focused
			// element since clicking on a non-focusable element should focus
			// the body anyway.
			.on( "focus" + this.eventNamespace, ".ui-tabs-anchor", function() {
				if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) {
					this.blur();
				}
			} );

		this.tabs = this.tablist.find( "> li:has(a[href])" )
			.attr( {
				role: "tab",
				tabIndex: -1
			} );
		this._addClass( this.tabs, "ui-tabs-tab", "ui-state-default" );

		this.anchors = this.tabs.map( function() {
			return $( "a", this )[ 0 ];
		} )
			.attr( {
				tabIndex: -1
			} );
		this._addClass( this.anchors, "ui-tabs-anchor" );

		this.panels = $();

		this.anchors.each( function( i, anchor ) {
			var selector, panel, panelId,
				anchorId = $( anchor ).uniqueId().attr( "id" ),
				tab = $( anchor ).closest( "li" ),
				originalAriaControls = tab.attr( "aria-controls" );

			// Inline tab
			if ( that._isLocal( anchor ) ) {
				selector = anchor.hash;
				panelId = selector.substring( 1 );
				panel = that.element.find( that._sanitizeSelector( selector ) );

			// remote tab
			} else {

				// If the tab doesn't already have aria-controls,
				// generate an id by using a throw-away element
				panelId = tab.attr( "aria-controls" ) || $( {} ).uniqueId()[ 0 ].id;
				selector = "#" + panelId;
				panel = that.element.find( selector );
				if ( !panel.length ) {
					panel = that._createPanel( panelId );
					panel.insertAfter( that.panels[ i - 1 ] || that.tablist );
				}
				panel.attr( "aria-live", "polite" );
			}

			if ( panel.length ) {
				that.panels = that.panels.add( panel );
			}
			if ( originalAriaControls ) {
				tab.data( "ui-tabs-aria-controls", originalAriaControls );
			}
			tab.attr( {
				"aria-controls": panelId,
				"aria-labelledby": anchorId
			} );
			panel.attr( "aria-labelledby", anchorId );
		} );

		this.panels.attr( "role", "tabpanel" );
		this._addClass( this.panels, "ui-tabs-panel", "ui-widget-content" );

		// Avoid memory leaks (#10056)
		if ( prevTabs ) {
			this._off( prevTabs.not( this.tabs ) );
			this._off( prevAnchors.not( this.anchors ) );
			this._off( prevPanels.not( this.panels ) );
		}
	},

	// Allow overriding how to find the list for rare usage scenarios (#7715)
	_getList: function() {
		return this.tablist || this.element.find( "ol, ul" ).eq( 0 );
	},

	_createPanel: function( id ) {
		return $( "<div>" )
			.attr( "id", id )
			.data( "ui-tabs-destroy", true );
	},

	_setOptionDisabled: function( disabled ) {
		var currentItem, li, i;

		if ( Array.isArray( disabled ) ) {
			if ( !disabled.length ) {
				disabled = false;
			} else if ( disabled.length === this.anchors.length ) {
				disabled = true;
			}
		}

		// Disable tabs
		for ( i = 0; ( li = this.tabs[ i ] ); i++ ) {
			currentItem = $( li );
			if ( disabled === true || $.inArray( i, disabled ) !== -1 ) {
				currentItem.attr( "aria-disabled", "true" );
				this._addClass( currentItem, null, "ui-state-disabled" );
			} else {
				currentItem.removeAttr( "aria-disabled" );
				this._removeClass( currentItem, null, "ui-state-disabled" );
			}
		}

		this.options.disabled = disabled;

		this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null,
			disabled === true );
	},

	_setupEvents: function( event ) {
		var events = {};
		if ( event ) {
			$.each( event.split( " " ), function( index, eventName ) {
				events[ eventName ] = "_eventHandler";
			} );
		}

		this._off( this.anchors.add( this.tabs ).add( this.panels ) );

		// Always prevent the default action, even when disabled
		this._on( true, this.anchors, {
			click: function( event ) {
				event.preventDefault();
			}
		} );
		this._on( this.anchors, events );
		this._on( this.tabs, { keydown: "_tabKeydown" } );
		this._on( this.panels, { keydown: "_panelKeydown" } );

		this._focusable( this.tabs );
		this._hoverable( this.tabs );
	},

	_setupHeightStyle: function( heightStyle ) {
		var maxHeight,
			parent = this.element.parent();

		if ( heightStyle === "fill" ) {
			maxHeight = parent.height();
			maxHeight -= this.element.outerHeight() - this.element.height();

			this.element.siblings( ":visible" ).each( function() {
				var elem = $( this ),
					position = elem.css( "position" );

				if ( position === "absolute" || position === "fixed" ) {
					return;
				}
				maxHeight -= elem.outerHeight( true );
			} );

			this.element.children().not( this.panels ).each( function() {
				maxHeight -= $( this ).outerHeight( true );
			} );

			this.panels.each( function() {
				$( this ).height( Math.max( 0, maxHeight -
					$( this ).innerHeight() + $( this ).height() ) );
			} )
				.css( "overflow", "auto" );
		} else if ( heightStyle === "auto" ) {
			maxHeight = 0;
			this.panels.each( function() {
				maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
			} ).height( maxHeight );
		}
	},

	_eventHandler: function( event ) {
		var options = this.options,
			active = this.active,
			anchor = $( event.currentTarget ),
			tab = anchor.closest( "li" ),
			clickedIsActive = tab[ 0 ] === active[ 0 ],
			collapsing = clickedIsActive && options.collapsible,
			toShow = collapsing ? $() : this._getPanelForTab( tab ),
			toHide = !active.length ? $() : this._getPanelForTab( active ),
			eventData = {
				oldTab: active,
				oldPanel: toHide,
				newTab: collapsing ? $() : tab,
				newPanel: toShow
			};

		event.preventDefault();

		if ( tab.hasClass( "ui-state-disabled" ) ||

				// tab is already loading
				tab.hasClass( "ui-tabs-loading" ) ||

				// can't switch durning an animation
				this.running ||

				// click on active header, but not collapsible
				( clickedIsActive && !options.collapsible ) ||

				// allow canceling activation
				( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
			return;
		}

		options.active = collapsing ? false : this.tabs.index( tab );

		this.active = clickedIsActive ? $() : tab;
		if ( this.xhr ) {
			this.xhr.abort();
		}

		if ( !toHide.length && !toShow.length ) {
			$.error( "jQuery UI Tabs: Mismatching fragment identifier." );
		}

		if ( toShow.length ) {
			this.load( this.tabs.index( tab ), event );
		}
		this._toggle( event, eventData );
	},

	// Handles show/hide for selecting tabs
	_toggle: function( event, eventData ) {
		var that = this,
			toShow = eventData.newPanel,
			toHide = eventData.oldPanel;

		this.running = true;

		function complete() {
			that.running = false;
			that._trigger( "activate", event, eventData );
		}

		function show() {
			that._addClass( eventData.newTab.closest( "li" ), "ui-tabs-active", "ui-state-active" );

			if ( toShow.length && that.options.show ) {
				that._show( toShow, that.options.show, complete );
			} else {
				toShow.show();
				complete();
			}
		}

		// Start out by hiding, then showing, then completing
		if ( toHide.length && this.options.hide ) {
			this._hide( toHide, this.options.hide, function() {
				that._removeClass( eventData.oldTab.closest( "li" ),
					"ui-tabs-active", "ui-state-active" );
				show();
			} );
		} else {
			this._removeClass( eventData.oldTab.closest( "li" ),
				"ui-tabs-active", "ui-state-active" );
			toHide.hide();
			show();
		}

		toHide.attr( "aria-hidden", "true" );
		eventData.oldTab.attr( {
			"aria-selected": "false",
			"aria-expanded": "false"
		} );

		// If we're switching tabs, remove the old tab from the tab order.
		// If we're opening from collapsed state, remove the previous tab from the tab order.
		// If we're collapsing, then keep the collapsing tab in the tab order.
		if ( toShow.length && toHide.length ) {
			eventData.oldTab.attr( "tabIndex", -1 );
		} else if ( toShow.length ) {
			this.tabs.filter( function() {
				return $( this ).attr( "tabIndex" ) === 0;
			} )
				.attr( "tabIndex", -1 );
		}

		toShow.attr( "aria-hidden", "false" );
		eventData.newTab.attr( {
			"aria-selected": "true",
			"aria-expanded": "true",
			tabIndex: 0
		} );
	},

	_activate: function( index ) {
		var anchor,
			active = this._findActive( index );

		// Trying to activate the already active panel
		if ( active[ 0 ] === this.active[ 0 ] ) {
			return;
		}

		// Trying to collapse, simulate a click on the current active header
		if ( !active.length ) {
			active = this.active;
		}

		anchor = active.find( ".ui-tabs-anchor" )[ 0 ];
		this._eventHandler( {
			target: anchor,
			currentTarget: anchor,
			preventDefault: $.noop
		} );
	},

	_findActive: function( index ) {
		return index === false ? $() : this.tabs.eq( index );
	},

	_getIndex: function( index ) {

		// meta-function to give users option to provide a href string instead of a numerical index.
		if ( typeof index === "string" ) {
			index = this.anchors.index( this.anchors.filter( "[href$='" +
				$.escapeSelector( index ) + "']" ) );
		}

		return index;
	},

	_destroy: function() {
		if ( this.xhr ) {
			this.xhr.abort();
		}

		this.tablist
			.removeAttr( "role" )
			.off( this.eventNamespace );

		this.anchors
			.removeAttr( "role tabIndex" )
			.removeUniqueId();

		this.tabs.add( this.panels ).each( function() {
			if ( $.data( this, "ui-tabs-destroy" ) ) {
				$( this ).remove();
			} else {
				$( this ).removeAttr( "role tabIndex " +
					"aria-live aria-busy aria-selected aria-labelledby aria-hidden aria-expanded" );
			}
		} );

		this.tabs.each( function() {
			var li = $( this ),
				prev = li.data( "ui-tabs-aria-controls" );
			if ( prev ) {
				li
					.attr( "aria-controls", prev )
					.removeData( "ui-tabs-aria-controls" );
			} else {
				li.removeAttr( "aria-controls" );
			}
		} );

		this.panels.show();

		if ( this.options.heightStyle !== "content" ) {
			this.panels.css( "height", "" );
		}
	},

	enable: function( index ) {
		var disabled = this.options.disabled;
		if ( disabled === false ) {
			return;
		}

		if ( index === undefined ) {
			disabled = false;
		} else {
			index = this._getIndex( index );
			if ( Array.isArray( disabled ) ) {
				disabled = $.map( disabled, function( num ) {
					return num !== index ? num : null;
				} );
			} else {
				disabled = $.map( this.tabs, function( li, num ) {
					return num !== index ? num : null;
				} );
			}
		}
		this._setOptionDisabled( disabled );
	},

	disable: function( index ) {
		var disabled = this.options.disabled;
		if ( disabled === true ) {
			return;
		}

		if ( index === undefined ) {
			disabled = true;
		} else {
			index = this._getIndex( index );
			if ( $.inArray( index, disabled ) !== -1 ) {
				return;
			}
			if ( Array.isArray( disabled ) ) {
				disabled = $.merge( [ index ], disabled ).sort();
			} else {
				disabled = [ index ];
			}
		}
		this._setOptionDisabled( disabled );
	},

	load: function( index, event ) {
		index = this._getIndex( index );
		var that = this,
			tab = this.tabs.eq( index ),
			anchor = tab.find( ".ui-tabs-anchor" ),
			panel = this._getPanelForTab( tab ),
			eventData = {
				tab: tab,
				panel: panel
			},
			complete = function( jqXHR, status ) {
				if ( status === "abort" ) {
					that.panels.stop( false, true );
				}

				that._removeClass( tab, "ui-tabs-loading" );
				panel.removeAttr( "aria-busy" );

				if ( jqXHR === that.xhr ) {
					delete that.xhr;
				}
			};

		// Not remote
		if ( this._isLocal( anchor[ 0 ] ) ) {
			return;
		}

		this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );

		// Support: jQuery <1.8
		// jQuery <1.8 returns false if the request is canceled in beforeSend,
		// but as of 1.8, $.ajax() always returns a jqXHR object.
		if ( this.xhr && this.xhr.statusText !== "canceled" ) {
			this._addClass( tab, "ui-tabs-loading" );
			panel.attr( "aria-busy", "true" );

			this.xhr
				.done( function( response, status, jqXHR ) {

					// support: jQuery <1.8
					// http://bugs.jquery.com/ticket/11778
					setTimeout( function() {
						panel.html( response );
						that._trigger( "load", event, eventData );

						complete( jqXHR, status );
					}, 1 );
				} )
				.fail( function( jqXHR, status ) {

					// support: jQuery <1.8
					// http://bugs.jquery.com/ticket/11778
					setTimeout( function() {
						complete( jqXHR, status );
					}, 1 );
				} );
		}
	},

	_ajaxSettings: function( anchor, event, eventData ) {
		var that = this;
		return {

			// Support: IE <11 only
			// Strip any hash that exists to prevent errors with the Ajax request
			url: anchor.attr( "href" ).replace( /#.*$/, "" ),
			beforeSend: function( jqXHR, settings ) {
				return that._trigger( "beforeLoad", event,
					$.extend( { jqXHR: jqXHR, ajaxSettings: settings }, eventData ) );
			}
		};
	},

	_getPanelForTab: function( tab ) {
		var id = $( tab ).attr( "aria-controls" );
		return this.element.find( this._sanitizeSelector( "#" + id ) );
	}
} );

// DEPRECATED
// TODO: Switch return back to widget declaration at top of file when this is removed
if ( $.uiBackCompat !== false ) {

	// Backcompat for ui-tab class (now ui-tabs-tab)
	$.widget( "ui.tabs", $.ui.tabs, {
		_processTabs: function() {
			this._superApply( arguments );
			this._addClass( this.tabs, "ui-tab" );
		}
	} );
}

var widgetsTabs = $.ui.tabs;


/*!
 * jQuery UI Tooltip 1.13.2
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Tooltip
//>>group: Widgets
//>>description: Shows additional information for any element on hover or focus.
//>>docs: http://api.jqueryui.com/tooltip/
//>>demos: http://jqueryui.com/tooltip/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/tooltip.css
//>>css.theme: ../../themes/base/theme.css


$.widget( "ui.tooltip", {
	version: "1.13.2",
	options: {
		classes: {
			"ui-tooltip": "ui-corner-all ui-widget-shadow"
		},
		content: function() {
			var title = $( this ).attr( "title" );

			// Escape title, since we're going from an attribute to raw HTML
			return $( "<a>" ).text( title ).html();
		},
		hide: true,

		// Disabled elements have inconsistent behavior across browsers (#8661)
		items: "[title]:not([disabled])",
		position: {
			my: "left top+15",
			at: "left bottom",
			collision: "flipfit flip"
		},
		show: true,
		track: false,

		// Callbacks
		close: null,
		open: null
	},

	_addDescribedBy: function( elem, id ) {
		var describedby = ( elem.attr( "aria-describedby" ) || "" ).split( /\s+/ );
		describedby.push( id );
		elem
			.data( "ui-tooltip-id", id )
			.attr( "aria-describedby", String.prototype.trim.call( describedby.join( " " ) ) );
	},

	_removeDescribedBy: function( elem ) {
		var id = elem.data( "ui-tooltip-id" ),
			describedby = ( elem.attr( "aria-describedby" ) || "" ).split( /\s+/ ),
			index = $.inArray( id, describedby );

		if ( index !== -1 ) {
			describedby.splice( index, 1 );
		}

		elem.removeData( "ui-tooltip-id" );
		describedby = String.prototype.trim.call( describedby.join( " " ) );
		if ( describedby ) {
			elem.attr( "aria-describedby", describedby );
		} else {
			elem.removeAttr( "aria-describedby" );
		}
	},

	_create: function() {
		this._on( {
			mouseover: "open",
			focusin: "open"
		} );

		// IDs of generated tooltips, needed for destroy
		this.tooltips = {};

		// IDs of parent tooltips where we removed the title attribute
		this.parents = {};

		// Append the aria-live region so tooltips announce correctly
		this.liveRegion = $( "<div>" )
			.attr( {
				role: "log",
				"aria-live": "assertive",
				"aria-relevant": "additions"
			} )
			.appendTo( this.document[ 0 ].body );
		this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" );

		this.disabledTitles = $( [] );
	},

	_setOption: function( key, value ) {
		var that = this;

		this._super( key, value );

		if ( key === "content" ) {
			$.each( this.tooltips, function( id, tooltipData ) {
				that._updateContent( tooltipData.element );
			} );
		}
	},

	_setOptionDisabled: function( value ) {
		this[ value ? "_disable" : "_enable" ]();
	},

	_disable: function() {
		var that = this;

		// Close open tooltips
		$.each( this.tooltips, function( id, tooltipData ) {
			var event = $.Event( "blur" );
			event.target = event.currentTarget = tooltipData.element[ 0 ];
			that.close( event, true );
		} );

		// Remove title attributes to prevent native tooltips
		this.disabledTitles = this.disabledTitles.add(
			this.element.find( this.options.items ).addBack()
				.filter( function() {
					var element = $( this );
					if ( element.is( "[title]" ) ) {
						return element
							.data( "ui-tooltip-title", element.attr( "title" ) )
							.removeAttr( "title" );
					}
				} )
		);
	},

	_enable: function() {

		// restore title attributes
		this.disabledTitles.each( function() {
			var element = $( this );
			if ( element.data( "ui-tooltip-title" ) ) {
				element.attr( "title", element.data( "ui-tooltip-title" ) );
			}
		} );
		this.disabledTitles = $( [] );
	},

	open: function( event ) {
		var that = this,
			target = $( event ? event.target : this.element )

				// we need closest here due to mouseover bubbling,
				// but always pointing at the same event target
				.closest( this.options.items );

		// No element to show a tooltip for or the tooltip is already open
		if ( !target.length || target.data( "ui-tooltip-id" ) ) {
			return;
		}

		if ( target.attr( "title" ) ) {
			target.data( "ui-tooltip-title", target.attr( "title" ) );
		}

		target.data( "ui-tooltip-open", true );

		// Kill parent tooltips, custom or native, for hover
		if ( event && event.type === "mouseover" ) {
			target.parents().each( function() {
				var parent = $( this ),
					blurEvent;
				if ( parent.data( "ui-tooltip-open" ) ) {
					blurEvent = $.Event( "blur" );
					blurEvent.target = blurEvent.currentTarget = this;
					that.close( blurEvent, true );
				}
				if ( parent.attr( "title" ) ) {
					parent.uniqueId();
					that.parents[ this.id ] = {
						element: this,
						title: parent.attr( "title" )
					};
					parent.attr( "title", "" );
				}
			} );
		}

		this._registerCloseHandlers( event, target );
		this._updateContent( target, event );
	},

	_updateContent: function( target, event ) {
		var content,
			contentOption = this.options.content,
			that = this,
			eventType = event ? event.type : null;

		if ( typeof contentOption === "string" || contentOption.nodeType ||
				contentOption.jquery ) {
			return this._open( event, target, contentOption );
		}

		content = contentOption.call( target[ 0 ], function( response ) {

			// IE may instantly serve a cached response for ajax requests
			// delay this call to _open so the other call to _open runs first
			that._delay( function() {

				// Ignore async response if tooltip was closed already
				if ( !target.data( "ui-tooltip-open" ) ) {
					return;
				}

				// JQuery creates a special event for focusin when it doesn't
				// exist natively. To improve performance, the native event
				// object is reused and the type is changed. Therefore, we can't
				// rely on the type being correct after the event finished
				// bubbling, so we set it back to the previous value. (#8740)
				if ( event ) {
					event.type = eventType;
				}
				this._open( event, target, response );
			} );
		} );
		if ( content ) {
			this._open( event, target, content );
		}
	},

	_open: function( event, target, content ) {
		var tooltipData, tooltip, delayedShow, a11yContent,
			positionOption = $.extend( {}, this.options.position );

		if ( !content ) {
			return;
		}

		// Content can be updated multiple times. If the tooltip already
		// exists, then just update the content and bail.
		tooltipData = this._find( target );
		if ( tooltipData ) {
			tooltipData.tooltip.find( ".ui-tooltip-content" ).html( content );
			return;
		}

		// If we have a title, clear it to prevent the native tooltip
		// we have to check first to avoid defining a title if none exists
		// (we don't want to cause an element to start matching [title])
		//
		// We use removeAttr only for key events, to allow IE to export the correct
		// accessible attributes. For mouse events, set to empty string to avoid
		// native tooltip showing up (happens only when removing inside mouseover).
		if ( target.is( "[title]" ) ) {
			if ( event && event.type === "mouseover" ) {
				target.attr( "title", "" );
			} else {
				target.removeAttr( "title" );
			}
		}

		tooltipData = this._tooltip( target );
		tooltip = tooltipData.tooltip;
		this._addDescribedBy( target, tooltip.attr( "id" ) );
		tooltip.find( ".ui-tooltip-content" ).html( content );

		// Support: Voiceover on OS X, JAWS on IE <= 9
		// JAWS announces deletions even when aria-relevant="additions"
		// Voiceover will sometimes re-read the entire log region's contents from the beginning
		this.liveRegion.children().hide();
		a11yContent = $( "<div>" ).html( tooltip.find( ".ui-tooltip-content" ).html() );
		a11yContent.removeAttr( "name" ).find( "[name]" ).removeAttr( "name" );
		a11yContent.removeAttr( "id" ).find( "[id]" ).removeAttr( "id" );
		a11yContent.appendTo( this.liveRegion );

		function position( event ) {
			positionOption.of = event;
			if ( tooltip.is( ":hidden" ) ) {
				return;
			}
			tooltip.position( positionOption );
		}
		if ( this.options.track && event && /^mouse/.test( event.type ) ) {
			this._on( this.document, {
				mousemove: position
			} );

			// trigger once to override element-relative positioning
			position( event );
		} else {
			tooltip.position( $.extend( {
				of: target
			}, this.options.position ) );
		}

		tooltip.hide();

		this._show( tooltip, this.options.show );

		// Handle tracking tooltips that are shown with a delay (#8644). As soon
		// as the tooltip is visible, position the tooltip using the most recent
		// event.
		// Adds the check to add the timers only when both delay and track options are set (#14682)
		if ( this.options.track && this.options.show && this.options.show.delay ) {
			delayedShow = this.delayedShow = setInterval( function() {
				if ( tooltip.is( ":visible" ) ) {
					position( positionOption.of );
					clearInterval( delayedShow );
				}
			}, 13 );
		}

		this._trigger( "open", event, { tooltip: tooltip } );
	},

	_registerCloseHandlers: function( event, target ) {
		var events = {
			keyup: function( event ) {
				if ( event.keyCode === $.ui.keyCode.ESCAPE ) {
					var fakeEvent = $.Event( event );
					fakeEvent.currentTarget = target[ 0 ];
					this.close( fakeEvent, true );
				}
			}
		};

		// Only bind remove handler for delegated targets. Non-delegated
		// tooltips will handle this in destroy.
		if ( target[ 0 ] !== this.element[ 0 ] ) {
			events.remove = function() {
				var targetElement = this._find( target );
				if ( targetElement ) {
					this._removeTooltip( targetElement.tooltip );
				}
			};
		}

		if ( !event || event.type === "mouseover" ) {
			events.mouseleave = "close";
		}
		if ( !event || event.type === "focusin" ) {
			events.focusout = "close";
		}
		this._on( true, target, events );
	},

	close: function( event ) {
		var tooltip,
			that = this,
			target = $( event ? event.currentTarget : this.element ),
			tooltipData = this._find( target );

		// The tooltip may already be closed
		if ( !tooltipData ) {

			// We set ui-tooltip-open immediately upon open (in open()), but only set the
			// additional data once there's actually content to show (in _open()). So even if the
			// tooltip doesn't have full data, we always remove ui-tooltip-open in case we're in
			// the period between open() and _open().
			target.removeData( "ui-tooltip-open" );
			return;
		}

		tooltip = tooltipData.tooltip;

		// Disabling closes the tooltip, so we need to track when we're closing
		// to avoid an infinite loop in case the tooltip becomes disabled on close
		if ( tooltipData.closing ) {
			return;
		}

		// Clear the interval for delayed tracking tooltips
		clearInterval( this.delayedShow );

		// Only set title if we had one before (see comment in _open())
		// If the title attribute has changed since open(), don't restore
		if ( target.data( "ui-tooltip-title" ) && !target.attr( "title" ) ) {
			target.attr( "title", target.data( "ui-tooltip-title" ) );
		}

		this._removeDescribedBy( target );

		tooltipData.hiding = true;
		tooltip.stop( true );
		this._hide( tooltip, this.options.hide, function() {
			that._removeTooltip( $( this ) );
		} );

		target.removeData( "ui-tooltip-open" );
		this._off( target, "mouseleave focusout keyup" );

		// Remove 'remove' binding only on delegated targets
		if ( target[ 0 ] !== this.element[ 0 ] ) {
			this._off( target, "remove" );
		}
		this._off( this.document, "mousemove" );

		if ( event && event.type === "mouseleave" ) {
			$.each( this.parents, function( id, parent ) {
				$( parent.element ).attr( "title", parent.title );
				delete that.parents[ id ];
			} );
		}

		tooltipData.closing = true;
		this._trigger( "close", event, { tooltip: tooltip } );
		if ( !tooltipData.hiding ) {
			tooltipData.closing = false;
		}
	},

	_tooltip: function( element ) {
		var tooltip = $( "<div>" ).attr( "role", "tooltip" ),
			content = $( "<div>" ).appendTo( tooltip ),
			id = tooltip.uniqueId().attr( "id" );

		this._addClass( content, "ui-tooltip-content" );
		this._addClass( tooltip, "ui-tooltip", "ui-widget ui-widget-content" );

		tooltip.appendTo( this._appendTo( element ) );

		return this.tooltips[ id ] = {
			element: element,
			tooltip: tooltip
		};
	},

	_find: function( target ) {
		var id = target.data( "ui-tooltip-id" );
		return id ? this.tooltips[ id ] : null;
	},

	_removeTooltip: function( tooltip ) {

		// Clear the interval for delayed tracking tooltips
		clearInterval( this.delayedShow );

		tooltip.remove();
		delete this.tooltips[ tooltip.attr( "id" ) ];
	},

	_appendTo: function( target ) {
		var element = target.closest( ".ui-front, dialog" );

		if ( !element.length ) {
			element = this.document[ 0 ].body;
		}

		return element;
	},

	_destroy: function() {
		var that = this;

		// Close open tooltips
		$.each( this.tooltips, function( id, tooltipData ) {

			// Delegate to close method to handle common cleanup
			var event = $.Event( "blur" ),
				element = tooltipData.element;
			event.target = event.currentTarget = element[ 0 ];
			that.close( event, true );

			// Remove immediately; destroying an open tooltip doesn't use the
			// hide animation
			$( "#" + id ).remove();

			// Restore the title
			if ( element.data( "ui-tooltip-title" ) ) {

				// If the title attribute has changed since open(), don't restore
				if ( !element.attr( "title" ) ) {
					element.attr( "title", element.data( "ui-tooltip-title" ) );
				}
				element.removeData( "ui-tooltip-title" );
			}
		} );
		this.liveRegion.remove();
	}
} );

// DEPRECATED
// TODO: Switch return back to widget declaration at top of file when this is removed
if ( $.uiBackCompat !== false ) {

	// Backcompat for tooltipClass option
	$.widget( "ui.tooltip", $.ui.tooltip, {
		options: {
			tooltipClass: null
		},
		_tooltip: function() {
			var tooltipData = this._superApply( arguments );
			if ( this.options.tooltipClass ) {
				tooltipData.tooltip.addClass( this.options.tooltipClass );
			}
			return tooltipData;
		}
	} );
}

var widgetsTooltip = $.ui.tooltip;




} );;
/** 
 * Name:    Highslide JS
 * Version: 4.1.12 (2011-03-28)
 * Config:  default +events +unobtrusive +imagemap +slideshow +positioning +transitions +viewport +thumbstrip +inline +ajax +iframe +flash
 * Author:  Torstein Hønsi
 * Support: www.highslide.com/support
 * License: www.highslide.com/#license
 */
if(!hs){var hs={lang:{cssDirection:"ltr",loadingText:"Loading...",loadingTitle:"Click to cancel",focusTitle:"Click to bring to front",fullExpandTitle:"Expand to actual size (f)",creditsText:"Powered by <i>Highslide JS</i>",creditsTitle:"Go to the Highslide JS homepage",previousText:"Previous",nextText:"Next",moveText:"Move",closeText:"Close",closeTitle:"Close (esc)",resizeTitle:"Resize",playText:"Play",playTitle:"Play slideshow (spacebar)",pauseText:"Pause",pauseTitle:"Pause slideshow (spacebar)",previousTitle:"Previous (arrow left)",nextTitle:"Next (arrow right)",moveTitle:"Move",fullExpandText:"1:1",number:"Image %1 of %2",restoreTitle:"Click to close image, click and drag to move. Use arrow keys for next and previous."},graphicsDir:"highslide/graphics/",expandCursor:"zoomin.cur",restoreCursor:"zoomout.cur",expandDuration:250,restoreDuration:250,marginLeft:15,marginRight:15,marginTop:15,marginBottom:15,zIndexCounter:1001,loadingOpacity:0.75,allowMultipleInstances:true,numberOfImagesToPreload:5,outlineWhileAnimating:2,outlineStartOffset:3,padToMinWidth:false,fullExpandPosition:"bottom right",fullExpandOpacity:1,showCredits:true,creditsHref:"http://highslide.com/",creditsTarget:"_self",enableKeyListener:true,openerTagNames:["a","area"],transitions:[],transitionDuration:250,dimmingOpacity:0,dimmingDuration:50,allowWidthReduction:false,allowHeightReduction:true,preserveContent:true,objectLoadTime:"before",cacheAjax:true,anchor:"auto",align:"auto",targetX:null,targetY:null,dragByHeading:true,minWidth:200,minHeight:200,allowSizeReduction:true,outlineType:"drop-shadow",skin:{controls:'<div class="highslide-controls"><ul><li class="highslide-previous"><a href="#" title="{hs.lang.previousTitle}"><span>{hs.lang.previousText}</span></a></li><li class="highslide-play"><a href="#" title="{hs.lang.playTitle}"><span>{hs.lang.playText}</span></a></li><li class="highslide-pause"><a href="#" title="{hs.lang.pauseTitle}"><span>{hs.lang.pauseText}</span></a></li><li class="highslide-next"><a href="#" title="{hs.lang.nextTitle}"><span>{hs.lang.nextText}</span></a></li><li class="highslide-move"><a href="#" title="{hs.lang.moveTitle}"><span>{hs.lang.moveText}</span></a></li><li class="highslide-full-expand"><a href="#" title="{hs.lang.fullExpandTitle}"><span>{hs.lang.fullExpandText}</span></a></li><li class="highslide-close"><a href="#" title="{hs.lang.closeTitle}" ><span>{hs.lang.closeText}</span></a></li></ul></div>',contentWrapper:'<div class="highslide-header"><ul><li class="highslide-previous"><a href="#" title="{hs.lang.previousTitle}" onclick="return hs.previous(this)"><span>{hs.lang.previousText}</span></a></li><li class="highslide-next"><a href="#" title="{hs.lang.nextTitle}" onclick="return hs.next(this)"><span>{hs.lang.nextText}</span></a></li><li class="highslide-move"><a href="#" title="{hs.lang.moveTitle}" onclick="return false"><span>{hs.lang.moveText}</span></a></li><li class="highslide-close"><a href="#" title="{hs.lang.closeTitle}" onclick="return hs.close(this)"><span>{hs.lang.closeText}</span></a></li></ul></div><div class="highslide-body"></div><div class="highslide-footer"><div><span class="highslide-resize" title="{hs.lang.resizeTitle}"><span></span></span></div></div>'},preloadTheseImages:[],continuePreloading:true,expanders:[],overrides:["allowSizeReduction","useBox","anchor","align","targetX","targetY","outlineType","outlineWhileAnimating","captionId","captionText","captionEval","captionOverlay","headingId","headingText","headingEval","headingOverlay","creditsPosition","dragByHeading","autoplay","numberPosition","transitions","dimmingOpacity","width","height","contentId","allowWidthReduction","allowHeightReduction","preserveContent","maincontentId","maincontentText","maincontentEval","objectType","cacheAjax","objectWidth","objectHeight","objectLoadTime","swfOptions","wrapperClassName","minWidth","minHeight","maxWidth","maxHeight","pageOrigin","slideshowGroup","easing","easingClose","fadeInOut","src"],overlays:[],idCounter:0,oPos:{x:["leftpanel","left","center","right","rightpanel"],y:["above","top","middle","bottom","below"]},mouse:{},headingOverlay:{},captionOverlay:{},swfOptions:{flashvars:{},params:{},attributes:{}},timers:[],slideshows:[],pendingOutlines:{},sleeping:[],preloadTheseAjax:[],cacheBindings:[],cachedGets:{},clones:{},onReady:[],uaVersion:/Trident\/4\.0/.test(navigator.userAgent)?8:parseFloat((navigator.userAgent.toLowerCase().match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[0,"0"])[1]),ie:(document.all&&!window.opera),safari:/Safari/.test(navigator.userAgent),geckoMac:/Macintosh.+rv:1\.[0-8].+Gecko/.test(navigator.userAgent),$:function(a){if(a){return document.getElementById(a)}},push:function(a,b){a[a.length]=b},createElement:function(a,f,e,d,c){var b=document.createElement(a);if(f){hs.extend(b,f)}if(c){hs.setStyles(b,{padding:0,border:"none",margin:0})}if(e){hs.setStyles(b,e)}if(d){d.appendChild(b)}return b},extend:function(b,c){for(var a in c){b[a]=c[a]}return b},setStyles:function(b,c){for(var a in c){if(hs.ieLt9&&a=="opacity"){if(c[a]>0.99){b.style.removeAttribute("filter")}else{b.style.filter="alpha(opacity="+(c[a]*100)+")"}}else{b.style[a]=c[a]}}},animate:function(f,a,d){var c,g,j;if(typeof d!="object"||d===null){var i=arguments;d={duration:i[2],easing:i[3],complete:i[4]}}if(typeof d.duration!="number"){d.duration=250}d.easing=Math[d.easing]||Math.easeInQuad;d.curAnim=hs.extend({},a);for(var b in a){var h=new hs.fx(f,d,b);c=parseFloat(hs.css(f,b))||0;g=parseFloat(a[b]);j=b!="opacity"?"px":"";h.custom(c,g,j)}},css:function(a,c){if(a.style[c]){return a.style[c]}else{if(document.defaultView){return document.defaultView.getComputedStyle(a,null).getPropertyValue(c)}else{if(c=="opacity"){c="filter"}var b=a.currentStyle[c.replace(/\-(\w)/g,function(e,d){return d.toUpperCase()})];if(c=="filter"){b=b.replace(/alpha\(opacity=([0-9]+)\)/,function(e,d){return d/100})}return b===""?1:b}}},getPageSize:function(){var f=document,b=window,e=f.compatMode&&f.compatMode!="BackCompat"?f.documentElement:f.body;var c=hs.ieLt9?e.clientWidth:(f.documentElement.clientWidth||self.innerWidth),a=hs.ieLt9?e.clientHeight:self.innerHeight;hs.page={width:c,height:a,scrollLeft:hs.ieLt9?e.scrollLeft:pageXOffset,scrollTop:hs.ieLt9?e.scrollTop:pageYOffset};return hs.page},getPosition:function(c){if(/area/i.test(c.tagName)){var e=document.getElementsByTagName("img");for(var b=0;b<e.length;b++){var a=e[b].useMap;if(a&&a.replace(/^.*?#/,"")==c.parentNode.name){c=e[b];break}}}var d={x:c.offsetLeft,y:c.offsetTop};while(c.offsetParent){c=c.offsetParent;d.x+=c.offsetLeft;d.y+=c.offsetTop;if(c!=document.body&&c!=document.documentElement){d.x-=c.scrollLeft;d.y-=c.scrollTop}}return d},expand:function(b,h,f,d){if(!b){b=hs.createElement("a",null,{display:"none"},hs.container)}if(typeof b.getParams=="function"){return h}if(d=="html"){for(var c=0;c<hs.sleeping.length;c++){if(hs.sleeping[c]&&hs.sleeping[c].a==b){hs.sleeping[c].awake();hs.sleeping[c]=null;return false}}hs.hasHtmlExpanders=true}try{new hs.Expander(b,h,f,d);return false}catch(g){return true}},htmlExpand:function(b,d,c){return hs.expand(b,d,c,"html")},getSelfRendered:function(){return hs.createElement("div",{className:"highslide-html-content",innerHTML:hs.replaceLang(hs.skin.contentWrapper)})},getElementByClass:function(e,c,d){var b=e.getElementsByTagName(c);for(var a=0;a<b.length;a++){if((new RegExp(d)).test(b[a].className)){return b[a]}}return null},replaceLang:function(c){c=c.replace(/\s/g," ");var b=/{hs\.lang\.([^}]+)\}/g,d=c.match(b),e;if(d){for(var a=0;a<d.length;a++){e=d[a].replace(b,"$1");if(typeof hs.lang[e]!="undefined"){c=c.replace(d[a],hs.lang[e])}}}return c},setClickEvents:function(){var b=document.getElementsByTagName("a");for(var a=0;a<b.length;a++){var c=hs.isUnobtrusiveAnchor(b[a]);if(c&&!b[a].hsHasSetClick){(function(){var d=c;if(hs.fireEvent(hs,"onSetClickEvent",{element:b[a],type:d})){b[a].onclick=(c=="image")?function(){return hs.expand(this)}:function(){return hs.htmlExpand(this,{objectType:d})}}})();b[a].hsHasSetClick=true}}hs.getAnchors()},isUnobtrusiveAnchor:function(a){if(a.rel=="highslide"){return"image"}else{if(a.rel=="highslide-ajax"){return"ajax"}else{if(a.rel=="highslide-iframe"){return"iframe"}else{if(a.rel=="highslide-swf"){return"swf"}}}}},getCacheBinding:function(b){for(var d=0;d<hs.cacheBindings.length;d++){if(hs.cacheBindings[d][0]==b){var e=hs.cacheBindings[d][1];hs.cacheBindings[d][1]=e.cloneNode(1);return e}}return null},preloadAjax:function(f){var b=hs.getAnchors();for(var d=0;d<b.htmls.length;d++){var c=b.htmls[d];if(hs.getParam(c,"objectType")=="ajax"&&hs.getParam(c,"cacheAjax")){hs.push(hs.preloadTheseAjax,c)}}hs.preloadAjaxElement(0)},preloadAjaxElement:function(d){if(!hs.preloadTheseAjax[d]){return}var b=hs.preloadTheseAjax[d];var c=hs.getNode(hs.getParam(b,"contentId"));if(!c){c=hs.getSelfRendered()}var e=new hs.Ajax(b,c,1);e.onError=function(){};e.onLoad=function(){hs.push(hs.cacheBindings,[b,c]);hs.preloadAjaxElement(d+1)};e.run()},focusTopmost:function(){var c=0,b=-1,a=hs.expanders,e,f;for(var d=0;d<a.length;d++){e=a[d];if(e){f=e.wrapper.style.zIndex;if(f&&f>c){c=f;b=d}}}if(b==-1){hs.focusKey=-1}else{a[b].focus()}},getParam:function(b,d){b.getParams=b.onclick;var c=b.getParams?b.getParams():null;b.getParams=null;return(c&&typeof c[d]!="undefined")?c[d]:(typeof hs[d]!="undefined"?hs[d]:null)},getSrc:function(b){var c=hs.getParam(b,"src");if(c){return c}return b.href},getNode:function(e){var c=hs.$(e),d=hs.clones[e],b={};if(!c&&!d){return null}if(!d){d=c.cloneNode(true);d.id="";hs.clones[e]=d;return c}else{return d.cloneNode(true)}},discardElement:function(a){if(a){hs.garbageBin.appendChild(a)}hs.garbageBin.innerHTML=""},dim:function(b){if(!hs.dimmer){a=true;hs.dimmer=hs.createElement("div",{className:"highslide-dimming highslide-viewport-size",owner:"",onclick:function(){if(hs.fireEvent(hs,"onDimmerClick")){hs.close()}}},{visibility:"visible",opacity:0},hs.container,true)}hs.dimmer.style.display="";var a=hs.dimmer.owner=="";hs.dimmer.owner+="|"+b.key;if(a){if(hs.geckoMac&&hs.dimmingGeckoFix){hs.setStyles(hs.dimmer,{background:"url("+hs.graphicsDir+"geckodimmer.png)",opacity:1})}else{hs.animate(hs.dimmer,{opacity:b.dimmingOpacity},hs.dimmingDuration)}}},undim:function(a){if(!hs.dimmer){return}if(typeof a!="undefined"){hs.dimmer.owner=hs.dimmer.owner.replace("|"+a,"")}if((typeof a!="undefined"&&hs.dimmer.owner!="")||(hs.upcoming&&hs.getParam(hs.upcoming,"dimmingOpacity"))){return}if(hs.geckoMac&&hs.dimmingGeckoFix){hs.dimmer.style.display="none"}else{hs.animate(hs.dimmer,{opacity:0},hs.dimmingDuration,null,function(){hs.dimmer.style.display="none"})}},transit:function(a,d){var b=d||hs.getExpander();d=b;if(hs.upcoming){return false}else{hs.last=b}hs.removeEventListener(document,window.opera?"keypress":"keydown",hs.keyHandler);try{hs.upcoming=a;a.onclick()}catch(c){hs.last=hs.upcoming=null}try{if(!a||d.transitions[1]!="crossfade"){d.close()}}catch(c){}return false},previousOrNext:function(a,c){var b=hs.getExpander(a);if(b){return hs.transit(b.getAdjacentAnchor(c),b)}else{return false}},previous:function(a){return hs.previousOrNext(a,-1)},next:function(a){return hs.previousOrNext(a,1)},keyHandler:function(a){if(!a){a=window.event}if(!a.target){a.target=a.srcElement}if(typeof a.target.form!="undefined"){return true}if(!hs.fireEvent(hs,"onKeyDown",a)){return true}var b=hs.getExpander();var c=null;switch(a.keyCode){case 70:if(b){b.doFullExpand()}return true;case 32:c=2;break;case 34:case 39:case 40:c=1;break;case 8:case 33:case 37:case 38:c=-1;break;case 27:case 13:c=0}if(c!==null){hs.removeEventListener(document,window.opera?"keypress":"keydown",hs.keyHandler);if(!hs.enableKeyListener){return true}if(a.preventDefault){a.preventDefault()}else{a.returnValue=false}if(b){if(c==0){b.close()}else{if(c==2){if(b.slideshow){b.slideshow.hitSpace()}}else{if(b.slideshow){b.slideshow.pause()}hs.previousOrNext(b.key,c)}}return false}}return true},registerOverlay:function(a){hs.push(hs.overlays,hs.extend(a,{hsId:"hsId"+hs.idCounter++}))},addSlideshow:function(b){var d=b.slideshowGroup;if(typeof d=="object"){for(var c=0;c<d.length;c++){var e={};for(var a in b){e[a]=b[a]}e.slideshowGroup=d[c];hs.push(hs.slideshows,e)}}else{hs.push(hs.slideshows,b)}},getWrapperKey:function(c,b){var e,d=/^highslide-wrapper-([0-9]+)$/;e=c;while(e.parentNode){if(e.hsKey!==undefined){return e.hsKey}if(e.id&&d.test(e.id)){return e.id.replace(d,"$1")}e=e.parentNode}if(!b){e=c;while(e.parentNode){if(e.tagName&&hs.isHsAnchor(e)){for(var a=0;a<hs.expanders.length;a++){var f=hs.expanders[a];if(f&&f.a==e){return a}}}e=e.parentNode}}return null},getExpander:function(b,a){if(typeof b=="undefined"){return hs.expanders[hs.focusKey]||null}if(typeof b=="number"){return hs.expanders[b]||null}if(typeof b=="string"){b=hs.$(b)}return hs.expanders[hs.getWrapperKey(b,a)]||null},isHsAnchor:function(b){return(b.onclick&&b.onclick.toString().replace(/\s/g," ").match(/hs.(htmlE|e)xpand/))},reOrder:function(){for(var a=0;a<hs.expanders.length;a++){if(hs.expanders[a]&&hs.expanders[a].isExpanded){hs.focusTopmost()}}},fireEvent:function(c,a,b){return c&&c[a]?(c[a](c,b)!==false):true},mouseClickHandler:function(d){if(!d){d=window.event}if(d.button>1){return true}if(!d.target){d.target=d.srcElement}var b=d.target;while(b.parentNode&&!(/highslide-(image|move|html|resize)/.test(b.className))){b=b.parentNode}var f=hs.getExpander(b);if(f&&(f.isClosing||!f.isExpanded)){return true}if(f&&d.type=="mousedown"){if(d.target.form){return true}var a=b.className.match(/highslide-(image|move|resize)/);if(a){hs.dragArgs={exp:f,type:a[1],left:f.x.pos,width:f.x.size,top:f.y.pos,height:f.y.size,clickX:d.clientX,clickY:d.clientY};hs.addEventListener(document,"mousemove",hs.dragHandler);if(d.preventDefault){d.preventDefault()}if(/highslide-(image|html)-blur/.test(f.content.className)){f.focus();hs.hasFocused=true}return false}else{if(/highslide-html/.test(b.className)&&hs.focusKey!=f.key){f.focus();f.doShowHide("hidden")}}}else{if(d.type=="mouseup"){hs.removeEventListener(document,"mousemove",hs.dragHandler);if(hs.dragArgs){if(hs.styleRestoreCursor&&hs.dragArgs.type=="image"){hs.dragArgs.exp.content.style.cursor=hs.styleRestoreCursor}var c=hs.dragArgs.hasDragged;if(!c&&!hs.hasFocused&&!/(move|resize)/.test(hs.dragArgs.type)){if(hs.fireEvent(f,"onImageClick")){f.close()}}else{if(c||(!c&&hs.hasHtmlExpanders)){hs.dragArgs.exp.doShowHide("hidden")}}if(hs.dragArgs.exp.releaseMask){hs.dragArgs.exp.releaseMask.style.display="none"}if(c){hs.fireEvent(hs.dragArgs.exp,"onDrop",hs.dragArgs)}hs.hasFocused=false;hs.dragArgs=null}else{if(/highslide-image-blur/.test(b.className)){b.style.cursor=hs.styleRestoreCursor}}}}return false},dragHandler:function(c){if(!hs.dragArgs){return true}if(!c){c=window.event}var b=hs.dragArgs,d=b.exp;if(d.iframe){if(!d.releaseMask){d.releaseMask=hs.createElement("div",null,{position:"absolute",width:d.x.size+"px",height:d.y.size+"px",left:d.x.cb+"px",top:d.y.cb+"px",zIndex:4,background:(hs.ieLt9?"white":"none"),opacity:0.01},d.wrapper,true)}if(d.releaseMask.style.display=="none"){d.releaseMask.style.display=""}}b.dX=c.clientX-b.clickX;b.dY=c.clientY-b.clickY;var f=Math.sqrt(Math.pow(b.dX,2)+Math.pow(b.dY,2));if(!b.hasDragged){b.hasDragged=(b.type!="image"&&f>0)||(f>(hs.dragSensitivity||5))}if(b.hasDragged&&c.clientX>5&&c.clientY>5){if(!hs.fireEvent(d,"onDrag",b)){return false}if(b.type=="resize"){d.resize(b)}else{d.moveTo(b.left+b.dX,b.top+b.dY);if(b.type=="image"){d.content.style.cursor="move"}}}return false},wrapperMouseHandler:function(c){try{if(!c){c=window.event}var b=/mouseover/i.test(c.type);if(!c.target){c.target=c.srcElement}if(!c.relatedTarget){c.relatedTarget=b?c.fromElement:c.toElement}var d=hs.getExpander(c.target);if(!d.isExpanded){return}if(!d||!c.relatedTarget||hs.getExpander(c.relatedTarget,true)==d||hs.dragArgs){return}hs.fireEvent(d,b?"onMouseOver":"onMouseOut",c);for(var a=0;a<d.overlays.length;a++){(function(){var e=hs.$("hsId"+d.overlays[a]);if(e&&e.hideOnMouseOut){if(b){hs.setStyles(e,{visibility:"visible",display:""})}hs.animate(e,{opacity:b?e.opacity:0},e.dur)}})()}}catch(c){}},addEventListener:function(a,c,b){if(a==document&&c=="ready"){hs.push(hs.onReady,b)}try{a.addEventListener(c,b,false)}catch(d){try{a.detachEvent("on"+c,b);a.attachEvent("on"+c,b)}catch(d){a["on"+c]=b}}},removeEventListener:function(a,c,b){try{a.removeEventListener(c,b,false)}catch(d){try{a.detachEvent("on"+c,b)}catch(d){a["on"+c]=null}}},preloadFullImage:function(b){if(hs.continuePreloading&&hs.preloadTheseImages[b]&&hs.preloadTheseImages[b]!="undefined"){var a=document.createElement("img");a.onload=function(){a=null;hs.preloadFullImage(b+1)};a.src=hs.preloadTheseImages[b]}},preloadImages:function(c){if(c&&typeof c!="object"){hs.numberOfImagesToPreload=c}var a=hs.getAnchors();for(var b=0;b<a.images.length&&b<hs.numberOfImagesToPreload;b++){hs.push(hs.preloadTheseImages,hs.getSrc(a.images[b]))}if(hs.outlineType){new hs.Outline(hs.outlineType,function(){hs.preloadFullImage(0)})}else{hs.preloadFullImage(0)}if(hs.restoreCursor){var d=hs.createElement("img",{src:hs.graphicsDir+hs.restoreCursor})}},init:function(){if(!hs.container){hs.ieLt7=hs.ie&&hs.uaVersion<7;hs.ieLt9=hs.ie&&hs.uaVersion<9;hs.getPageSize();hs.ie6SSL=hs.ieLt7&&location.protocol=="https:";for(var a in hs.langDefaults){if(typeof hs[a]!="undefined"){hs.lang[a]=hs[a]}else{if(typeof hs.lang[a]=="undefined"&&typeof hs.langDefaults[a]!="undefined"){hs.lang[a]=hs.langDefaults[a]}}}hs.container=hs.createElement("div",{className:"highslide-container"},{position:"absolute",left:0,top:0,width:"100%",zIndex:hs.zIndexCounter,direction:"ltr"},document.body,true);hs.loading=hs.createElement("a",{className:"highslide-loading",title:hs.lang.loadingTitle,innerHTML:hs.lang.loadingText,href:"javascript:;"},{position:"absolute",top:"-9999px",opacity:hs.loadingOpacity,zIndex:1},hs.container);hs.garbageBin=hs.createElement("div",null,{display:"none"},hs.container);hs.viewport=hs.createElement("div",{className:"highslide-viewport highslide-viewport-size"},{visibility:(hs.safari&&hs.uaVersion<525)?"visible":"hidden"},hs.container,1);hs.clearing=hs.createElement("div",null,{clear:"both",paddingTop:"1px"},null,true);Math.linearTween=function(f,e,h,g){return h*f/g+e};Math.easeInQuad=function(f,e,h,g){return h*(f/=g)*f+e};Math.easeOutQuad=function(f,e,h,g){return -h*(f/=g)*(f-2)+e};hs.hideSelects=hs.ieLt7;hs.hideIframes=((window.opera&&hs.uaVersion<9)||navigator.vendor=="KDE"||(hs.ieLt7&&hs.uaVersion<5.5));hs.fireEvent(this,"onActivate")}},ready:function(){if(hs.isReady){return}hs.isReady=true;for(var a=0;a<hs.onReady.length;a++){hs.onReady[a]()}},updateAnchors:function(){var a,d,l=[],h=[],k=[],b={},m;for(var e=0;e<hs.openerTagNames.length;e++){d=document.getElementsByTagName(hs.openerTagNames[e]);for(var c=0;c<d.length;c++){a=d[c];m=hs.isHsAnchor(a);if(m){hs.push(l,a);if(m[0]=="hs.expand"){hs.push(h,a)}else{if(m[0]=="hs.htmlExpand"){hs.push(k,a)}}var f=hs.getParam(a,"slideshowGroup")||"none";if(!b[f]){b[f]=[]}hs.push(b[f],a)}}}hs.anchors={all:l,groups:b,images:h,htmls:k};return hs.anchors},getAnchors:function(){return hs.anchors||hs.updateAnchors()},close:function(a){var b=hs.getExpander(a);if(b){b.close()}return false}};hs.fx=function(b,a,c){this.options=a;this.elem=b;this.prop=c;if(!a.orig){a.orig={}}};hs.fx.prototype={update:function(){(hs.fx.step[this.prop]||hs.fx.step._default)(this);if(this.options.step){this.options.step.call(this.elem,this.now,this)}},custom:function(e,d,c){this.startTime=(new Date()).getTime();this.start=e;this.end=d;this.unit=c;this.now=this.start;this.pos=this.state=0;var a=this;function b(f){return a.step(f)}b.elem=this.elem;if(b()&&hs.timers.push(b)==1){hs.timerId=setInterval(function(){var g=hs.timers;for(var f=0;f<g.length;f++){if(!g[f]()){g.splice(f--,1)}}if(!g.length){clearInterval(hs.timerId)}},13)}},step:function(d){var c=(new Date()).getTime();if(d||c>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var a=true;for(var b in this.options.curAnim){if(this.options.curAnim[b]!==true){a=false}}if(a){if(this.options.complete){this.options.complete.call(this.elem)}}return false}else{var e=c-this.startTime;this.state=e/this.options.duration;this.pos=this.options.easing(e,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update()}return true}};hs.extend(hs.fx,{step:{opacity:function(a){hs.setStyles(a.elem,{opacity:a.now})},_default:function(a){try{if(a.elem.style&&a.elem.style[a.prop]!=null){a.elem.style[a.prop]=a.now+a.unit}else{a.elem[a.prop]=a.now}}catch(b){}}}});hs.Outline=function(g,e){this.onLoad=e;this.outlineType=g;var a=hs.uaVersion,f;this.hasAlphaImageLoader=hs.ie&&hs.uaVersion<7;if(!g){if(e){e()}return}hs.init();this.table=hs.createElement("table",{cellSpacing:0},{visibility:"hidden",position:"absolute",borderCollapse:"collapse",width:0},hs.container,true);var b=hs.createElement("tbody",null,null,this.table,1);this.td=[];for(var c=0;c<=8;c++){if(c%3==0){f=hs.createElement("tr",null,{height:"auto"},b,true)}this.td[c]=hs.createElement("td",null,null,f,true);var d=c!=4?{lineHeight:0,fontSize:0}:{position:"relative"};hs.setStyles(this.td[c],d)}this.td[4].className=g+" highslide-outline";this.preloadGraphic()};hs.Outline.prototype={preloadGraphic:function(){var b=hs.graphicsDir+(hs.outlinesDir||"outlines/")+this.outlineType+".png";var a=hs.safari&&hs.uaVersion<525?hs.container:null;this.graphic=hs.createElement("img",null,{position:"absolute",top:"-9999px"},a,true);var c=this;this.graphic.onload=function(){c.onGraphicLoad()};this.graphic.src=b},onGraphicLoad:function(){var d=this.offset=this.graphic.width/4,f=[[0,0],[0,-4],[-2,0],[0,-8],0,[-2,-8],[0,-2],[0,-6],[-2,-2]],c={height:(2*d)+"px",width:(2*d)+"px"};for(var b=0;b<=8;b++){if(f[b]){if(this.hasAlphaImageLoader){var a=(b==1||b==7)?"100%":this.graphic.width+"px";var e=hs.createElement("div",null,{width:"100%",height:"100%",position:"relative",overflow:"hidden"},this.td[b],true);hs.createElement("div",null,{filter:"progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale, src='"+this.graphic.src+"')",position:"absolute",width:a,height:this.graphic.height+"px",left:(f[b][0]*d)+"px",top:(f[b][1]*d)+"px"},e,true)}else{hs.setStyles(this.td[b],{background:"url("+this.graphic.src+") "+(f[b][0]*d)+"px "+(f[b][1]*d)+"px"})}if(window.opera&&(b==3||b==5)){hs.createElement("div",null,c,this.td[b],true)}hs.setStyles(this.td[b],c)}}this.graphic=null;if(hs.pendingOutlines[this.outlineType]){hs.pendingOutlines[this.outlineType].destroy()}hs.pendingOutlines[this.outlineType]=this;if(this.onLoad){this.onLoad()}},setPosition:function(g,e,c,b,f){var d=this.exp,a=d.wrapper.style,e=e||0,g=g||{x:d.x.pos+e,y:d.y.pos+e,w:d.x.get("wsize")-2*e,h:d.y.get("wsize")-2*e};if(c){this.table.style.visibility=(g.h>=4*this.offset)?"visible":"hidden"}hs.setStyles(this.table,{left:(g.x-this.offset)+"px",top:(g.y-this.offset)+"px",width:(g.w+2*this.offset)+"px"});g.w-=2*this.offset;g.h-=2*this.offset;hs.setStyles(this.td[4],{width:g.w>=0?g.w+"px":0,height:g.h>=0?g.h+"px":0});if(this.hasAlphaImageLoader){this.td[3].style.height=this.td[5].style.height=this.td[4].style.height}},destroy:function(a){if(a){this.table.style.visibility="hidden"}else{hs.discardElement(this.table)}}};hs.Dimension=function(b,a){this.exp=b;this.dim=a;this.ucwh=a=="x"?"Width":"Height";this.wh=this.ucwh.toLowerCase();this.uclt=a=="x"?"Left":"Top";this.lt=this.uclt.toLowerCase();this.ucrb=a=="x"?"Right":"Bottom";this.rb=this.ucrb.toLowerCase();this.p1=this.p2=0};hs.Dimension.prototype={get:function(a){switch(a){case"loadingPos":return this.tpos+this.tb+(this.t-hs.loading["offset"+this.ucwh])/2;case"loadingPosXfade":return this.pos+this.cb+this.p1+(this.size-hs.loading["offset"+this.ucwh])/2;case"wsize":return this.size+2*this.cb+this.p1+this.p2;case"fitsize":return this.clientSize-this.marginMin-this.marginMax;case"maxsize":return this.get("fitsize")-2*this.cb-this.p1-this.p2;case"opos":return this.pos-(this.exp.outline?this.exp.outline.offset:0);case"osize":return this.get("wsize")+(this.exp.outline?2*this.exp.outline.offset:0);case"imgPad":return this.imgSize?Math.round((this.size-this.imgSize)/2):0}},calcBorders:function(){this.cb=(this.exp.content["offset"+this.ucwh]-this.t)/2;this.marginMax=hs["margin"+this.ucrb]},calcThumb:function(){this.t=this.exp.el[this.wh]?parseInt(this.exp.el[this.wh]):this.exp.el["offset"+this.ucwh];this.tpos=this.exp.tpos[this.dim];this.tb=(this.exp.el["offset"+this.ucwh]-this.t)/2;if(this.tpos==0||this.tpos==-1){this.tpos=(hs.page[this.wh]/2)+hs.page["scroll"+this.uclt]}},calcExpanded:function(){var a=this.exp;this.justify="auto";if(a.align=="center"){this.justify="center"}else{if(new RegExp(this.lt).test(a.anchor)){this.justify=null}else{if(new RegExp(this.rb).test(a.anchor)){this.justify="max"}}}this.pos=this.tpos-this.cb+this.tb;if(this.maxHeight&&this.dim=="x"){a.maxWidth=Math.min(a.maxWidth||this.full,a.maxHeight*this.full/a.y.full)}this.size=Math.min(this.full,a["max"+this.ucwh]||this.full);this.minSize=a.allowSizeReduction?Math.min(a["min"+this.ucwh],this.full):this.full;if(a.isImage&&a.useBox){this.size=a[this.wh];this.imgSize=this.full}if(this.dim=="x"&&hs.padToMinWidth){this.minSize=a.minWidth}this.target=a["target"+this.dim.toUpperCase()];this.marginMin=hs["margin"+this.uclt];this.scroll=hs.page["scroll"+this.uclt];this.clientSize=hs.page[this.wh]},setSize:function(a){var f=this.exp;if(f.isImage&&(f.useBox||hs.padToMinWidth)){this.imgSize=a;this.size=Math.max(this.size,this.imgSize);f.content.style[this.lt]=this.get("imgPad")+"px"}else{this.size=a}f.content.style[this.wh]=a+"px";f.wrapper.style[this.wh]=this.get("wsize")+"px";if(f.outline){f.outline.setPosition()}if(f.releaseMask){f.releaseMask.style[this.wh]=a+"px"}if(this.dim=="y"&&f.iDoc&&f.body.style.height!="auto"){try{f.iDoc.body.style.overflow="auto"}catch(b){}}if(f.isHtml){var c=f.scrollerDiv;if(this.sizeDiff===undefined){this.sizeDiff=f.innerContent["offset"+this.ucwh]-c["offset"+this.ucwh]}c.style[this.wh]=(this.size-this.sizeDiff)+"px";if(this.dim=="x"){f.mediumContent.style.width="auto"}if(f.body){f.body.style[this.wh]="auto"}}if(this.dim=="x"&&f.overlayBox){f.sizeOverlayBox(true)}if(this.dim=="x"&&f.slideshow&&f.isImage){if(a==this.full){f.slideshow.disable("full-expand")}else{f.slideshow.enable("full-expand")}}},setPos:function(a){this.pos=a;this.exp.wrapper.style[this.lt]=a+"px";if(this.exp.outline){this.exp.outline.setPosition()}}};hs.Expander=function(k,f,b,l){if(document.readyState&&hs.ie&&!hs.isReady){hs.addEventListener(document,"ready",function(){new hs.Expander(k,f,b,l)});return}this.a=k;this.custom=b;this.contentType=l||"image";this.isHtml=(l=="html");this.isImage=!this.isHtml;hs.continuePreloading=false;this.overlays=[];this.last=hs.last;hs.last=null;hs.init();var m=this.key=hs.expanders.length;for(var g=0;g<hs.overrides.length;g++){var c=hs.overrides[g];this[c]=f&&typeof f[c]!="undefined"?f[c]:hs[c]}if(!this.src){this.src=k.href}var d=(f&&f.thumbnailId)?hs.$(f.thumbnailId):k;d=this.thumb=d.getElementsByTagName("img")[0]||d;this.thumbsUserSetId=d.id||k.id;if(!hs.fireEvent(this,"onInit")){return true}for(var g=0;g<hs.expanders.length;g++){if(hs.expanders[g]&&hs.expanders[g].a==k&&!(this.last&&this.transitions[1]=="crossfade")){hs.expanders[g].focus();return false}}if(!hs.allowSimultaneousLoading){for(var g=0;g<hs.expanders.length;g++){if(hs.expanders[g]&&hs.expanders[g].thumb!=d&&!hs.expanders[g].onLoadStarted){hs.expanders[g].cancelLoading()}}}hs.expanders[m]=this;if(!hs.allowMultipleInstances&&!hs.upcoming){if(hs.expanders[m-1]){hs.expanders[m-1].close()}if(typeof hs.focusKey!="undefined"&&hs.expanders[hs.focusKey]){hs.expanders[hs.focusKey].close()}}this.el=d;this.tpos=this.pageOrigin||hs.getPosition(d);hs.getPageSize();var j=this.x=new hs.Dimension(this,"x");j.calcThumb();var h=this.y=new hs.Dimension(this,"y");h.calcThumb();if(/area/i.test(d.tagName)){this.getImageMapAreaCorrection(d)}this.wrapper=hs.createElement("div",{id:"highslide-wrapper-"+this.key,className:"highslide-wrapper "+this.wrapperClassName},{visibility:"hidden",position:"absolute",zIndex:hs.zIndexCounter+=2},null,true);this.wrapper.onmouseover=this.wrapper.onmouseout=hs.wrapperMouseHandler;if(this.contentType=="image"&&this.outlineWhileAnimating==2){this.outlineWhileAnimating=0}if(!this.outlineType||(this.last&&this.isImage&&this.transitions[1]=="crossfade")){this[this.contentType+"Create"]()}else{if(hs.pendingOutlines[this.outlineType]){this.connectOutline();this[this.contentType+"Create"]()}else{this.showLoading();var e=this;new hs.Outline(this.outlineType,function(){e.connectOutline();e[e.contentType+"Create"]()})}}return true};hs.Expander.prototype={error:function(a){if(hs.debug){alert("Line "+a.lineNumber+": "+a.message)}else{window.location.href=this.src}},connectOutline:function(){var a=this.outline=hs.pendingOutlines[this.outlineType];a.exp=this;a.table.style.zIndex=this.wrapper.style.zIndex-1;hs.pendingOutlines[this.outlineType]=null},showLoading:function(){if(this.onLoadStarted||this.loading){return}this.loading=hs.loading;var c=this;this.loading.onclick=function(){c.cancelLoading()};if(!hs.fireEvent(this,"onShowLoading")){return}var c=this,a=this.x.get("loadingPos")+"px",b=this.y.get("loadingPos")+"px";if(!d&&this.last&&this.transitions[1]=="crossfade"){var d=this.last}if(d){a=d.x.get("loadingPosXfade")+"px";b=d.y.get("loadingPosXfade")+"px";this.loading.style.zIndex=hs.zIndexCounter++}setTimeout(function(){if(c.loading){hs.setStyles(c.loading,{left:a,top:b,zIndex:hs.zIndexCounter++})}},100)},imageCreate:function(){var b=this;var a=document.createElement("img");this.content=a;a.onload=function(){if(hs.expanders[b.key]){b.contentLoaded()}};if(hs.blockRightClick){a.oncontextmenu=function(){return false}}a.className="highslide-image";hs.setStyles(a,{visibility:"hidden",display:"block",position:"absolute",maxWidth:"9999px",zIndex:3});a.title=hs.lang.restoreTitle;if(hs.safari&&hs.uaVersion<525){hs.container.appendChild(a)}if(hs.ie&&hs.flushImgSize){a.src=null}a.src=this.src;this.showLoading()},htmlCreate:function(){if(!hs.fireEvent(this,"onBeforeGetContent")){return}this.content=hs.getCacheBinding(this.a);if(!this.content){this.content=hs.getNode(this.contentId)}if(!this.content){this.content=hs.getSelfRendered()}this.getInline(["maincontent"]);if(this.maincontent){var a=hs.getElementByClass(this.content,"div","highslide-body");if(a){a.appendChild(this.maincontent)}this.maincontent.style.display="block"}hs.fireEvent(this,"onAfterGetContent");var d=this.innerContent=this.content;if(/(swf|iframe)/.test(this.objectType)){this.setObjContainerSize(d)}hs.container.appendChild(this.wrapper);hs.setStyles(this.wrapper,{position:"static",padding:"0 "+hs.marginRight+"px 0 "+hs.marginLeft+"px"});this.content=hs.createElement("div",{className:"highslide-html"},{position:"relative",zIndex:3,height:0,overflow:"hidden"},this.wrapper);this.mediumContent=hs.createElement("div",null,null,this.content,1);this.mediumContent.appendChild(d);hs.setStyles(d,{position:"relative",display:"block",direction:hs.lang.cssDirection||""});if(this.width){d.style.width=this.width+"px"}if(this.height){hs.setStyles(d,{height:this.height+"px",overflow:"hidden"})}if(d.offsetWidth<this.minWidth){d.style.width=this.minWidth+"px"}if(this.objectType=="ajax"&&!hs.getCacheBinding(this.a)){this.showLoading();var c=this;var b=new hs.Ajax(this.a,d);b.src=this.src;b.onLoad=function(){if(hs.expanders[c.key]){c.contentLoaded()}};b.onError=function(){location.href=c.src};b.run()}else{if(this.objectType=="iframe"&&this.objectLoadTime=="before"){this.writeExtendedContent()}else{this.contentLoaded()}}},contentLoaded:function(){try{if(!this.content){return}this.content.onload=null;if(this.onLoadStarted){return}else{this.onLoadStarted=true}var j=this.x,g=this.y;if(this.loading){hs.setStyles(this.loading,{top:"-9999px"});this.loading=null;hs.fireEvent(this,"onHideLoading")}if(this.isImage){j.full=this.content.width;g.full=this.content.height;hs.setStyles(this.content,{width:j.t+"px",height:g.t+"px"});this.wrapper.appendChild(this.content);hs.container.appendChild(this.wrapper)}else{if(this.htmlGetSize){this.htmlGetSize()}}j.calcBorders();g.calcBorders();hs.setStyles(this.wrapper,{left:(j.tpos+j.tb-j.cb)+"px",top:(g.tpos+j.tb-g.cb)+"px"});this.initSlideshow();this.getOverlays();var f=j.full/g.full;j.calcExpanded();this.justify(j);g.calcExpanded();this.justify(g);if(this.isHtml){this.htmlSizeOperations()}if(this.overlayBox){this.sizeOverlayBox(0,1)}if(this.allowSizeReduction){if(this.isImage){this.correctRatio(f)}else{this.fitOverlayBox()}var k=this.slideshow;if(k&&this.last&&k.controls&&k.fixedControls){var h=k.overlayOptions.position||"",a;for(var c in hs.oPos){for(var b=0;b<5;b++){a=this[c];if(h.match(hs.oPos[c][b])){a.pos=this.last[c].pos+(this.last[c].p1-a.p1)+(this.last[c].size-a.size)*[0,0,0.5,1,1][b];if(k.fixedControls=="fit"){if(a.pos+a.size+a.p1+a.p2>a.scroll+a.clientSize-a.marginMax){a.pos=a.scroll+a.clientSize-a.size-a.marginMin-a.marginMax-a.p1-a.p2}if(a.pos<a.scroll+a.marginMin){a.pos=a.scroll+a.marginMin}}}}}}if(this.isImage&&this.x.full>(this.x.imgSize||this.x.size)){this.createFullExpand();if(this.overlays.length==1){this.sizeOverlayBox()}}}this.show()}catch(d){this.error(d)}},setObjContainerSize:function(a,d){var b=hs.getElementByClass(a,"DIV","highslide-body");if(/(iframe|swf)/.test(this.objectType)){if(this.objectWidth){b.style.width=this.objectWidth+"px"}if(this.objectHeight){b.style.height=this.objectHeight+"px"}}},writeExtendedContent:function(){if(this.hasExtendedContent){return}var f=this;this.body=hs.getElementByClass(this.innerContent,"DIV","highslide-body");if(this.objectType=="iframe"){this.showLoading();var g=hs.clearing.cloneNode(1);this.body.appendChild(g);this.newWidth=this.innerContent.offsetWidth;if(!this.objectWidth){this.objectWidth=g.offsetWidth}var c=this.innerContent.offsetHeight-this.body.offsetHeight,d=this.objectHeight||hs.page.height-c-hs.marginTop-hs.marginBottom,e=this.objectLoadTime=="before"?' onload="if (hs.expanders['+this.key+"]) hs.expanders["+this.key+'].contentLoaded()" ':"";this.body.innerHTML+='<iframe name="hs'+(new Date()).getTime()+'" frameborder="0" key="'+this.key+'"  style="width:'+this.objectWidth+"px; height:"+d+'px" '+e+' src="'+this.src+'" ></iframe>';this.ruler=this.body.getElementsByTagName("div")[0];this.iframe=this.body.getElementsByTagName("iframe")[0];if(this.objectLoadTime=="after"){this.correctIframeSize()}}if(this.objectType=="swf"){this.body.id=this.body.id||"hs-flash-id-"+this.key;var b=this.swfOptions;if(!b.params){b.params={}}if(typeof b.params.wmode=="undefined"){b.params.wmode="transparent"}if(swfobject){swfobject.embedSWF(this.src,this.body.id,this.objectWidth,this.objectHeight,b.version||"7",b.expressInstallSwfurl,b.flashvars,b.params,b.attributes)}}this.hasExtendedContent=true},htmlGetSize:function(){if(this.iframe&&!this.objectHeight){this.iframe.style.height=this.body.style.height=this.getIframePageHeight()+"px"}this.innerContent.appendChild(hs.clearing);if(!this.x.full){this.x.full=this.innerContent.offsetWidth}this.y.full=this.innerContent.offsetHeight;this.innerContent.removeChild(hs.clearing);if(hs.ie&&this.newHeight>parseInt(this.innerContent.currentStyle.height)){this.newHeight=parseInt(this.innerContent.currentStyle.height)}hs.setStyles(this.wrapper,{position:"absolute",padding:"0"});hs.setStyles(this.content,{width:this.x.t+"px",height:this.y.t+"px"})},getIframePageHeight:function(){var a;try{var d=this.iDoc=this.iframe.contentDocument||this.iframe.contentWindow.document;var b=d.createElement("div");b.style.clear="both";d.body.appendChild(b);a=b.offsetTop;if(hs.ie){a+=parseInt(d.body.currentStyle.marginTop)+parseInt(d.body.currentStyle.marginBottom)-1}}catch(c){a=300}return a},correctIframeSize:function(){var b=this.innerContent.offsetWidth-this.ruler.offsetWidth;hs.discardElement(this.ruler);if(b<0){b=0}var a=this.innerContent.offsetHeight-this.iframe.offsetHeight;if(this.iDoc&&!this.objectHeight&&!this.height&&this.y.size==this.y.full){try{this.iDoc.body.style.overflow="hidden"}catch(c){}}hs.setStyles(this.iframe,{width:Math.abs(this.x.size-b)+"px",height:Math.abs(this.y.size-a)+"px"});hs.setStyles(this.body,{width:this.iframe.style.width,height:this.iframe.style.height});this.scrollingContent=this.iframe;this.scrollerDiv=this.scrollingContent},htmlSizeOperations:function(){this.setObjContainerSize(this.innerContent);if(this.objectType=="swf"&&this.objectLoadTime=="before"){this.writeExtendedContent()}if(this.x.size<this.x.full&&!this.allowWidthReduction){this.x.size=this.x.full}if(this.y.size<this.y.full&&!this.allowHeightReduction){this.y.size=this.y.full}this.scrollerDiv=this.innerContent;hs.setStyles(this.mediumContent,{position:"relative",width:this.x.size+"px"});hs.setStyles(this.innerContent,{border:"none",width:"auto",height:"auto"});var e=hs.getElementByClass(this.innerContent,"DIV","highslide-body");if(e&&!/(iframe|swf)/.test(this.objectType)){var b=e;e=hs.createElement(b.nodeName,null,{overflow:"hidden"},null,true);b.parentNode.insertBefore(e,b);e.appendChild(hs.clearing);e.appendChild(b);var c=this.innerContent.offsetWidth-e.offsetWidth;var a=this.innerContent.offsetHeight-e.offsetHeight;e.removeChild(hs.clearing);var d=hs.safari||navigator.vendor=="KDE"?1:0;hs.setStyles(e,{width:(this.x.size-c-d)+"px",height:(this.y.size-a)+"px",overflow:"auto",position:"relative"});if(d&&b.offsetHeight>e.offsetHeight){e.style.width=(parseInt(e.style.width)+d)+"px"}this.scrollingContent=e;this.scrollerDiv=this.scrollingContent}if(this.iframe&&this.objectLoadTime=="before"){this.correctIframeSize()}if(!this.scrollingContent&&this.y.size<this.mediumContent.offsetHeight){this.scrollerDiv=this.content}if(this.scrollerDiv==this.content&&!this.allowWidthReduction&&!/(iframe|swf)/.test(this.objectType)){this.x.size+=17}if(this.scrollerDiv&&this.scrollerDiv.offsetHeight>this.scrollerDiv.parentNode.offsetHeight){setTimeout("try { hs.expanders["+this.key+"].scrollerDiv.style.overflow = 'auto'; } catch(e) {}",hs.expandDuration)}},getImageMapAreaCorrection:function(d){var h=d.coords.split(",");for(var b=0;b<h.length;b++){h[b]=parseInt(h[b])}if(d.shape.toLowerCase()=="circle"){this.x.tpos+=h[0]-h[2];this.y.tpos+=h[1]-h[2];this.x.t=this.y.t=2*h[2]}else{var f,e,a=f=h[0],g=e=h[1];for(var b=0;b<h.length;b++){if(b%2==0){a=Math.min(a,h[b]);f=Math.max(f,h[b])}else{g=Math.min(g,h[b]);e=Math.max(e,h[b])}}this.x.tpos+=a;this.x.t=f-a;this.y.tpos+=g;this.y.t=e-g}},justify:function(f,b){var g,h=f.target,e=f==this.x?"x":"y";if(h&&h.match(/ /)){g=h.split(" ");h=g[0]}if(h&&hs.$(h)){f.pos=hs.getPosition(hs.$(h))[e];if(g&&g[1]&&g[1].match(/^[-]?[0-9]+px$/)){f.pos+=parseInt(g[1])}if(f.size<f.minSize){f.size=f.minSize}}else{if(f.justify=="auto"||f.justify=="center"){var d=false;var a=f.exp.allowSizeReduction;if(f.justify=="center"){f.pos=Math.round(f.scroll+(f.clientSize+f.marginMin-f.marginMax-f.get("wsize"))/2)}else{f.pos=Math.round(f.pos-((f.get("wsize")-f.t)/2))}if(f.pos<f.scroll+f.marginMin){f.pos=f.scroll+f.marginMin;d=true}if(!b&&f.size<f.minSize){f.size=f.minSize;a=false}if(f.pos+f.get("wsize")>f.scroll+f.clientSize-f.marginMax){if(!b&&d&&a){f.size=Math.min(f.size,f.get(e=="y"?"fitsize":"maxsize"))}else{if(f.get("wsize")<f.get("fitsize")){f.pos=f.scroll+f.clientSize-f.marginMax-f.get("wsize")}else{f.pos=f.scroll+f.marginMin;if(!b&&a){f.size=f.get(e=="y"?"fitsize":"maxsize")}}}}if(!b&&f.size<f.minSize){f.size=f.minSize;a=false}}else{if(f.justify=="max"){f.pos=Math.floor(f.pos-f.size+f.t)}}}if(f.pos<f.marginMin){var c=f.pos;f.pos=f.marginMin;if(a&&!b){f.size=f.size-(f.pos-c)}}},correctRatio:function(c){var a=this.x,g=this.y,e=false,d=Math.min(a.full,a.size),b=Math.min(g.full,g.size),f=(this.useBox||hs.padToMinWidth);if(d/b>c){d=b*c;if(d<a.minSize){d=a.minSize;b=d/c}e=true}else{if(d/b<c){b=d/c;e=true}}if(hs.padToMinWidth&&a.full<a.minSize){a.imgSize=a.full;g.size=g.imgSize=g.full}else{if(this.useBox){a.imgSize=d;g.imgSize=b}else{a.size=d;g.size=b}}e=this.fitOverlayBox(this.useBox?null:c,e);if(f&&g.size<g.imgSize){g.imgSize=g.size;a.imgSize=g.size*c}if(e||f){a.pos=a.tpos-a.cb+a.tb;a.minSize=a.size;this.justify(a,true);g.pos=g.tpos-g.cb+g.tb;g.minSize=g.size;this.justify(g,true);if(this.overlayBox){this.sizeOverlayBox()}}},fitOverlayBox:function(b,c){var a=this.x,d=this.y;if(this.overlayBox&&(this.isImage||this.allowHeightReduction)){while(d.size>this.minHeight&&a.size>this.minWidth&&d.get("wsize")>d.get("fitsize")){d.size-=10;if(b){a.size=d.size*b}this.sizeOverlayBox(0,1);c=true}}return c},reflow:function(){if(this.scrollerDiv){var a=/iframe/i.test(this.scrollerDiv.tagName)?(this.getIframePageHeight()+1)+"px":"auto";if(this.body){this.body.style.height=a}this.scrollerDiv.style.height=a;this.y.setSize(this.innerContent.offsetHeight)}},show:function(){var a=this.x,b=this.y;this.doShowHide("hidden");hs.fireEvent(this,"onBeforeExpand");if(this.slideshow&&this.slideshow.thumbstrip){this.slideshow.thumbstrip.selectThumb()}this.changeSize(1,{wrapper:{width:a.get("wsize"),height:b.get("wsize"),left:a.pos,top:b.pos},content:{left:a.p1+a.get("imgPad"),top:b.p1+b.get("imgPad"),width:a.imgSize||a.size,height:b.imgSize||b.size}},hs.expandDuration)},changeSize:function(d,i,b){var k=this.transitions,e=d?(this.last?this.last.a:null):hs.upcoming,j=(k[1]&&e&&hs.getParam(e,"transitions")[1]==k[1])?k[1]:k[0];if(this[j]&&j!="expand"){this[j](d,i);return}if(this.outline&&!this.outlineWhileAnimating){if(d){this.outline.setPosition()}else{this.outline.destroy((this.isHtml&&this.preserveContent))}}if(!d){this.destroyOverlays()}var c=this,h=c.x,g=c.y,f=this.easing;if(!d){f=this.easingClose||f}var a=d?function(){if(c.outline){c.outline.table.style.visibility="visible"}setTimeout(function(){c.afterExpand()},50)}:function(){c.afterClose()};if(d){hs.setStyles(this.wrapper,{width:h.t+"px",height:g.t+"px"})}if(d&&this.isHtml){hs.setStyles(this.wrapper,{left:(h.tpos-h.cb+h.tb)+"px",top:(g.tpos-g.cb+g.tb)+"px"})}if(this.fadeInOut){hs.setStyles(this.wrapper,{opacity:d?0:1});hs.extend(i.wrapper,{opacity:d})}hs.animate(this.wrapper,i.wrapper,{duration:b,easing:f,step:function(n,l){if(c.outline&&c.outlineWhileAnimating&&l.prop=="top"){var m=d?l.pos:1-l.pos;var o={w:h.t+(h.get("wsize")-h.t)*m,h:g.t+(g.get("wsize")-g.t)*m,x:h.tpos+(h.pos-h.tpos)*m,y:g.tpos+(g.pos-g.tpos)*m};c.outline.setPosition(o,0,1)}if(c.isHtml){if(l.prop=="left"){c.mediumContent.style.left=(h.pos-n)+"px"}if(l.prop=="top"){c.mediumContent.style.top=(g.pos-n)+"px"}}}});hs.animate(this.content,i.content,b,f,a);if(d){this.wrapper.style.visibility="visible";this.content.style.visibility="visible";if(this.isHtml){this.innerContent.style.visibility="visible"}this.a.className+=" highslide-active-anchor"}},fade:function(f,h){this.outlineWhileAnimating=false;var c=this,j=f?hs.expandDuration:0;if(f){hs.animate(this.wrapper,h.wrapper,0);hs.setStyles(this.wrapper,{opacity:0,visibility:"visible"});hs.animate(this.content,h.content,0);this.content.style.visibility="visible";hs.animate(this.wrapper,{opacity:1},j,null,function(){c.afterExpand()})}if(this.outline){this.outline.table.style.zIndex=this.wrapper.style.zIndex;var b=f||-1,d=this.outline.offset,a=f?3:d,g=f?d:3;for(var e=a;b*e<=b*g;e+=b,j+=25){(function(){var i=f?g-e:a-e;setTimeout(function(){c.outline.setPosition(0,i,1)},j)})()}}if(f){}else{setTimeout(function(){if(c.outline){c.outline.destroy(c.preserveContent)}c.destroyOverlays();hs.animate(c.wrapper,{opacity:0},hs.restoreDuration,null,function(){c.afterClose()})},j)}},crossfade:function(g,m,o){if(!g){return}var f=this,p=this.last,l=this.x,k=this.y,d=p.x,b=p.y,a=this.wrapper,i=this.content,c=this.overlayBox;hs.removeEventListener(document,"mousemove",hs.dragHandler);hs.setStyles(i,{width:(l.imgSize||l.size)+"px",height:(k.imgSize||k.size)+"px"});if(c){c.style.overflow="visible"}this.outline=p.outline;if(this.outline){this.outline.exp=f}p.outline=null;var h=hs.createElement("div",{className:"highslide-"+this.contentType},{position:"absolute",zIndex:4,overflow:"hidden",display:"none"});var j={oldImg:p,newImg:this};for(var e in j){this[e]=j[e].content.cloneNode(1);hs.setStyles(this[e],{position:"absolute",border:0,visibility:"visible"});h.appendChild(this[e])}a.appendChild(h);if(this.isHtml){hs.setStyles(this.mediumContent,{left:0,top:0})}if(c){c.className="";a.appendChild(c)}h.style.display="";p.content.style.display="none";if(hs.safari&&hs.uaVersion<525){this.wrapper.style.visibility="visible"}hs.animate(a,{width:l.size},{duration:hs.transitionDuration,step:function(u,r){var x=r.pos,q=1-x;var w,s={},t=["pos","size","p1","p2"];for(var v in t){w=t[v];s["x"+w]=Math.round(q*d[w]+x*l[w]);s["y"+w]=Math.round(q*b[w]+x*k[w]);s.ximgSize=Math.round(q*(d.imgSize||d.size)+x*(l.imgSize||l.size));s.ximgPad=Math.round(q*d.get("imgPad")+x*l.get("imgPad"));s.yimgSize=Math.round(q*(b.imgSize||b.size)+x*(k.imgSize||k.size));s.yimgPad=Math.round(q*b.get("imgPad")+x*k.get("imgPad"))}if(f.outline){f.outline.setPosition({x:s.xpos,y:s.ypos,w:s.xsize+s.xp1+s.xp2+2*l.cb,h:s.ysize+s.yp1+s.yp2+2*k.cb})}p.wrapper.style.clip="rect("+(s.ypos-b.pos)+"px, "+(s.xsize+s.xp1+s.xp2+s.xpos+2*d.cb-d.pos)+"px, "+(s.ysize+s.yp1+s.yp2+s.ypos+2*b.cb-b.pos)+"px, "+(s.xpos-d.pos)+"px)";hs.setStyles(i,{top:(s.yp1+k.get("imgPad"))+"px",left:(s.xp1+l.get("imgPad"))+"px",marginTop:(k.pos-s.ypos)+"px",marginLeft:(l.pos-s.xpos)+"px"});hs.setStyles(a,{top:s.ypos+"px",left:s.xpos+"px",width:(s.xp1+s.xp2+s.xsize+2*l.cb)+"px",height:(s.yp1+s.yp2+s.ysize+2*k.cb)+"px"});hs.setStyles(h,{width:(s.ximgSize||s.xsize)+"px",height:(s.yimgSize||s.ysize)+"px",left:(s.xp1+s.ximgPad)+"px",top:(s.yp1+s.yimgPad)+"px",visibility:"visible"});hs.setStyles(f.oldImg,{top:(b.pos-s.ypos+b.p1-s.yp1+b.get("imgPad")-s.yimgPad)+"px",left:(d.pos-s.xpos+d.p1-s.xp1+d.get("imgPad")-s.ximgPad)+"px"});hs.setStyles(f.newImg,{opacity:x,top:(k.pos-s.ypos+k.p1-s.yp1+k.get("imgPad")-s.yimgPad)+"px",left:(l.pos-s.xpos+l.p1-s.xp1+l.get("imgPad")-s.ximgPad)+"px"});if(c){hs.setStyles(c,{width:s.xsize+"px",height:s.ysize+"px",left:(s.xp1+l.cb)+"px",top:(s.yp1+k.cb)+"px"})}},complete:function(){a.style.visibility=i.style.visibility="visible";i.style.display="block";hs.discardElement(h);f.afterExpand();p.afterClose();f.last=null}})},reuseOverlay:function(d,c){if(!this.last){return false}for(var b=0;b<this.last.overlays.length;b++){var a=hs.$("hsId"+this.last.overlays[b]);if(a&&a.hsId==d.hsId){this.genOverlayBox();a.reuse=this.key;hs.push(this.overlays,this.last.overlays[b]);return true}}return false},afterExpand:function(){this.isExpanded=true;this.focus();if(this.isHtml&&this.objectLoadTime=="after"){this.writeExtendedContent()}if(this.iframe){try{var g=this,f=this.iframe.contentDocument||this.iframe.contentWindow.document;hs.addEventListener(f,"mousedown",function(){if(hs.focusKey!=g.key){g.focus()}})}catch(d){}if(hs.ie&&typeof this.isClosing!="boolean"){this.iframe.style.width=(this.objectWidth-1)+"px"}}if(this.dimmingOpacity){hs.dim(this)}if(hs.upcoming&&hs.upcoming==this.a){hs.upcoming=null}this.prepareNextOutline();var c=hs.page,b=hs.mouse.x+c.scrollLeft,a=hs.mouse.y+c.scrollTop;this.mouseIsOver=this.x.pos<b&&b<this.x.pos+this.x.get("wsize")&&this.y.pos<a&&a<this.y.pos+this.y.get("wsize");if(this.overlayBox){this.showOverlays()}hs.fireEvent(this,"onAfterExpand")},prepareNextOutline:function(){var a=this.key;var b=this.outlineType;new hs.Outline(b,function(){try{hs.expanders[a].preloadNext()}catch(c){}})},preloadNext:function(){var b=this.getAdjacentAnchor(1);if(b&&b.onclick.toString().match(/hs\.expand/)){var a=hs.createElement("img",{src:hs.getSrc(b)})}},getAdjacentAnchor:function(c){var b=this.getAnchorIndex(),a=hs.anchors.groups[this.slideshowGroup||"none"];if(a&&!a[b+c]&&this.slideshow&&this.slideshow.repeat){if(c==1){return a[0]}else{if(c==-1){return a[a.length-1]}}}return(a&&a[b+c])||null},getAnchorIndex:function(){var a=hs.getAnchors().groups[this.slideshowGroup||"none"];if(a){for(var b=0;b<a.length;b++){if(a[b]==this.a){return b}}}return null},getNumber:function(){if(this[this.numberPosition]){var a=hs.anchors.groups[this.slideshowGroup||"none"];if(a){var b=hs.lang.number.replace("%1",this.getAnchorIndex()+1).replace("%2",a.length);this[this.numberPosition].innerHTML='<div class="highslide-number">'+b+"</div>"+this[this.numberPosition].innerHTML}}},initSlideshow:function(){if(!this.last){for(var c=0;c<hs.slideshows.length;c++){var b=hs.slideshows[c],d=b.slideshowGroup;if(typeof d=="undefined"||d===null||d===this.slideshowGroup){this.slideshow=new hs.Slideshow(this.key,b)}}}else{this.slideshow=this.last.slideshow}var b=this.slideshow;if(!b){return}var a=b.expKey=this.key;b.checkFirstAndLast();b.disable("full-expand");if(b.controls){this.createOverlay(hs.extend(b.overlayOptions||{},{overlayId:b.controls,hsId:"controls",zIndex:5}))}if(b.thumbstrip){b.thumbstrip.add(this)}if(!this.last&&this.autoplay){b.play(true)}if(b.autoplay){b.autoplay=setTimeout(function(){hs.next(a)},(b.interval||500))}},cancelLoading:function(){hs.discardElement(this.wrapper);hs.expanders[this.key]=null;if(hs.upcoming==this.a){hs.upcoming=null}hs.undim(this.key);if(this.loading){hs.loading.style.left="-9999px"}hs.fireEvent(this,"onHideLoading")},writeCredits:function(){if(this.credits){return}this.credits=hs.createElement("a",{href:hs.creditsHref,target:hs.creditsTarget,className:"highslide-credits",innerHTML:hs.lang.creditsText,title:hs.lang.creditsTitle});this.createOverlay({overlayId:this.credits,position:this.creditsPosition||"top left",hsId:"credits"})},getInline:function(types,addOverlay){for(var i=0;i<types.length;i++){var type=types[i],s=null;if(type=="caption"&&!hs.fireEvent(this,"onBeforeGetCaption")){return}else{if(type=="heading"&&!hs.fireEvent(this,"onBeforeGetHeading")){return}}if(!this[type+"Id"]&&this.thumbsUserSetId){this[type+"Id"]=type+"-for-"+this.thumbsUserSetId}if(this[type+"Id"]){this[type]=hs.getNode(this[type+"Id"])}if(!this[type]&&!this[type+"Text"]&&this[type+"Eval"]){try{s=eval(this[type+"Eval"])}catch(e){}}if(!this[type]&&this[type+"Text"]){s=this[type+"Text"]}if(!this[type]&&!s){this[type]=hs.getNode(this.a["_"+type+"Id"]);if(!this[type]){var next=this.a.nextSibling;while(next&&!hs.isHsAnchor(next)){if((new RegExp("highslide-"+type)).test(next.className||null)){if(!next.id){this.a["_"+type+"Id"]=next.id="hsId"+hs.idCounter++}this[type]=hs.getNode(next.id);break}next=next.nextSibling}}}if(!this[type]&&!s&&this.numberPosition==type){s="\n"}if(!this[type]&&s){this[type]=hs.createElement("div",{className:"highslide-"+type,innerHTML:s})}if(addOverlay&&this[type]){var o={position:(type=="heading")?"above":"below"};for(var x in this[type+"Overlay"]){o[x]=this[type+"Overlay"][x]}o.overlayId=this[type];this.createOverlay(o)}}},doShowHide:function(a){if(hs.hideSelects){this.showHideElements("SELECT",a)}if(hs.hideIframes){this.showHideElements("IFRAME",a)}if(hs.geckoMac){this.showHideElements("*",a)}},showHideElements:function(c,b){var e=document.getElementsByTagName(c);var a=c=="*"?"overflow":"visibility";for(var f=0;f<e.length;f++){if(a=="visibility"||(document.defaultView.getComputedStyle(e[f],"").getPropertyValue("overflow")=="auto"||e[f].getAttribute("hidden-by")!=null)){var h=e[f].getAttribute("hidden-by");if(b=="visible"&&h){h=h.replace("["+this.key+"]","");e[f].setAttribute("hidden-by",h);if(!h){e[f].style[a]=e[f].origProp}}else{if(b=="hidden"){var k=hs.getPosition(e[f]);k.w=e[f].offsetWidth;k.h=e[f].offsetHeight;if(!this.dimmingOpacity){var j=(k.x+k.w<this.x.get("opos")||k.x>this.x.get("opos")+this.x.get("osize"));var g=(k.y+k.h<this.y.get("opos")||k.y>this.y.get("opos")+this.y.get("osize"))}var d=hs.getWrapperKey(e[f]);if(!j&&!g&&d!=this.key){if(!h){e[f].setAttribute("hidden-by","["+this.key+"]");e[f].origProp=e[f].style[a];e[f].style[a]="hidden"}else{if(h.indexOf("["+this.key+"]")==-1){e[f].setAttribute("hidden-by",h+"["+this.key+"]")}}}else{if((h=="["+this.key+"]"||hs.focusKey==d)&&d!=this.key){e[f].setAttribute("hidden-by","");e[f].style[a]=e[f].origProp||""}else{if(h&&h.indexOf("["+this.key+"]")>-1){e[f].setAttribute("hidden-by",h.replace("["+this.key+"]",""))}}}}}}}},focus:function(){this.wrapper.style.zIndex=hs.zIndexCounter+=2;for(var a=0;a<hs.expanders.length;a++){if(hs.expanders[a]&&a==hs.focusKey){var b=hs.expanders[a];b.content.className+=" highslide-"+b.contentType+"-blur";if(b.isImage){b.content.style.cursor=hs.ieLt7?"hand":"pointer";b.content.title=hs.lang.focusTitle}hs.fireEvent(b,"onBlur")}}if(this.outline){this.outline.table.style.zIndex=this.wrapper.style.zIndex-1}this.content.className="highslide-"+this.contentType;if(this.isImage){this.content.title=hs.lang.restoreTitle;if(hs.restoreCursor){hs.styleRestoreCursor=window.opera?"pointer":"url("+hs.graphicsDir+hs.restoreCursor+"), pointer";if(hs.ieLt7&&hs.uaVersion<6){hs.styleRestoreCursor="hand"}this.content.style.cursor=hs.styleRestoreCursor}}hs.focusKey=this.key;hs.addEventListener(document,window.opera?"keypress":"keydown",hs.keyHandler);hs.fireEvent(this,"onFocus")},moveTo:function(a,b){this.x.setPos(a);this.y.setPos(b)},resize:function(d){var a,b,c=d.width/d.height;a=Math.max(d.width+d.dX,Math.min(this.minWidth,this.x.full));if(this.isImage&&Math.abs(a-this.x.full)<12){a=this.x.full}b=this.isHtml?d.height+d.dY:a/c;if(b<Math.min(this.minHeight,this.y.full)){b=Math.min(this.minHeight,this.y.full);if(this.isImage){a=b*c}}this.resizeTo(a,b)},resizeTo:function(a,b){this.y.setSize(b);this.x.setSize(a);this.wrapper.style.height=this.y.get("wsize")+"px"},close:function(){if(this.isClosing||!this.isExpanded){return}if(this.transitions[1]=="crossfade"&&hs.upcoming){hs.getExpander(hs.upcoming).cancelLoading();hs.upcoming=null}if(!hs.fireEvent(this,"onBeforeClose")){return}this.isClosing=true;if(this.slideshow&&!hs.upcoming){this.slideshow.pause()}hs.removeEventListener(document,window.opera?"keypress":"keydown",hs.keyHandler);try{if(this.isHtml){this.htmlPrepareClose()}this.content.style.cursor="default";this.changeSize(0,{wrapper:{width:this.x.t,height:this.y.t,left:this.x.tpos-this.x.cb+this.x.tb,top:this.y.tpos-this.y.cb+this.y.tb},content:{left:0,top:0,width:this.x.t,height:this.y.t}},hs.restoreDuration)}catch(a){this.afterClose()}},htmlPrepareClose:function(){if(hs.geckoMac){if(!hs.mask){hs.mask=hs.createElement("div",null,{position:"absolute"},hs.container)}hs.setStyles(hs.mask,{width:this.x.size+"px",height:this.y.size+"px",left:this.x.pos+"px",top:this.y.pos+"px",display:"block"})}if(this.objectType=="swf"){try{hs.$(this.body.id).StopPlay()}catch(a){}}if(this.objectLoadTime=="after"&&!this.preserveContent){this.destroyObject()}if(this.scrollerDiv&&this.scrollerDiv!=this.scrollingContent){this.scrollerDiv.style.overflow="hidden"}},destroyObject:function(){if(hs.ie&&this.iframe){try{this.iframe.contentWindow.document.body.innerHTML=""}catch(a){}}if(this.objectType=="swf"){swfobject.removeSWF(this.body.id)}this.body.innerHTML=""},sleep:function(){if(this.outline){this.outline.table.style.display="none"}this.releaseMask=null;this.wrapper.style.display="none";this.isExpanded=false;hs.push(hs.sleeping,this)},awake:function(){try{hs.expanders[this.key]=this;if(!hs.allowMultipleInstances&&hs.focusKey!=this.key){try{hs.expanders[hs.focusKey].close()}catch(b){}}var d=hs.zIndexCounter++,a={display:"",zIndex:d};hs.setStyles(this.wrapper,a);this.isClosing=false;var c=this.outline||0;if(c){if(!this.outlineWhileAnimating){a.visibility="hidden"}hs.setStyles(c.table,a)}if(this.slideshow){this.initSlideshow()}this.show()}catch(b){}},createOverlay:function(e){var d=e.overlayId,a=(e.relativeTo=="viewport"&&!/panel$/.test(e.position));if(typeof d=="string"){d=hs.getNode(d)}if(e.html){d=hs.createElement("div",{innerHTML:e.html})}if(!d||typeof d=="string"){return}if(!hs.fireEvent(this,"onCreateOverlay",{overlay:d})){return}d.style.display="block";e.hsId=e.hsId||e.overlayId;if(this.transitions[1]=="crossfade"&&this.reuseOverlay(e,d)){return}this.genOverlayBox();var c=e.width&&/^[0-9]+(px|%)$/.test(e.width)?e.width:"auto";if(/^(left|right)panel$/.test(e.position)&&!/^[0-9]+px$/.test(e.width)){c="200px"}var b=hs.createElement("div",{id:"hsId"+hs.idCounter++,hsId:e.hsId},{position:"absolute",visibility:"hidden",width:c,direction:hs.lang.cssDirection||"",opacity:0},a?hs.viewport:this.overlayBox,true);if(a){b.hsKey=this.key}b.appendChild(d);hs.extend(b,{opacity:1,offsetX:0,offsetY:0,dur:(e.fade===0||e.fade===false||(e.fade==2&&hs.ie))?0:250});hs.extend(b,e);if(this.gotOverlays){this.positionOverlay(b);if(!b.hideOnMouseOut||this.mouseIsOver){hs.animate(b,{opacity:b.opacity},b.dur)}}hs.push(this.overlays,hs.idCounter-1)},positionOverlay:function(e){var f=e.position||"middle center",c=(e.relativeTo=="viewport"),b=e.offsetX,a=e.offsetY;if(c){hs.viewport.style.display="block";e.hsKey=this.key;if(e.offsetWidth>e.parentNode.offsetWidth){e.style.width="100%"}}else{if(e.parentNode!=this.overlayBox){this.overlayBox.appendChild(e)}}if(/left$/.test(f)){e.style.left=b+"px"}if(/center$/.test(f)){hs.setStyles(e,{left:"50%",marginLeft:(b-Math.round(e.offsetWidth/2))+"px"})}if(/right$/.test(f)){e.style.right=-b+"px"}if(/^leftpanel$/.test(f)){hs.setStyles(e,{right:"100%",marginRight:this.x.cb+"px",top:-this.y.cb+"px",bottom:-this.y.cb+"px",overflow:"auto"});this.x.p1=e.offsetWidth}else{if(/^rightpanel$/.test(f)){hs.setStyles(e,{left:"100%",marginLeft:this.x.cb+"px",top:-this.y.cb+"px",bottom:-this.y.cb+"px",overflow:"auto"});this.x.p2=e.offsetWidth}}var d=e.parentNode.offsetHeight;e.style.height="auto";if(c&&e.offsetHeight>d){e.style.height=hs.ieLt7?d+"px":"100%"}if(/^top/.test(f)){e.style.top=a+"px"}if(/^middle/.test(f)){hs.setStyles(e,{top:"50%",marginTop:(a-Math.round(e.offsetHeight/2))+"px"})}if(/^bottom/.test(f)){e.style.bottom=-a+"px"}if(/^above$/.test(f)){hs.setStyles(e,{left:(-this.x.p1-this.x.cb)+"px",right:(-this.x.p2-this.x.cb)+"px",bottom:"100%",marginBottom:this.y.cb+"px",width:"auto"});this.y.p1=e.offsetHeight}else{if(/^below$/.test(f)){hs.setStyles(e,{position:"relative",left:(-this.x.p1-this.x.cb)+"px",right:(-this.x.p2-this.x.cb)+"px",top:"100%",marginTop:this.y.cb+"px",width:"auto"});this.y.p2=e.offsetHeight;e.style.position="absolute"}}},getOverlays:function(){this.getInline(["heading","caption"],true);this.getNumber();if(this.caption){hs.fireEvent(this,"onAfterGetCaption")}if(this.heading){hs.fireEvent(this,"onAfterGetHeading")}if(this.heading&&this.dragByHeading){this.heading.className+=" highslide-move"}if(hs.showCredits){this.writeCredits()}for(var a=0;a<hs.overlays.length;a++){var d=hs.overlays[a],e=d.thumbnailId,b=d.slideshowGroup;if((!e&&!b)||(e&&e==this.thumbsUserSetId)||(b&&b===this.slideshowGroup)){if(this.isImage||(this.isHtml&&d.useOnHtml)){this.createOverlay(d)}}}var c=[];for(var a=0;a<this.overlays.length;a++){var d=hs.$("hsId"+this.overlays[a]);if(/panel$/.test(d.position)){this.positionOverlay(d)}else{hs.push(c,d)}}for(var a=0;a<c.length;a++){this.positionOverlay(c[a])}this.gotOverlays=true},genOverlayBox:function(){if(!this.overlayBox){this.overlayBox=hs.createElement("div",{className:this.wrapperClassName},{position:"absolute",width:(this.x.size||(this.useBox?this.width:null)||this.x.full)+"px",height:(this.y.size||this.y.full)+"px",visibility:"hidden",overflow:"hidden",zIndex:hs.ie?4:"auto"},hs.container,true)}},sizeOverlayBox:function(f,d){var c=this.overlayBox,a=this.x,h=this.y;hs.setStyles(c,{width:a.size+"px",height:h.size+"px"});if(f||d){for(var e=0;e<this.overlays.length;e++){var g=hs.$("hsId"+this.overlays[e]);var b=(hs.ieLt7||document.compatMode=="BackCompat");if(g&&/^(above|below)$/.test(g.position)){if(b){g.style.width=(c.offsetWidth+2*a.cb+a.p1+a.p2)+"px"}h[g.position=="above"?"p1":"p2"]=g.offsetHeight}if(g&&b&&/^(left|right)panel$/.test(g.position)){g.style.height=(c.offsetHeight+2*h.cb)+"px"}}}if(f){hs.setStyles(this.content,{top:h.p1+"px"});hs.setStyles(c,{top:(h.p1+h.cb)+"px"})}},showOverlays:function(){var a=this.overlayBox;a.className="";hs.setStyles(a,{top:(this.y.p1+this.y.cb)+"px",left:(this.x.p1+this.x.cb)+"px",overflow:"visible"});if(hs.safari){a.style.visibility="visible"}this.wrapper.appendChild(a);for(var c=0;c<this.overlays.length;c++){var d=hs.$("hsId"+this.overlays[c]);d.style.zIndex=d.zIndex||4;if(!d.hideOnMouseOut||this.mouseIsOver){d.style.visibility="visible";hs.setStyles(d,{visibility:"visible",display:""});hs.animate(d,{opacity:d.opacity},d.dur)}}},destroyOverlays:function(){if(!this.overlays.length){return}if(this.slideshow){var d=this.slideshow.controls;if(d&&hs.getExpander(d)==this){d.parentNode.removeChild(d)}}for(var a=0;a<this.overlays.length;a++){var b=hs.$("hsId"+this.overlays[a]);if(b&&b.parentNode==hs.viewport&&hs.getExpander(b)==this){hs.discardElement(b)}}if(this.isHtml&&this.preserveContent){this.overlayBox.style.top="-9999px";hs.container.appendChild(this.overlayBox)}else{hs.discardElement(this.overlayBox)}},createFullExpand:function(){if(this.slideshow&&this.slideshow.controls){this.slideshow.enable("full-expand");return}this.fullExpandLabel=hs.createElement("a",{href:"javascript:hs.expanders["+this.key+"].doFullExpand();",title:hs.lang.fullExpandTitle,className:"highslide-full-expand"});if(!hs.fireEvent(this,"onCreateFullExpand")){return}this.createOverlay({overlayId:this.fullExpandLabel,position:hs.fullExpandPosition,hideOnMouseOut:true,opacity:hs.fullExpandOpacity})},doFullExpand:function(){try{if(!hs.fireEvent(this,"onDoFullExpand")){return}if(this.fullExpandLabel){hs.discardElement(this.fullExpandLabel)}this.focus();var b=this.x.size;this.resizeTo(this.x.full,this.y.full);var a=this.x.pos-(this.x.size-b)/2;if(a<hs.marginLeft){a=hs.marginLeft}this.moveTo(a,this.y.pos);this.doShowHide("hidden")}catch(c){this.error(c)}},afterClose:function(){this.a.className=this.a.className.replace("highslide-active-anchor","");this.doShowHide("visible");if(this.isHtml&&this.preserveContent&&this.transitions[1]!="crossfade"){this.sleep()}else{if(this.outline&&this.outlineWhileAnimating){this.outline.destroy()}hs.discardElement(this.wrapper)}if(hs.mask){hs.mask.style.display="none"}this.destroyOverlays();if(!hs.viewport.childNodes.length){hs.viewport.style.display="none"}if(this.dimmingOpacity){hs.undim(this.key)}hs.fireEvent(this,"onAfterClose");hs.expanders[this.key]=null;hs.reOrder()}};hs.Ajax=function(b,c,d){this.a=b;this.content=c;this.pre=d};hs.Ajax.prototype={run:function(){var d;if(!this.src){this.src=hs.getSrc(this.a)}if(this.src.match("#")){var a=this.src.split("#");this.src=a[0];this.id=a[1]}if(hs.cachedGets[this.src]){this.cachedGet=hs.cachedGets[this.src];if(this.id){this.getElementContent()}else{this.loadHTML()}return}try{d=new XMLHttpRequest()}catch(b){try{d=new ActiveXObject("Msxml2.XMLHTTP")}catch(b){try{d=new ActiveXObject("Microsoft.XMLHTTP")}catch(b){this.onError()}}}var f=this;d.onreadystatechange=function(){if(f.xhr.readyState==4){if(f.id){f.getElementContent()}else{f.loadHTML()}}};var c=this.src;this.xhr=d;if(hs.forceAjaxReload){c=c.replace(/$/,(/\?/.test(c)?"&":"?")+"dummy="+(new Date()).getTime())}d.open("GET",c,true);d.setRequestHeader("X-Requested-With","XMLHttpRequest");d.setRequestHeader("Content-Type","application/x-www-form-urlencoded");d.send(null)},getElementContent:function(){hs.init();var a=window.opera||hs.ie6SSL?{src:"about:blank"}:null;this.iframe=hs.createElement("iframe",a,{position:"absolute",top:"-9999px"},hs.container);this.loadHTML()},loadHTML:function(){var c=this.cachedGet||this.xhr.responseText,b;if(this.pre){hs.cachedGets[this.src]=c}if(!hs.ie||hs.uaVersion>=5.5){c=c.replace(new RegExp("<link[^>]*>","gi"),"").replace(new RegExp("<script[^>]*>.*?<\/script>","gi"),"");if(this.iframe){var f=this.iframe.contentDocument;if(!f&&this.iframe.contentWindow){f=this.iframe.contentWindow.document}if(!f){var g=this;setTimeout(function(){g.loadHTML()},25);return}f.open();f.write(c);f.close();try{c=f.getElementById(this.id).innerHTML}catch(d){try{c=this.iframe.document.getElementById(this.id).innerHTML}catch(d){}}hs.discardElement(this.iframe)}else{b=/(<body[^>]*>|<\/body>)/ig;if(b.test(c)){c=c.split(b)[hs.ieLt9?1:2]}}}hs.getElementByClass(this.content,"DIV","highslide-body").innerHTML=c;this.onLoad();for(var a in this){this[a]=null}}};hs.Slideshow=function(c,b){if(hs.dynamicallyUpdateAnchors!==false){hs.updateAnchors()}this.expKey=c;for(var a in b){this[a]=b[a]}if(this.useControls){this.getControls()}if(this.thumbstrip){this.thumbstrip=hs.Thumbstrip(this)}};hs.Slideshow.prototype={getControls:function(){this.controls=hs.createElement("div",{innerHTML:hs.replaceLang(hs.skin.controls)},null,hs.container);var b=["play","pause","previous","next","move","full-expand","close"];this.btn={};var c=this;for(var a=0;a<b.length;a++){this.btn[b[a]]=hs.getElementByClass(this.controls,"li","highslide-"+b[a]);this.enable(b[a])}this.btn.pause.style.display="none"},checkFirstAndLast:function(){if(this.repeat||!this.controls){return}var c=hs.expanders[this.expKey],b=c.getAnchorIndex(),a=/disabled$/;if(b==0){this.disable("previous")}else{if(a.test(this.btn.previous.getElementsByTagName("a")[0].className)){this.enable("previous")}}if(b+1==hs.anchors.groups[c.slideshowGroup||"none"].length){this.disable("next");this.disable("play")}else{if(a.test(this.btn.next.getElementsByTagName("a")[0].className)){this.enable("next");this.enable("play")}}},enable:function(d){if(!this.btn){return}var c=this,b=this.btn[d].getElementsByTagName("a")[0],e=/disabled$/;b.onclick=function(){c[d]();return false};if(e.test(b.className)){b.className=b.className.replace(e,"")}},disable:function(c){if(!this.btn){return}var b=this.btn[c].getElementsByTagName("a")[0];b.onclick=function(){return false};if(!/disabled$/.test(b.className)){b.className+=" disabled"}},hitSpace:function(){if(this.autoplay){this.pause()}else{this.play()}},play:function(a){if(this.btn){this.btn.play.style.display="none";this.btn.pause.style.display=""}this.autoplay=true;if(!a){hs.next(this.expKey)}},pause:function(){if(this.btn){this.btn.pause.style.display="none";this.btn.play.style.display=""}clearTimeout(this.autoplay);this.autoplay=null},previous:function(){this.pause();hs.previous(this.btn.previous)},next:function(){this.pause();hs.next(this.btn.next)},move:function(){},"full-expand":function(){hs.getExpander().doFullExpand()},close:function(){hs.close(this.btn.close)}};hs.Thumbstrip=function(k){function p(i){hs.extend(f||{},{overlayId:r,hsId:"thumbstrip",className:"highslide-thumbstrip-"+m+"-overlay "+(f.className||"")});if(hs.ieLt7){f.fade=0}i.createOverlay(f);hs.setStyles(r.parentNode,{overflow:"hidden"})}function c(i){d(undefined,Math.round(i*r[h?"offsetWidth":"offsetHeight"]*0.7))}function d(L,M){if(L===undefined){for(var K=0;K<j.length;K++){if(j[K]==hs.expanders[k.expKey].a){L=K;break}}}if(L===undefined){return}var G=r.getElementsByTagName("a"),z=G[L],w=z.parentNode,y=h?"Left":"Top",N=h?"Right":"Bottom",I=h?"Width":"Height",B="offset"+y,H="offset"+I,x=n.parentNode.parentNode[H],F=x-s[H],v=parseInt(s.style[h?"left":"top"])||0,C=v,D=20;if(M!==undefined){C=v-M;if(F>0){F=0}if(C>0){C=0}if(C<F){C=F}}else{for(var K=0;K<G.length;K++){G[K].className=""}z.className="highslide-active-anchor";var J=L>0?G[L-1].parentNode[B]:w[B],A=w[B]+w[H]+(G[L+1]?G[L+1].parentNode[H]:0);if(A>x-v){C=x-A}else{if(J<-v){C=-J}}}var E=w[B]+(w[H]-g[H])/2+C;hs.animate(s,h?{left:C}:{top:C},null,"easeOutQuad");hs.animate(g,h?{left:E}:{top:E},null,"easeOutQuad");l.style.display=C<0?"block":"none";t.style.display=(C>F)?"block":"none"}var j=hs.anchors.groups[hs.expanders[k.expKey].slideshowGroup||"none"],f=k.thumbstrip,m=f.mode||"horizontal",u=(m=="float"),o=u?["div","ul","li","span"]:["table","tbody","tr","td"],h=(m=="horizontal"),r=hs.createElement("div",{className:"highslide-thumbstrip highslide-thumbstrip-"+m,innerHTML:'<div class="highslide-thumbstrip-inner"><'+o[0]+"><"+o[1]+"></"+o[1]+"></"+o[0]+'></div><div class="highslide-scroll-up"><div></div></div><div class="highslide-scroll-down"><div></div></div><div class="highslide-marker"><div></div></div>'},{display:"none"},hs.container),e=r.childNodes,n=e[0],l=e[1],t=e[2],g=e[3],s=n.firstChild,a=r.getElementsByTagName(o[1])[0],b;for(var q=0;q<j.length;q++){if(q==0||!h){b=hs.createElement(o[2],null,null,a)}(function(){var v=j[q],i=hs.createElement(o[3],null,null,b),w=q;hs.createElement("a",{href:v.href,onclick:function(){if(/highslide-active-anchor/.test(this.className)){return false}hs.getExpander(this).focus();return hs.transit(v)},innerHTML:hs.stripItemFormatter?hs.stripItemFormatter(v):v.innerHTML},null,i)})()}if(!u){l.onclick=function(){c(-1)};t.onclick=function(){c(1)};hs.addEventListener(a,document.onmousewheel!==undefined?"mousewheel":"DOMMouseScroll",function(i){var v=0;i=i||window.event;if(i.wheelDelta){v=i.wheelDelta/120;if(hs.opera){v=-v}}else{if(i.detail){v=-i.detail/3}}if(v){c(-v*0.2)}if(i.preventDefault){i.preventDefault()}i.returnValue=false})}return{add:p,selectThumb:d}};hs.langDefaults=hs.lang;var HsExpander=hs.Expander;if(hs.ie&&window==window.top){(function(){try{document.documentElement.doScroll("left")}catch(a){setTimeout(arguments.callee,50);return}hs.ready()})()}hs.addEventListener(document,"DOMContentLoaded",hs.ready);hs.addEventListener(window,"load",hs.ready);hs.addEventListener(document,"ready",function(){if(hs.expandCursor||hs.dimmingOpacity){var c=hs.createElement("style",{type:"text/css"},null,document.getElementsByTagName("HEAD")[0]);function b(e,f){if(hs.ie&&hs.uaVersion<9){var d=document.styleSheets[document.styleSheets.length-1];if(typeof(d.addRule)=="object"){d.addRule(e,f)}}else{c.appendChild(document.createTextNode(e+" {"+f+"}"))}}function a(d){return"expression( ( ( ignoreMe = document.documentElement."+d+" ? document.documentElement."+d+" : document.body."+d+" ) ) + 'px' );"}if(hs.expandCursor){b(".highslide img","cursor: url("+hs.graphicsDir+hs.expandCursor+"), pointer !important;")}b(".highslide-viewport-size",hs.ie&&(hs.uaVersion<7||document.compatMode=="BackCompat")?"position: absolute; left:"+a("scrollLeft")+"top:"+a("scrollTop")+"width:"+a("clientWidth")+"height:"+a("clientHeight"):"position: fixed; width: 100%; height: 100%; left: 0; top: 0")}});hs.addEventListener(window,"resize",function(){hs.getPageSize();if(hs.viewport){for(var a=0;a<hs.viewport.childNodes.length;a++){var b=hs.viewport.childNodes[a],c=hs.getExpander(b);c.positionOverlay(b);if(b.hsId=="thumbstrip"){c.slideshow.thumbstrip.selectThumb()}}}});hs.addEventListener(document,"mousemove",function(a){hs.mouse={x:a.clientX,y:a.clientY}});hs.addEventListener(document,"mousedown",hs.mouseClickHandler);hs.addEventListener(document,"mouseup",hs.mouseClickHandler);hs.addEventListener(document,"ready",hs.setClickEvents);hs.addEventListener(window,"load",hs.preloadImages);hs.addEventListener(window,"load",hs.preloadAjax)};;
/* global app */
/* global hs */
/* global tree */
/* global Clipboard */
/* global require */
$(function () {
  // HACK - if save state requires full screen, set it as soon as possible so that multiple extent changes don't have to be fired.
  // $("#resize").click() won't work because it acts too slowly.
  if (app.mapState && JSON.parse(app.mapState).f) {
    document.getElementById("entire-header").style.display = "none";
    document.getElementById("navbar").style.display = "none";
    document.getElementById("usgsfooter").style.display = "none";
    document.getElementById("disclaimer").style.display = "none";
    document.getElementById("resize").src = "/viewer/newmap/images/icons/shrink.png";
    document.getElementById("content").style.height = "100%";
  }

  // End early full screen hack

  app.override = null; // By default, warn user about too-large individual specimen results. Change override to true to force rendering.
  app.override = null; // By default, warn user about too-large individual specimen results. Change override to true to force rendering.
  app.labelHide = "&lt;"; // Accordion menu toggle labels
  app.labelShow = "&gt;";
  app.refTooltip = "Zoom in to enable this layer";
  app.basemap = "topo";
  app.center = [-90, 35.5];
  app.zoom = 3;
  app.usExtent = {};
  app.nativehuc = [];
  app.eDNA = [];
  app.defaultColor = [0, 0, 0, 255]; // black for > 6 species
  app.readyToChangeExtent = false;
  app.selecting = false; // true if point-selection Draw is activated
  app.showeDNADisclaimer = true; // set to false after it is shown once
  app.legendSymbols = []; // holds ArcGIS [url]/legend JSON for drawing custom legend for external layers
  app.numClusterSites = 0;
  app.numNonclusterSites = 0;
  app.numEdnaSites = 0;

  // Apply settings for special maps (e.g. Mid-tlantic Panel)
  if (app.specialMap) {
    app.zoom = app.specialMap.zoom;
    app.center = app.specialMap.center;
  }

  // New method of creating color-shape combinations.
  //
  // NOTE: currently menu and selection graphic ONLY assumes diamond shapes. Need to change these if more than just Diamond shape is used below
  //
  app.colors = [];
  app.colorseDNA = [];
  app.hues = [
    [230, 159, 0, 255],   // orange
    [86, 180, 233, 255],  // sky blue
    [213, 94, 0, 255],    // vermilion
    [0, 158, 115, 255],   // bluish green
    [204, 121, 167, 255], // reddish purple
    [0, 114, 178, 255]    // blue
  ];
  // http://resources.arcgis.com/en/help/rest/apiref/symbol.html
  // esriSMSCircle | esriSMSCross | esriSMSDiamond | esriSMSSquare | esriSMSX | esriSMSTriangle              [Triangle doesn't work]
  app.shapes = ["Diamond"];

  for (var t = 0; t < app.shapes.length; t++) {
    for (var v = 0; v < app.hues.length; v++) {
      app.colors.push({
        "speciesID": null,
        "color": app.hues[v],
        "shape": app.shapes[t]
      });
      app.colorseDNA.push({
        "speciesID": null,
        "color": [27, 158, 119, 255], // all are the same color for now
        "shape": "Square" // all are squares for now
      });
    }
  }

  $("#dialog").dialog({
    autoOpen: false,
    draggable: false,
    position: { my: "top", at: "top", of: "#map" }
  });

  $("#eDNADialog").dialog({
    autoOpen: false,
    draggable: false,
    position: { my: "center", at: "center", of: window }
  });

  $("#eDNADisclaimer").dialog({
    width: 700,
    autoOpen: false,
    draggable: false,
    position: { my: "center", at: "center", of: window }
  });

  hs.graphicsDir = "/viewer/js/highslide/graphics/";
  hs.outlineType = "rounded-white";
  hs.wrapperClassName = "draggable-header";
  hs.zIndexCounter = 2200;
  hs.lang.restoreTitle = "Click to close image, click and drag to move.";
  hs.showCredits = false;

  // Add link to Videos page onto every help menu
  var helpVideo = "<p>Need help? View a <a href='/viewer/Videos.aspx' target='_blank'>tutorial video</a> to learn how to use this map.</p>";

  app.help = [
    { h: 600, img: "cluster.jpg", text: helpVideo + "<p>The Clustered Specimens layer groups together specimens from your search that occur close together in the same area - useful for visualizing specimen density.</p><p>Click a cluster or use the <img style='border:0;vertical-align:middle' src='/viewer/newmap/images/icons/highlight1.png' alt='Highlight' /> tool to highlight specimens on the Records tab.</p>" },
    { h: 630, img: "individual.jpg", text: helpVideo + "<p>The Individual Specimens layer shows each distinct specimen record from your search. This layer performance can be very slow if your search returns many specimen points.</p><p>Points and native ranges are color-coded by species.</p><p>Click a point or use the <img style='border:0;vertical-align:middle' src='/viewer/newmap/images/icons/highlight1.png' alt='Highlight' /> tool to highlight specimens on the Records tab.</p>" },
    { img: "base.jpg", text: "<p></p>" }, // basemap not currently used
    { img: "ref.jpg", text: "<p></p>" }, // ref not currently used
    { img: "tree.jpg", text: helpVideo + "<p>Search for species based on their taxonomic classification. The levels in this taxonomic tree are: Group, Order, Family, Genus, and Species.</p><p>Click on a species checkbox to show it on the map. Click the Reset button to uncheck all selections and begin a new search.</p>" },
    { img: "species.jpg", text: helpVideo + "<p>The Species tab will show all distinct species from your search. Toggle <b>Include</b> to show or hide a species. Toggle <b>Native Range</b> to draw native HUC ranges.</p><p>The first " + app.hues.length + " species in the result set are color-coded. Any additional species are colored black.</p>" },
    { img: "polygon.jpg", text: helpVideo + "<p>Draw a polygon to search for species within a given area.<ul><li>Click the Draw Polygon checkbox.</li><li>Click and drag the mouse on the map.</li><li>Let go when your shape is finished.</li><li>Click Search button.</li></ul></p>" },
    { img: "circle.jpg", text: helpVideo + "<p>Draw a circle to search for species within a given radius.<ul><li>Click the Draw Circle checkbox.</li><li>Click the map to place the circle center.</li><li>Select the desired radius and units.</li><li>Click Search button.</li></ul></p>" },
    { h: 240, w: 540, text: helpVideo + "<p>The Records tab displays individual specimen occurrences returned by your search.</p><ul><li>Sort the table by clicking on a column header.</li><li>Click on a Specimen ID to view detailed information for that observation (in a new tab).</li><li>Click the <img style='border:0;vertical-align:middle' src='/viewer/newmap/images/icons/download.png' alt='Download data' /> button to export all records to a CSV file.</li></ul>" },
    {
      h: 370,
      text: helpVideo +
        "<p><img style='border:0;vertical-align:middle;width:26px' src='/viewer/newmap/images/icons/zoom1.png' alt='Zoom to box extent on map' /> Use your mouse to draw a rectangle on the map. Release the mouse to zoom in to the drawn area.</p>" +
        "<p><img style='border:0;vertical-align:middle;width:26px' src='/viewer/newmap/images/icons/globe.png' alt='Full extent' /> Restore the map to its original zoom level.</p>" +
        "<p><img style='border:0;vertical-align:middle;width:26px' src='/viewer/newmap/images/icons/expand.png' alt='Resize' /> Toggle whether the map is full-screen or not.</p>" +
        "<p><img style='border:0;vertical-align:middle;width:26px' src='/viewer/newmap/images/icons/link.png' alt='Save' /> Save the current map state to a link that can be re-used and shared.</p>" +
        "<p><img style='border:0;vertical-align:middle;width:26px' src='/viewer/newmap/images/icons/download.png' alt='Download' /> Download all specimen records that match your search. Records are exported as a CSV file.</p>" +
        "<p><img style='border:0;vertical-align:middle;width:26px' src='/viewer/newmap/images/icons/highlight1.png' alt='Highlight' /> Draw polygon around map points to select and highlight those points on the Records tab. Click the <img style='border:0;vertical-align:middle;width:26px' src='/viewer/newmap/images/icons/x.png' alt='Clear highlighted' /> button to clear all highlighted points.</p>"
    },
    {
      h: 310,
      text: "<p>Enter <a href='https://en.wikipedia.org/wiki/Well-known_text' target='_blank'>Well-known text</a> to find specimens within a custom polygon. Only POLYGON and MULTIPOLYGON are supported. Multi-polygons with holes are not supported at this time.</p>" +
        "<p>Examples:</p>" +
        "<p><code>POLYGON((-82.17 29.58, -82.15 29.65, -82.197 29.72, -82.40 29.68, -82.46 29.56, -82.3 29.54, -82.17 29.58))</code></p>" +
        "<p><code>MULTIPOLYGON(((-82.54 29.6, -82.7 29.7, -82.5 29.5, -82.4 29.62, -82.54 29.6)),((-81.7 29.8, -81.7 30, -81.8 30, -81.85 29.4, -81.7 29.8)),((-82.2 29.2, -82.2 29.3, -82.4 29.3, -82.4 29.2, -82.2 29.2)))</code></p>" +
        "<p><b>Note:</b> Very large polygons could increase query time and greatly reduce map performance if they are too complex. Try simplifying your WKT whenever possible for best performance.</p>"
    }
  ];

  $(document).on("click", ".help", function () {
    hs.dimmingOpacity = 0.5;
    hs.align = "center";

    // ID of 'help' element should match help-i where i is the index to app.help above
    var id = this.id.replace("help-", "");
    var help = app.help[id];
    var rand = Math.round(Math.random() * 10000);

    $("body").append(
      "<div class='highslide-html-content' id='help" + rand + "'>" +
      "<div class='highslide-header'><ul>" +
      "<li class='highslide-move'><a href='#' onclick='return false;'></a></li>" +
      "<li class='highslide-close'><a href='#' onclick='return hs.close(this)'></a></li>" +
      "</ul></div>" +
      "<div class='highslide-body'>" +
      help.text +
      (help.img ? "<img src='/viewer/images/help/" + help.img + "' alt='Map screenshot' width='730' />" : "") +
      "</div>" +
      "<div class='highslide-footer'><div><span class='highslide-resize' title='Resize'><span></span></span></div></div>" +
      "</div>"
    );

    hs.htmlExpand(this, {
      contentId: "help" + rand,
      width: help.w || 750,
      height: help.h || 625
    });
  });

  // Record which layer is currently being shown.
  //
  // Show lionfish in individual specimen layer by default
  if (app.speciesID === "963") {
    app.showingClusters = false;
    app.showingSpecimens = true;

  }
  else {
    app.showingClusters = true;
    app.showingSpecimens = false;
  }

  app.querySpecimenRecords = false; // When true, clicking on Specimen Records tab queries data. When false, nothing is queried.
  app.queryeDNARecords = false; // When true, clicking on eDNA Records tab queries data.  When false, nothing is queried.
  app.querySpecies = false; // When true, clicking on Species tab queries data. When false, nothing is queried.
  app.resetText = "<div id='beginquery'>Click the Query tab to begin a search.</div>";
  app.noneText = "<div id='beginquery'>No species found. Please change your search terms and try again.</div>";
  app.waitText = "<div id='beginquery'>Retrieving records.<br />Please wait...</div>";
  app.hlText = "<div id='beginquery'>Highlighting records.<br />Please wait...</div>";
  app.noRecordsText = "<div id='beginquery'>No records found. Please change your search terms and try again.</div>";

  app.excluded = [];
  app.excludedeDNA = [];
  app.params = undefined;
  app.order = undefined;
  app.selectedIDs = []; // Array of specimen IDs selected on map.
  app.selectedeDNAIDs = []; // Array of eDNA detection IDs selected on map.
  app.selectedSites = []; // Array of site IDs (selected clusters). Will be passed to AJAX to get linked Specimen IDs
  app.treeIDs = []; // Array of Species IDs checked within tree structure

  // HACK: hard-coding DDL options (just like SpSearch does)
  if (app.specialMap) {
    app.param_groups = ["Amphibians", "Bryozoans", "Coelenterates", "Crustaceans", "Entoprocts", "Fishes", "Mammals", "Marine Fishes", "Mollusks", "Plants", "Reptiles"];
    app.param_states = app.specialMap.states;
  }
  else {
    app.param_groups = ["Amphibians", "Bryozoans", "Coelenterates", "Crustaceans", "Entoprocts", "Fishes", "Mammals", "Marine Fishes", "Mollusks", "Plants", "Reptiles"];
    app.param_states = [{ id: "AL", name: "Alabama" }, { id: "AK", name: "Alaska" }, { id: "AZ", name: "Arizona" }, { id: "AR", name: "Arkansas" }, { id: "CA", name: "California" }, { id: "CO", name: "Colorado" }, { id: "CT", name: "Connecticut" }, { id: "DE", name: "Delaware" }, { id: "DC", name: "District of Columbia" }, { id: "FL", name: "Florida" }, { id: "GA", name: "Georgia" }, { id: "GU", name: "Guam" }, { id: "HI", name: "Hawaii" }, { id: "ID", name: "Idaho" }, { id: "IL", name: "Illinois" }, { id: "IN", name: "Indiana" }, { id: "IA", name: "Iowa" }, { id: "KS", name: "Kansas" }, { id: "KY", name: "Kentucky" }, { id: "LA", name: "Louisiana" }, { id: "ME", name: "Maine" }, { id: "MD", name: "Maryland" }, { id: "MA", name: "Massachusetts" }, { id: "MI", name: "Michigan" }, { id: "MN", name: "Minnesota" }, { id: "MS", name: "Mississippi" }, { id: "MO", name: "Missouri" }, { id: "MT", name: "Montana" }, { id: "NE", name: "Nebraska" }, { id: "NV", name: "Nevada" }, { id: "NH", name: "New Hampshire" }, { id: "NJ", name: "New Jersey" }, { id: "NM", name: "New Mexico" }, { id: "NY", name: "New York" }, { id: "NC", name: "North Carolina" }, { id: "ND", name: "North Dakota" }, { id: "OH", name: "Ohio" }, { id: "OK", name: "Oklahoma" }, { id: "OR", name: "Oregon" }, { id: "PA", name: "Pennsylvania" }, { id: "PR", name: "Puerto Rico" }, { id: "RI", name: "Rhode Island" }, { id: "SC", name: "South Carolina" }, { id: "SD", name: "South Dakota" }, { id: "TN", name: "Tennessee" }, { id: "TX", name: "Texas" }, { id: "UT", name: "Utah" }, { id: "VT", name: "Vermont" }, { id: "VI", name: "Virgin Islands" }, { id: "VA", name: "Virginia" }, { id: "WA", name: "Washington" }, { id: "WV", name: "West Virginia" }, { id: "WI", name: "Wisconsin" }, { id: "WY", name: "Wyoming" }];
  }

  app.param_native = [{ id: "Exotic", name: "Exotic" }, { id: "Native", name: "Native Transplant" }, { id: "Cryptogenic", name: "Cryptogenic" }, { id: "Hybrid", name: "Hybrid" }];
  app.param_fmb = [{ id: "1", name: "Freshwater" }, { id: "2", name: "Marine" }, { id: "3", name: "Brackish" }];
  app.param_status = [{ id: "1", name: "Established" }, { id: "2", name: "Reported" }, { id: "3", name: "Failed" }];
  app.param_pathway = [{ id: "1", name: "Stocked" }, { id: "2", name: "Shipping" }, { id: "3", name: "Aquarium Release" }, { id: "4", name: "Bait Release" }, { id: "5", name: "Aquaculture" }, { id: "6", name: "Canals" }, { id: "7", name: "Pet Escape" }];
  app.param_accuracy = ["Accurate", "Approximate", "Centroid"];
  app.param_impacts = ["Predation/Herbivory", "Food Web", "Competition", "Habitat Alteration", "Genetic", "Disease/Parasites/Toxicity", "Water Quality", "Infrastructure", "Recreation", "Commerce", "Aquaculture/Agriculture", "Property Value", "Human Health", "Harvest", "Navigation", "Other"];
  app.searchFields = [
    //
    // NOTE: IF adding a new search field, be sure to add 1 to the speciesIndex below!
    //
    { title: "Specimen Number", column: "specimen_ID", inputType: "t", maxLength: 10 },
    { title: "Group", column: "[Group]", inputType: "d", options: app.param_groups },
    { title: "Family", column: "Family", inputType: "t", maxLength: 30 },
    { title: "Genus", column: "Genus", inputType: "t", maxLength: 60 },
    { title: "Species", column: "Species", inputType: "t", maxLength: 60 },
    { title: "Common Name", column: "common_name", inputType: "t", maxLength: 80 },
    { title: "State", column: "state", inputType: "d", options: app.param_states },
    { title: "County", column: "County", inputType: "t" },
    { title: "Drainage Name", column: "HUC8_name", inputType: "t", maxLength: 100 },
    { title: "HUC 8 Number", column: "HUC8_number", inputType: "t", maxLength: 60 },
    { title: "Impact", column: "Impact", inputType: "d", options: app.param_impacts },
    { title: "Accuracy", column: "lat_long_accuracy", inputType: "d", options: app.param_accuracy },
    { title: "Year", column: "Year", inputType: "r" },
    { title: "Status", column: "Status", inputType: "d", options: app.param_status },
    { title: "Pathway", column: "pathway", inputType: "d", options: app.param_pathway },
    { title: "Freshwater/Marine", column: "fresh_marine_brackish", inputType: "d", options: app.param_fmb },
    { title: "Exotic/Transplant", column: "native_exotic", inputType: "d", options: app.param_native },
    { title: "Reference Number", column: "refnum", inputType: "t", maxLength: 80 },
    { title: "Species ID", column: "species_ID", inputType: "h" } // Special hidden parameter to support speciesID URL parameter
    //
    // NOTE: IF adding a new search field, be sure to add 1 to the speciesIndex below!
    //
  ];
  app.speciesIndex = 18;

  var createNewClusterLayer = function () { };
  var createNewSpecimenLayer = function () { };

  app.showLoading = function () {
    document.getElementById("loading").style.display = "block";
  };
  app.hideLoading = function () {
    document.getElementById("loading").style.display = "none";
  };
  app.hi = function (x, cls) {
    // cls: hi-info or hi-error
    document.getElementById("hi").innerHTML = (x ? "<span class='" + (cls || "hi-info") + "'>" + x + "</span>" : "");
  };
  // Creates custom legend using JSON in app.legendSymbols; a symbol item must have show set to 1 to be drawn on the legend
  app.createLegend = function () {
    var html = "";

    for (var i = 0; i < app.legendSymbols.length; i++) {
      var symbol = app.legendSymbols[i];
      if (symbol.show) {
        if (symbol.html) {
          // Handle Census 2020 Population feature layer
          html += symbol.html; // Fixed bug that was at times only displaying Census legend
        }
        else {

          if (symbol.legend.length === 1) {
            // If there is only one symbol, display it inline with layer name
            var item = symbol.legend[0];

            if (item.imageData) {

              if (symbol.layerName === "Counties") { // HACK to line up counties image with others
                html += "<div style='margin-left:2px'><img style='vertical-align:middle;opacity:" + symbol.opacity + ";' src='data:image/png;base64," +
                  item.imageData + "' /> <span class='legend-title'>" + symbol.layerName + "</span></div>";
              }
              else {
                html += "<div><img style='vertical-align:middle;opacity:" + symbol.opacity + ";' src='data:image/png;base64," +
                  item.imageData + "' /> <span class='legend-title'>" + symbol.layerName + "</span></div>";
              }
            }
            else {
              html += "<div>??? - " + symbol.layerName + "</div>";
            }
          }
          else {
            html += "<div><span class='legend-title'>" + symbol.layerName + "</span></div>";
            for (var j = 0; j < symbol.legend.length; j++) {
              var item = symbol.legend[j];
              if (item.imageData) {
                html += "<div><img style='vertical-align:middle;opacity:" + symbol.opacity + ";' src='data:image/png;base64," +
                  item.imageData + "' /> <span class='legend-item'>" + item.label + "</span></div>";
              }
              else {
                html += "<div>??? - " + item.label + "</div>";
              }
            }
          }


        }
      }
    }
    document.getElementById("legend").innerHTML = "<div style='padding-top:15px;padding-bottom:15px'>" + html + "</div>";
  };

  app.showRef = null;
  var handleRef, hideRef;

  // Create tabbed menus - default to Species if a single species was given.
  if (app.speciesID) {
    $("#tabL").tabs({
      active: 1
    });
    $("#tabR").tabs();
  }
  else {
    $(".tab-area").tabs();
    document.getElementById("speciesInner").innerHTML = app.resetText;
    document.getElementById("recordsTab").innerHTML = app.resetText;
    document.getElementById("eDNArecordsTab").innerHTML = app.resetText;
  }

  app.warcGeoUrl = "https://nas.er.usgs.gov/ag-nasgeo01/rest/services/NAS2/nas/MapServer";
  app.mapaisUrl = "https://nas.er.usgs.gov/ag-nasgeo01/rest/services/NAS2/ANSTF/MapServer";

  app.ref = [
    { grp: "admin", id: "GSARP", name: "GSARP-region states", opacity: 1, zoom: 1, customUrl: app.mapaisUrl, layerIDs: [0], legend: 1, specialMap: "GSARP" },
    { grp: "admin", id: "MAPAIS", name: "MAPAIS-region states", opacity: 1, zoom: 1, customUrl: app.mapaisUrl, layerIDs: [1], legend: 1, specialMap: "MAPAIS" },
    { grp: "admin", id: "MRBP", name: "MRBP-region states", opacity: 1, zoom: 1, customUrl: app.mapaisUrl, layerIDs: [2], legend: 1, specialMap: "MRBP" },
    { grp: "admin", id: "NEANS", name: "NEANS-region states", opacity: 1, zoom: 1, customUrl: app.mapaisUrl, layerIDs: [3], legend: 1, specialMap: "NEANS" },

    { grp: "admin", id: "states", name: "States", opacity: 0.6, zoom: 1, customUrl: app.warcGeoUrl, layerIDs: [11], legend: 1 },
    { grp: "admin", id: "states_label", opacity: 0.6, zoom: 1, customUrl: app.warcGeoUrl, layerIDs: [16], parent: "states" },
    //{ grp: "admin", id: "NAS_counties_2017", name: "Counties", opacity: 0.6, zoom: 6, customUrl: "https://services3.arcgis.com/3v060JiGlgJytIRe/ArcGIS/rest/services/NAS_MAP_for_AGOL_Counties/FeatureServer/0" },
    { grp: "admin", id: "NAS_counties_2017", name: "Counties", opacity: 0.6, zoom: 6, customUrl: app.warcGeoUrl, layerIDs: [17], legend: 1 },
    { grp: "admin", id: "counties_us_2015_label", opacity: 0.6, zoom: 6, customUrl: app.warcGeoUrl, layerIDs: [0], parent: "NAS_counties_2017" },
    //{ grp: "admin", id: "congress", name: "Congressional Districts", opacity: 0.9, legend: 1, customUrl: "https://services.nationalmap.gov/arcgis/rest/services/WFS/govunits/MapServer", layerIDs: [9], zoom: 5 },

    { grp: "admin", id: "congress", name: "Congressional Districts", opacity: 0.9, zoom: 3, customUrl: "https://carto.nationalmap.gov/arcgis/rest/services/govunits/MapServer", layerIDs: [41], legend: 1 },
    { grp: "admin", id: "congress_label", opacity: 0.9, zoom: 8, customUrl: "https://carto.nationalmap.gov/arcgis/rest/services/govunits/MapServer", layerIDs: [19], parent: "congress" },

    { grp: "hydro", id: "riv25mdd", name: "Major Rivers", opacity: 0.8, zoom: 1, customUrl: app.warcGeoUrl, layerIDs: [10], legend: 1 },
    //HUC8
    { grp: "hydro", id: "HUC8", name: "HUC 8", opacity: 0.8, zoom: 4, customUrl: app.warcGeoUrl, layerIDs: [2], legend: 1, href: "https://nas.er.usgs.gov/hucs.aspx" },
    { grp: "hydro", id: "HUC8_label", opacity: 0.8, zoom: 4, customUrl: app.warcGeoUrl, layerIDs: [1], parent: "HUC8" },
    //HUC6
    { grp: "hydro", id: "HUC6", name: "HUC 6", opacity: 0.8, zoom: 1, customUrl: app.warcGeoUrl, layerIDs: [4], legend: 1, href: "https://nas.er.usgs.gov/hucs.aspx" },
    { grp: "hydro", id: "HUC6_label", opacity: 0.8, zoom: 1, customUrl: app.warcGeoUrl, layerIDs: [3], parent: "HUC6" },
    // HUC4
    { grp: "hydro", id: "HUC4", name: "HUC 4", opacity: 0.8, zoom: 1, customUrl: app.warcGeoUrl, layerIDs: [6], legend: 1, href: "https://nas.er.usgs.gov/hucs.aspx" },
    { grp: "hydro", id: "HUC4_label", opacity: 0.8, zoom: 1, customUrl: app.warcGeoUrl, layerIDs: [5], parent: "HUC4" },
    // HUC2
    { grp: "hydro", id: "HUC2", name: "HUC 2", opacity: 0.8, zoom: 1, customUrl: app.warcGeoUrl, layerIDs: [8], legend: 1, href: "https://nas.er.usgs.gov/hucs.aspx" },
    { grp: "hydro", id: "HUC2_label", opacity: 0.8, zoom: 1, customUrl: app.warcGeoUrl, layerIDs: [7], parent: "HUC2" },

    // External layers (dynamic)
    { grp: "enviro", id: "eap", name: "EPA Annual Precipitation", opacity: 0.5, customUrl: "https://enviroatlas.epa.gov/arcgis/rest/services/National/National2016_master/MapServer", layerIDs: [12], zoom: 5, legend: 1, href: "https://enviroatlas.epa.gov/arcgis/rest/services/National/National2016_master/MapServer/12" },
    // { grp: "enviro", id: "umt", name: "USGS Average Temperature", opacity: 0.5, customUrl: "https://gis1.usgs.gov/arcgis/rest/services/US_Mean_Daily_Avg_Temperature/MapServer", layerIDs: [0, 7], zoom: 1, legend: 1, href: "https://gis1.usgs.gov/arcgis/rest/services/US_Mean_Daily_Avg_Temperature/MapServer" },

    //      { grp: "land", id: "upa", name: "USGS Protected Areas", opacity: 0.5, customUrl: "https://gis1.usgs.gov/arcgis/rest/services/PADUS1_4/Fine_Agency_Level/MapServer", layerIDs: [0], zoom: 1, legend: 1, href: "https://gapanalysis.usgs.gov/padus/" },
    //{ grp: "land", id: "upa", name: "USGS Protected Areas", opacity: 0.5, customUrl: "https://gis1.usgs.gov/arcgis/rest/services/padus2_1/ManagerName/MapServer", layerIDs: [0], zoom: 1, legend: 1, href: "https://gapanalysis.usgs.gov/padus/" },
    { grp: "land", id: "upa", name: "USGS Protected Areas", opacity: 0.5, customUrl: "https://gis1.usgs.gov/arcgis/rest/services/padus3/Manager_Name/MapServer", layerIDs: [0], zoom: 1, legend: 1, href: "https://gapanalysis.usgs.gov/padus/" },

    // { grp: "land", id: "cua", name: "Census Urbanized Areas", opacity: 0.5, customUrl: "https://tigerweb.geo.census.gov/arcgis/rest/services/TIGERweb/Urban/MapServer", layerIDs: [5], zoom: 7, legend: 1, href: "https://www.census.gov/geo/maps-data/" },
    { grp: "land", id: "cua", name: "Census Urbanized Areas", opacity: 0.5, customUrl: "https://tigerweb.geo.census.gov/arcgis/rest/services/TIGERweb/Urban/MapServer", layerIDs: [3], zoom: 7, legend: 1, href: "https://www.census.gov/geo/maps-data/" },
    // Feature layer - has custom renderer which we need to translate onto the "dynamic layer" legend handling above layers
    { grp: "land", id: "cpo", name: "Census Population", feature: 1, customUrl: "https://tigerweb.geo.census.gov/arcgis/rest/services/Census2020/Tracts_Blocks/MapServer/8", zoom: 9, legend: 1, outFields: ["NAME", "POP100"], href: "https://www.census.gov/geo/maps-data/" }
  ];

  app.latResolutions = [1.40625, 0.703125, 0.3515625, 0.17578125, 0.087890625, 0.0439453125, 0.02197265625, 0.010986328125, 0.0054931640625, 0.00274658203125, 0.001373291015625, 0.0006866455078125, 0.00034332275390625, 0.000171661376953125, 0.0000858306884765625, 0.00004291534423828125, 0.0000214576721191406, 0.0000107288360595703, 0.00000536441802978516, 0.00000268220901489258];
  app.specLayer = {};
  app.eDNALayer = {};
  app.paramTuples = [];
  app.readyToChangeExtent = true;
  app.map = {};

  app.HighlighteDNASpeciesWithSameCoordinates = function (table) {
    // Input:  HTML contents of eDNA tab with 0 or more records highlighted
    // Output: HTML contents of eDNA tab with same records highlighted, plus any
    //         records whose coordinates exactly match the originally highlighted records.
    //         Any lines that are added in this manner also have their detectionIDs added
    //         to the list so as to not get lost on re-queries.

    // split original table into array with one string per table row
    // only keep rows that are already highlighted, throw out all others

    var coordinateList = table.split("<tr ").filter(function (item) {
      return item.includes("class='hl'");
    });

    // loop through results and strip off all but the HTML code for the coordinates (including "td" tags)
    for (i = 0; i < coordinateList.length; i++) {
      var tmp;
      var position = coordinateList[i].search("<td style=\"display:none\">"); // beginning of coordinates
      tmp = coordinateList[i].substring(position); // strip off everything before
      position = tmp.search("</tr>"); // end of coordinates
      tmp = tmp.substring(0, position); // strip off everything after
      coordinateList[i] = tmp; // put result back in array
    }

    // Now we have a list of coordinates (with HTML formatting) to match in the entire table.

    // remove any duplicates to avoid unnecessary looping
    coordinateList = removeDuplicates(coordinateList);

    // Clear highlighting; we will re-do it by coordinates
    table = clearHighlighting(table);

    // split table into strings, one per row
    var splitTable = table.split("<tr ");

    // re-highlight based on coordinates
    for (i = 0; i < coordinateList.length; i++) {
      for (j = 0; j < splitTable.length; j++) {
        if (splitTable[j].includes(coordinateList[i])) {

          splitTable[j] = "class='hl' " + splitTable[j]; // highlight the record

          // begin add ID to app.selectedeDNAIDs
          var s = splitTable[j];
          s = s.replaceAll("\"", "'"); // code below is expecting single quotes
          //s = s.replaceAll("id=\"row", "id='row"); // if "row" is in double quotes, convert beginning quote to single quote
          var position = s.search("id='row"); // beginning of detection ID
          s = s.substring(position + 7); // strip off everything before
          position = s.search("'"); // end of detection ID
          s = s.substring(0, position); // strip off everything after
          if (!app.selectedeDNAIDs.includes(s) /*&& s != ''*/) {
            app.selectedeDNAIDs.push(s);
          }
          // end add ID to app.selectedeDNAIDs
        }
      }
    }

    // separate highlighted rows from non-highlighted so we can order the highlighted ones first.
    var rows_highlighted = [];
    var rows_nothighlighted = [];

    // re-order rows
    for (i = 1; i < splitTable.length; i++) {
      if (splitTable[i].includes("class='hl'")) {
        rows_highlighted.push(splitTable[i]);
      }
      else {
        rows_nothighlighted.push(splitTable[i]);
      }
    }

    var firstRow = splitTable[0];
    splitTable = rows_highlighted.concat(rows_nothighlighted);

    // put table back together and return it
    var reassembledTable = firstRow + "<tr " + splitTable.join("<tr ");

    // make sure closing tags appear only at the end
    reassembledTable = reassembledTable.replace("</tbody></table></div>", "") + "</tbody></table></div>";

    return reassembledTable;
  }

  require([
    "esri/Color",
    "esri/config",
    "esri/dijit/Basemap",
    "esri/dijit/BasemapGallery",
    "esri/dijit/BasemapLayer",
    "esri/layers/VectorTileLayer",
    "esri/dijit/PopupTemplate",
    "esri/dijit/Scalebar",
    "esri/geometry/Extent",
    "esri/geometry/geometryEngine",
    "esri/geometry/Point",
    "esri/geometry/Polygon",
    "esri/geometry/webMercatorUtils",
    "esri/graphic",
    "esri/layers/ArcGISDynamicMapServiceLayer",
    "esri/layers/ArcGISTiledMapServiceLayer",
    "esri/layers/FeatureLayer",
    "esri/layers/ImageParameters",
    "esri/symbols/SimpleFillSymbol",
    "esri/renderers/SimpleRenderer",
    "esri/map",
    "esri/renderers/ClassBreaksRenderer",
    "esri/SpatialReference",
    "esri/symbols/SimpleLineSymbol",
    "esri/symbols/SimpleMarkerSymbol",
    "esri/toolbars/draw",
    "dojo/domReady!"],
    function (Color, esriConfig, Basemap, BasemapGallery, BasemapLayer, VectorTileLayer, PopupTemplate, Scalebar, Extent, geoEngine, Point, Polygon, webMercatorUtils, Graphic, DynamicServiceLayer, TiledServiceLayer, FeatureLayer, ImageParameters,
      SimpleFillSymbol, SimpleRenderer, Map, ClassBreaksRenderer, SpatialReference, SimpleLineSymbol, SimpleMarkerSymbol, Draw) {

      esriConfig.defaults.io.proxyUrl = "/viewer/newmap/proxy/proxy.ashx";
      esriConfig.defaults.io.alwaysUseProxy = false;

      if (app.mapState) {
        app.saveState.readSaveState(app.mapState);
      }

      if (app.extent) {
        // Create map with supplied extent
        app.map = new Map("map", {
          extent: new Extent({
            xmin: app.extent.xmin,
            ymin: app.extent.ymin,
            xmax: app.extent.xmax,
            ymax: app.extent.ymax,
            spatialReference: app.extent.spatialReference
          }),
          zoom: app.zoom,
          minZoom: 3,
          maxZoom: 22,
          logo: false,
          showLabels: true,
          basemap: app.basemap
        });
      }
      else {
        // Create map with default extent
        app.map = new Map("map", {
          center: app.center,
          zoom: app.zoom,
          minZoom: 3,
          maxZoom: 22, // max on national map; can increase if we go back to esri
          logo: false,
          showLabels: true,
          basemap: app.basemap
        });
      }



            app.gallery = null;

      createBasemaps(app.basemap);

      app.gallery.on("selection-change", function () {
        var id = app.gallery.getSelected().id;
        app.basemap = app.gallery.getSelected();

        // serviceInfoResponse is bulky and not necessary.  For satellite, it causes
        // issues with non-escaped equal signs.  So, we just strip it out.
        for (var j = 0; j < app.basemap.layers.length; j++) {
          app.basemap.layers[j].serviceInfoResponse = "";
        }

        // restrict to zoom level 15 for national map, since that's all it supports
        // otherwise user will see the layer disappear at unsupported zoom levels
        if (id === 'national') {
          app.map._params.maxZoom = 15; // max for national map
        }
        else {
          app.map._params.maxZoom = 22; // max for all others
        }

        if (id === 'basic') {
          app.map.setBasemap('basic');
        }
        else {
          app.map.setBasemap(app.basemap);
        }
        app.toggleDarkGrayContrast(id);
      });

      // Define point symbology
      app.symbols = {
        lineSymbol: new SimpleLineSymbol(
          SimpleLineSymbol.STYLE_DASH, new Color([0, 70, 100, 1]), 3
        ),
        grayOutline: new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([34, 34, 34]), 1.5),
        // grayOutlineeDNA: new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([255, 0, 0]), 3),

        selectedCluster: function (style) {
          var size = 18;

          if (style === "1") size = 8;
          else if (style === "2") size = 10;
          else if (style === "6") size = 12;
          else if (style === "11") size = 14;

          return new SimpleMarkerSymbol(SimpleMarkerSymbol.STYLE_CIRCLE, size, this.grayOutline, new Color([255, 255, 0]));
        },
        selectedSpecimen: new SimpleMarkerSymbol(SimpleMarkerSymbol.STYLE_DIAMOND, 8, this.grayOutline, new Color([255, 255, 0])),
        selectedeDNADetection: new SimpleMarkerSymbol(SimpleMarkerSymbol.STYLE_SQUARE, 8, new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([0, 0, 0]), 2), new Color([255, 255, 0])) // highlighted eDNA detection is a square, yellow, with 2px border
      };

      app.map.on("click", function (evt) {
        if (app.map.loaded) {
          if (document.getElementById("chkCircle").checked) {
            var point = evt.mapPoint;

            var radius = document.getElementById("radius").value;
            if (!radius) {
              radius = 50;
              document.getElementById("radius").value = 50;
            }

            drawHelper(radius, point);

            var ll = webMercatorUtils.xyToLngLat(point.x, point.y);
            app.circleX = ll[0];
            app.circleY = ll[1];
          }
        }
      });

      if (app.specialMap) {
        // Pan back to 'special map' extent if user goes too far away
        app.map.on("pan-end", function (evt) {
          var centerOfNewExtent = evt.extent.getCenter();
          var centerX = app.startCenter[0];
          var centerY = app.startCenter[1];

          var dist = 1600000;

          if (app.specialMap.name === "MRBP") {
            dist = 2800000;
          }

          if (centerOfNewExtent.x < centerX - dist ||
            centerOfNewExtent.y > centerY + dist ||
            centerOfNewExtent.y < centerY - dist ||
            centerOfNewExtent.x > centerX + dist) {
            app.map.setExtent(app.usExtent);
          }
        });
      }
      // end Spatial geo buffer test

      // Below saves U.S. extent when full-zoom button is clicked. Currently Full Extent Zoom button goes here, even if map 
      // was loaded from a save state with a different extent.
      if (app.specialMap) {
        var ee = app.specialMap.extent;
        app.usExtent = new Extent(ee.xmin, ee.ymin, ee.xmax, ee.ymax, app.map.spatialReference);
        app.startCenter = webMercatorUtils.lngLatToXY(app.usExtent.getCenter().x, app.usExtent.getCenter().y);
      }
      else {
        app.usExtent = new Extent(-140.8447, 13.6716, -39.3311, 52.7522, app.map.spatialReference);
      }

      app.zoombox = {
        toolbar: new Draw(app.map),
        activated: false,
        zb: document.getElementById("zoombox"),

        deactivate: function () {
          this.toolbar.deactivate();
          this.activated = false;
          this.zb.src = "/viewer/newmap/images/icons/zoom1.png";
        }
      };

      $("#zoombox").click(function () {
        if (!app.zoombox.activated) {

          deactivatePolygonDrawing();
          deactivateSelection();

          app.zoombox.toolbar.activate(Draw.EXTENT, {
            showTooltips: false
          });
          app.zoombox.activated = true;
          app.zoombox.zb.src = "/viewer/newmap/images/icons/zoom2.png";
        }
        else {
          app.zoombox.deactivate();
        }
      });

      app.zoombox.toolbar.on("draw-end", function (e) {
        app.map.setExtent(e.geometry);
        app.zoombox.deactivate();
        app.map.enableMapNavigation();
      });

      app.map.on("load", function () {
        //console.log(getBoundingBox(app.map.extent)); // to get extent of anstf maps (?)
        var i, j;
        $(".fade").animate({ opacity: 1.0 });

        document.getElementById("chkCircle").checked = false;
        document.getElementById("chkPolygon").checked = false;

        app.toggleDarkGrayContrast(app.map.getBasemap());

        // Make cluster-layer-creation available after map has finished loading
        createNewClusterLayer = function () {
          var p = buildParams();

          if (app.params.length || p.length) {
            createClusterLayer(getBoundingBox(app.map.extent), app.params || p);
          }
          else {
            app.hideLoading();
          }
        };

        createNewSpecimenLayer = function () {
          var p = buildParams();

          if (app.params.length || p.length) {
            createSpecimenLayer(getBoundingBox(app.map.extent), app.params || p);
          }
          else {
            app.hideLoading();
          }
        };

        // Maintain backwards-compatibility with old ?speciesid= map functionality.
        // Replaced name match with exact ID match (see Ticket #807)
        if (app.speciesID) {
          addParameter(app.speciesIndex, app.speciesID);

          app.querySpecimenRecords = true;
          app.queryeDNARecords = true;
          app.querySpecies = true;

          populateSpecies(buildParams());
        }

        // Draw polygon from save state
        if (app.temp) {
          // TODO: move this inside drawing to eliminate esri/geo/Polygon dependency in this file
          var poly = new Polygon(app.temp);
          app.drawing.drawPolygon(new Graphic(poly, app.symbols.lineSymbol), "4326");
        }
        else if (app.circle) {
          app.circleX = app.circle.point.x;
          app.circleY = app.circle.point.y;

          // HACK - duplicate code
          var circle = app.circle;

          var point = circle.point;
          var radius = circle.radius;
          var unit = circle.unit;

          // Add a graphic representing a radius-unit buffer around the clicked point
          var buffer = geoEngine.geodesicBuffer(point, radius, unit);
          app.map.graphics.add(new Graphic(buffer, app.symbols.lineSymbol));

          // Save geometry for zooming
          app.geometry = buffer;
          // END HACK - dup code
        }
        else if (app.wkt) {
          document.getElementById("chkWKT").checked = true;
          document.getElementById("wkt").value = app.wkt;
          $("#wktControl").slideDown();

          if (app.tempWKT) {
            app.map.graphics.add(new Graphic(app.tempWKT, app.symbols.lineSymbol));
          }
        }

        // Handles initial search based on saved state
        if (app.paramTuples.length || app.treeIDs.length || app.polygon || app.circle || app.wkt) {
          // Call add parameter for stuff in tuples (tuples = indexId of param object and value in quotes)
          for (i = 0; i < app.paramTuples.length; i++) {
            var t = app.paramTuples[i];
            for (j = 0; j < t.values.length; j++) {
              addParameter(t.id, t.values[j]);
            }
          }

          app.querySpecimenRecords = true;
          app.queryeDNARecords = true;
          app.querySpecies = true;

          populateSpecies(buildParams());
        }

        var setRefsFromSaveState = false;

        if (app.refLayersFromSaveState && app.refLayersFromSaveState.length) {
          for (var jjj = 0; jjj < app.refLayersFromSaveState.length; jjj++) {
            var refID = app.refLayersFromSaveState[jjj];
            document.getElementById("esrimapRef" + refID).checked = true;
            app.showRef(app.ref[refID]);

            setRefsFromSaveState = true;
          }
        }

        if (app.specialMap) {
          if (!setRefsFromSaveState) {
            for (i = 0; i < app.ref.length; i++) {
              if (app.ref[i].specialMap === app.specialMap.name) {
                document.getElementById("esrimapRef" + i).checked = true;
                app.showRef(app.ref[i]);
              }
            }
          }
        }
      });

      // Disable/enable point observation checkboxes during zooming
      var layerCheckboxes = document.getElementsByName("sitesVisible");

      app.map.on("zoom-start", function () {
        for (var i = 0; i < layerCheckboxes.length; i++) { layerCheckboxes[i].disabled = true; }
      });

      app.map.on("zoom-end", function () {
        var i;
        for (i = 0; i < layerCheckboxes.length; i++) {
          layerCheckboxes[i].disabled = false;
        }

        // enable/disable ref layer chkboxes
        for (i = 0; i < app.ref.length; i++) {
          // Skip over ANSTF layers which stay enabled
          if (app.ref[i].specialMap) {
            continue;
          }

          handleRef(i);
        }
      });

      // Redraw cluster/sites layers on top reference layers
      app.map.on("layer-add", function (evt) {
        if (evt.layer.id !== "cluster" && evt.layer.id !== "specs") {
          var l;

          if (app.showingClusters) {
            l = "cluster";
          }
          else if (app.showingSpecimens) {
            l = "specs";
          }

          var layer = app.map.getLayer(l);
          if (layer) {
            app.map.removeLayer(layer);
            app.map.addLayer(layer);
          }
        }
      });

      app.oldExtent = null;
      app.extentReallyChanged = false;

      app.map.on("extent-change", function (evt) {
        // smatis /- 4/11/16 - fixed problem with Chrome that was firing extent-change on a simple click. Compare
        // old saved extent and current extent to verify extent really changed.
        // https://geonet.esri.com/thread/89288
        if (app.oldExtent && !app.extentsEqual(app.oldExtent, evt.extent)) {
          app.extentReallyChanged = true;
        }

        // Build conditions to re-query data. With certain configurations we can avoid this step if no new data would be queried.
        var didExtentReallyChange = (app.extentReallyChanged || !app.oldExtent);
        var isMapFullyLoaded = (app.readyToChangeExtent && app.map.loaded);
        var polygonChanged = (app.geometry && app.redrawSpecimens);

        // Always re-query if we're viewing clusters and extent changed. Also re-query if polygon changed or search parameters changed with a polygon drawn.
        var flag = (isMapFullyLoaded && didExtentReallyChange) || polygonChanged;
        if (flag) {
          app.showLoading();
          if (polygonChanged) {
            // Need to requery everything
            doQuery(true);
            app.redrawSpecimens = false;
          }
          else {
            // If no polygon, just requery the layer we're looking at. leave Species and Records as they are.
            var params = buildParams();
            if (params.length) {
              if (app.showingClusters) {
                createClusterLayer(getBoundingBox(app.map.extent), params);
              }
              else {
                // HACK : duplicated code
                // Add map graphics to specimen layer for records that were reverse-selected in Records tab
                for (var i = 0; i < app.selectedIDs.length; i++) {
                  for (var j = 0; j < app.specLayer.graphics.length; j++) {
                    var id = app.specLayer.graphics[j].attributes.i;
                    if (id.toString() === app.selectedIDs[i]) {
                      var geo = app.specLayer.graphics[j].geometry;
                      app.map.graphics.add(new Graphic(new Point(geo.x, geo.y), app.symbols.selectedSpecimen));
                    }
                  }
                }


                createSpecimenLayer(getBoundingBox(app.map.extent), params);
              }
              createeDNALayer(getBoundingBox(app.map.extent), params);
              // HACK : duplicated code
              // Add map graphics to eDNA layer for records that were reverse-selected in eDNA Records tab
              for (var i = 0; i < app.selectedeDNAIDs.length; i++) {
                for (var j = 0; j < app.eDNALayer.graphics.length; j++) {
                  var id = app.eDNALayer.graphics[j].attributes.i;
                  if (id.toString() === app.selectedeDNAIDs[i]) {
                    var geo = app.eDNALayer.graphics[j].geometry;
                    var theGraphic = new Graphic(new Point(geo.x, geo.y), app.symbols.selectedeDNADetection);
                    theGraphic.shape = 'Square'; // so we can identify this as an eDNA highlight
                    app.map.graphics.add(theGraphic);
                  }
                }
              }
            }
            else {
              app.hideLoading();
            }
          }
        }

        app.oldExtent = evt.extent;
      });

      app.map.on("update-end", function () {
        app.hideLoading();
      });

      new Scalebar({ map: app.map });

      app.map.on("mouse-move", function (evt) {
        if (evt.mapPoint) {
          var ll = webMercatorUtils.xyToLngLat(evt.mapPoint.x, evt.mapPoint.y);
          document.getElementById("coords").innerHTML = ll[0].toFixed(4) + ", " + ll[1].toFixed(4);
        }

        if (document.getElementById("chkCircle").checked) {
          var t = document.getElementById("circleTooltip");
          t.style.top = (evt.clientY + 25).toString() + "px";
          t.style.left = evt.clientX.toString() + "px";
          t.style.display = "block";
        }
      });

      app.map.on("mouse-out", function () {
        document.getElementById("circleTooltip").style.display = "none";
      });

      document.getElementById("updated").innerHTML = "Map updated " + new Date().toDateString() + ".";

      /* NEW function for newmap to toggle native hucs */
      function toggleNativeHuc(speciesID) {
        var index;

        for (var i = 0; i < app.nativehuc.length; i++) {
          if (app.nativehuc[i].id === speciesID) {
            index = i;
          }
        }

        var theLayer = app.nativehuc[index];

        if (theLayer && app.nativehuc[index].shown) {

          // layer is currently shown, so hide it
          app.map.removeLayer(theLayer.layer);
          app.nativehuc[index].shown = "";
        }
        else {
          if (app.nativehuc[index] && app.nativehuc[index].layer) { // if layer has been cached, don't query again
            app.map.addLayer(app.nativehuc[index].layer);
            app.nativehuc[index].shown = "1";

            // Ticket 974: redraw all active reference layers so they appear on top Native and HUC 8 layers
            redrawReferenceLayers();
          }
          else {
            $.ajax({
              url: "/viewer/newmap/NewMapHandler.ashx?r=n&speciesid=" + speciesID,
              success: function (huc) {
                if (huc.length) {

                  huc = huc.join("','");

                  var l = new FeatureLayer(app.warcGeoUrl + "/2", { // NOTE: this uses HUC8 layer (not SpeciesNativeHUC)
                    id: "native" + speciesID,
                    definitionExpression: "HUC8 IN ('" + huc + "')",
                    opacity: 0.5
                  });

                  var color = app.getColor(speciesID);
                  var sym = new SimpleFillSymbol(SimpleFillSymbol.STYLE_SOLID, new SimpleLineSymbol("solid", color, 1), color);
                  var ren = new SimpleRenderer(sym);
                  l.setRenderer(ren);

                  app.map.addLayer(l);

                  // Ticket 974: redraw all active reference layers so they appear on top Native and HUC 8 layers
                  redrawReferenceLayers();

                  app.nativehuc.push({ id: speciesID, layer: l, shown: "1" });
                }
                else {
                  console.log("NO NATIVE RANGE FOR " + speciesID);
                }
              },
              error: function (err) {
                app.handleError(err, this);
              }
            });
          }
        }
      }
      /* END new function for native hucs*/

      // Zoom to continental U.S. extent
      $("#fullextent").click(function () {
        app.map.setExtent(new Extent(app.usExtent.xmin, app.usExtent.ymin, app.usExtent.xmax, app.usExtent.ymax, app.usExtent.spatialReference));
      });

      // Toggle map fullscreen
      $("#resize").click(function () {
        var smallScreen = $("#usgsfooter").is(':visible');
        $("#entire-header").slideToggle();
        $("#navbar").slideToggle(); // needed for new usgs header
        $("#usgsfooter").slideToggle();
        $("#disclaimer").slideToggle();
        if (smallScreen) {
          this.src = "/viewer/newmap/images/icons/shrink.png";
          $("#content").animate({ height: "100%" }, 200);
          $(".menu ul").css("display", "none");
        } else {
          this.src = "/viewer/newmap/images/icons/expand.png";
          $("#content").animate({ height: "63%" }, 200);
          $(".menu ul").fadeIn(700);
        }

        // Refresh accordion to recompute height - ticket #729
        setTimeout(function () {
          $("#accordion").accordion("refresh");
        }, 200);
        setTimeout(function () {
          $("#layerAccordion").accordion("refresh");
        }, 200);
      });

      $("#clearselect").click(function () {
        app.clearSelection();
        app.drawing.redrawPolygons();
      });

      $("#createlink").click(function () {
        createLink();
      });

      $("#override").click(function () {
        // Force query to run again and show all individual points
        app.showLoading();
        app.override = 1;
        createSpecimenLayer(getBoundingBox(app.map.extent), app.params);
      });

      $("#eDNADialogbutton").click(function () {
        $("#eDNADialog").dialog("close");
      });

      $("#eDNADisclaimerbutton").click(function () {
        $("#eDNADisclaimer").dialog("close");
      });

      // Searches for points that lie within evt.geometry (the polygon that was just drawn by the user). Saves these points as "selected" 
      // and draws yellow graphics over the points. The selected symbology depends on which layer is currently active.
      function selectPoints(evt) {
        var graphics, selectionArea, point, id;
        if (app.showingClusters) {
          var clusterLayer = app.map.getLayer("cluster");
          if (clusterLayer) {
            graphics = clusterLayer.graphics;

            if (graphics.length) {
              selectionArea = new Polygon(evt.geometry);

              for (var i = 0; i < graphics.length; i++) {
                point = graphics[i].geometry;

                if (selectionArea.contains(point)) {

                  id = graphics[i].attributes.i;
                  var ids = id.split(",");
                  app.selectedSites = app.selectedSites.concat(ids);

                  // Add yellow 'selected' symbol to map
                  app.map.graphics.add(new Graphic(point, app.symbols.selectedCluster(graphics[i].attributes.s)));
                }
              }

              if (app.selectedSites.length) {
                document.getElementById("clearselect").style.visibility = "visible";
              }
            }
          }
        }
        else if (app.showingSpecimens) {
          var specimenLayer = app.map.getLayer("specs");
          if (specimenLayer) {
            graphics = specimenLayer.graphics;

            if (graphics.length) {
              selectionArea = new Polygon(evt.geometry);

              for (var iii = 0; iii < graphics.length; iii++) {
                point = graphics[iii].geometry;

                if (selectionArea.contains(point)) {

                  id = graphics[iii].attributes.i;

                  // Add/remove from selectedIDs
                  var index = app.selectedIDs.indexOf(id.toString());
                  if (index === -1) {
                    // Add
                    app.selectedIDs.push(id.toString());

                    // Add yellow 'selected' symbol to map
                    app.map.graphics.add(new Graphic(point, app.symbols.selectedSpecimen));
                  }
                }
              }

              if (app.selectedIDs.length) {
                document.getElementById("clearselect").style.visibility = "visible";
              }
            }
          }
        }

        var eDNALayer = app.map.getLayer("eDNA");
        if (eDNALayer) {
          graphics = eDNALayer.graphics;

          if (graphics.length) {
            selectionArea = new Polygon(evt.geometry);

            for (var iii = 0; iii < graphics.length; iii++) {
              point = graphics[iii].geometry;

              if (selectionArea.contains(point)) {

                id = graphics[iii].attributes.i;

                // Add/remove from selectedIDs
                var index = app.selectedeDNAIDs.indexOf(id.toString());
                if (index === -1) {
                  // Add
                  app.selectedeDNAIDs.push(id.toString());

                  // Add yellow 'selected' symbol to map
                  app.map.graphics.add(new Graphic(point, app.symbols.selectedeDNADetection));
                }
              }
            }

            if (app.selectedeDNAIDs.length) {
              document.getElementById("clearselect").style.visibility = "visible";
            }
          }
        }
      }

      function deactivateSelection() {
        if (app.pick) {
          app.selecting = false;
          document.getElementById("startselect").src = "/viewer/newmap/images/icons/highlight1.png";
          app.pick.deactivate();
          app.pick = null;
          app.map.enableMapNavigation();
        }
      }

      $("#startselect").click(function () {
        if (!app.selecting) {
          // selection turned on
          app.selecting = true;
          this.src = "/viewer/newmap/images/icons/highlight2.png";

          // turn off zoom box drawing
          app.zoombox.deactivate();

          deactivatePolygonDrawing();
          deactivateCircleDrawing();

          app.pick = new Draw(app.map);
          app.pick.on("draw-end", selectPoints);
          app.map.disableMapNavigation();
          app.pick.activate("freehandpolygon");
        }
        else {
          deactivateSelection();
        }
      });

      function deactivatePolygonDrawing() {
        app.poly = false;
        document.getElementById("chkPolygon").checked = false;
        if (app.tb) {
          app.tb.deactivate();
        }
      }
      function deactivateCircleDrawing() {
        document.getElementById("chkCircle").checked = false;
        $("#circleControl").slideUp();
      }

      function deactivateWKT() {
        if (document.getElementById("wkt")) {
          document.getElementById("chkWKT").checked = false;
          document.getElementById("wkt").value = "";
          $("#wktControl").slideUp();
          app.wkt = null;
        }
      }

      $("#chkCircle").change(function () {
        if (this.checked) {
          app.wkt = null;

          $("#circleControl").slideDown();

          // turn polygon off
          if (app.poly) {
            app.polygon = null;
            deactivatePolygonDrawing();
            app.map.enableMapNavigation();
          }

          // turn selection drawing off
          deactivateSelection();

          deactivateWKT();
        }
        else {
          // turn circle off
          $("#circleControl").slideUp();
        }
      });

      $("#chkWKT").change(function () {
        if (this.checked) {
          deactivatePolygonDrawing();
          deactivateCircleDrawing();
          $("#wktControl").slideDown();
        }
        else {
          $("#wktControl").slideUp();
        }
      });

      app.poly = false;
      $("#chkPolygon").click(function () {
        if (this.checked) {
          deactivateWKT();
          app.poly = true;

          // turn circle off
          if (app.circle) {
            app.circle = null;
          }
          deactivateCircleDrawing();

          // turn selection drawing off
          deactivateSelection();

          // turn off zoom box drawing
          app.zoombox.deactivate();

          // poly draw test
          app.tb = new Draw(app.map);
          //app.tb.on("draw-end", drawPolygon);
          app.tb.on("draw-end", app.drawing.drawPolygon);

          app.map.disableMapNavigation();
          app.tb.activate("freehandpolygon");
        }
        else {
          app.poly = false;
          app.tb.deactivate();
          app.map.enableMapNavigation();
        }
      });

      // Parses circle inputs (radius, radius units, and point clicked) and draws circle graphic on map.
      function drawHelper(radius, point) {
        app.map.graphics.clear();
        var n = Number(radius);

        var validNumber = !isNaN(n);
        if (parseInt(n)) {
          validNumber = (parseInt(n) >= 0);
        }
        else if (parseFloat(n)) {
          validNumber = (parseFloat(n) >= 0.0);
        }

        if (validNumber && document.getElementById("chkCircle").checked) {
          var unitDDL = document.getElementById("ddlUnit");
          var unit = unitDDL.options[unitDDL.selectedIndex].value;
          var thePoint = point || (app.circle && app.circle.point);

          if (thePoint) {
            app.circle = { "point": thePoint, "radius": n, "unit": unit };
            app.drawing.drawCircle(app.circle);
          }
        }
      }

      $("#ddlUnit").change(function () {
        drawHelper(document.getElementById("radius").value);
      });

      $("#radius").spinner({
        spin: function () {
          drawHelper(this.value);
        },
        stop: function () {
          if (this.value === "0") {
            document.getElementById("radius").value = "1";
          }

          drawHelper(this.value);
        }
      });

      $("#radius").on("keyup", function (e) {
        var val = e.currentTarget.value;

        if (val.indexOf("-") !== -1) {
          val = val.replace(/-/g, "");
          document.getElementById("radius").value = val;
        }

        drawHelper(val);
      });

      // Saves current map state in database and shows user a unique map link to this state
      function createLink() {
        var state = app.createMapState(app.map);

        $.ajax({
          type: "POST",
          url: "/viewer/newmap/NewMapHandler.ashx?s=1",
          data: JSON.stringify(state),
          success: function (guid) {
            if (guid) {
              var url = window.location.protocol + "//" + window.location.host + window.location.pathname + "?id=" + guid;

              // Create new highslide div every time a state is saved
              $("body").append(
                "<div id='" + guid + "' class='highslide-main-content'>" +
                "<textarea id='txtGuid' rows='3' type='text' readonly style='width:360px;margin-top:10px'>" +
                url + "</textarea>" +
                "<button id='btnCopy' type='button' data-clipboard-target='#txtGuid'>Save to Clipboard</button>" +
                " <span id='spanErr'></span></div>"
              );

              var cb = new Clipboard("#btnCopy");
              cb.on("success", function () {
                $("#spanErr").addClass("link-success").html("Link copied to clipboard.");
              });
              cb.on("error", function (e) {
                console.error(e.trigger);
                $("#spanErr").addClass("link-error").html("Your browser could not copy the link. Please copy it automatically.");
              });

              // Return to "basic" Highslide options
              hs.align = "auto";
              hs.dimmingOpacity = 0;

              hs.htmlExpand(null, {
                maincontentId: guid,
                preserveContent: false,
                headingText: "Copy link to share this map",
                width: 368,
                height: 170
              });
            }
            else {
              if (app.blackout) {
                alert('Map links are temporarily disabled due to system maintenance. Please try again at a later date.');
              }
              else {
                alert('An error occurred while saving the map state. Please try again or contact the NAS staff for help.');
              }
            }
          },
          error: function (err) {
            app.handleError(err, this);
          }
        });
      }

      document.getElementById("menuToggle").innerHTML = app.labelHide;

      $("#menuToggle").click(function () {
        toggleAccordion();
      });

      $("#accordion").accordion({
        collapsible: true,
        heightStyle: "fill",
        create: function () { }
      });
      $("#layerAccordion").accordion({
        active: false,
        collapsible: true,
        heightStyle: "content",
        create: function () { }
      });

      // Refresh accordion to recompute height - ticket #729
      $(window).resize(function () {
        $("#accordion").accordion("refresh");
        $("#layerCccordion").accordion("refresh");
      });

      function getBoundingBox(extent) {
        var bottomLeft = webMercatorUtils.xyToLngLat(extent.xmin, extent.ymin);
        var topLeft = webMercatorUtils.xyToLngLat(extent.xmin, extent.ymax);
        var bottomRight = webMercatorUtils.xyToLngLat(extent.xmax, extent.ymin);
        var bl = bottomLeft[0];

        if (bl >= 110 && bl <= 180) { // Try to show Hawaii records if extent passes to west of -180 degrees
          bl = -179.9999;
        }

        return bl + "," + bottomLeft[1] + "," + bottomRight[0] + "," + topLeft[1];
      }

      function createClusterLayer(boundingBox, params) {
        //app.clearSelection();
        app.clearSelectionExcepteDNA(); // recreating the clusterLayer should clear out SpecimenLayer but not eDNALayer. 
        app.drawing.redrawPolygons();

        var cluster = app.map.getLayer("cluster");
        if (cluster) {
          app.map.removeLayer(cluster);
        }

        var curZoom = app.map.getZoom();
        var resolution = app.latResolutions[curZoom] || 0.00000268220901489258;

        if (params) {
          $.ajax({
            type: "POST",
            url: "/viewer/getsites.ashx?SpeciesID=1&bbox=" + boundingBox + "&resolution=" + resolution + "&zoom=" + curZoom + (app.specialMap ? "&special=" + app.specialMap.name : ""),
            dataType: "json",
            data: JSON.stringify(params),
            success: function (result) {
              if (result) {
                cluster = new FeatureLayer(result, { id: "cluster" });
                //document.getElementById("imgDownload").style.visibility = "visible";
                document.getElementById("startselect").style.visibility = "visible";

                // Begin change for issue 165; hide download button if no sites are visible on map 11/27/2024 (change 1 of 3)
                app.numClusterSites = result.featureSet.features.length;
                app.numNonclusterSites = 0;

                if (app.numClusterSites == 0 && app.numNonclusterSites == 0 && app.numEdnaSites == 0) {
                  document.getElementById("imgDownload").style.visibility = "hidden";
                }
                else {
                  document.getElementById("imgDownload").style.visibility = "visible";
                }
                // End change for issue 165

                app.map.addLayer(cluster);
                app.showingClusters = true;

                // Look up specimens when their site is clicked
                cluster.on("click", function (evt) {
                  if (!document.getElementById("chkCircle").checked) {
                    // Add yellow 'selected' symbol to map
                    app.map.graphics.add(new Graphic(evt.graphic.geometry, app.symbols.selectedCluster(evt.graphic.attributes.s)));

                    var ids = evt.graphic.attributes.i.split(",");
                    app.selectedSites = app.selectedSites.concat(ids);

                    document.getElementById("clearselect").style.visibility = "visible";
                  }

                  evt.cancelBubble = true; // Prevents other click events (like PopupTemplate for 2020 Census layer)
                });
              }

              app.hideLoading();
            },
            error: function (err) {
              console.error("Error in createClusterLayer(): " + err);
              app.handleError(err, this);
            }
          });
        }
      }

      function createSpecimenLayer(boundingBox, params) {
        var speclay;
        // start creating individual specimens layer
        $.ajax({
          type: "POST",
          url: "/viewer/GetSpeciesMap.ashx?layer=newmap" + (app.specialMap ? "&special=" + app.specialMap.name : ""),
          dataType: "json",
          data: { params: JSON.stringify(params), colors: JSON.stringify(app.colors), extent: boundingBox, override: app.override },
          success: function (result) {
            if (!app.override && result.max) {
              if (document.getElementById("liMap").className.indexOf("ui-tabs-active ui-state-active") !== -1) {
                $("#dialog").dialog("open");
              }

              // Remove any previous specimen layer that may be visible on the map since extent may have changed
              speclay = app.map.getLayer("specs");
              if (speclay) {
                app.map.removeLayer(speclay);
              }

              app.hideLoading();
            }
            else {
              $("#dialog").dialog("close");

              if (!document.getElementById("saveOverride").checked) {
                app.override = null;
              }

              document.getElementById("sitesVisible2").disabled = false;

              if (result.featureSet.features.length) {
                // Don't show download link for Lionfish
                // WARCNAS-48: reinstating download link for Lionfish
                //if (app.speciesID !== "963") {
                //document.getElementById("imgDownload").style.visibility = "visible";
                //}
                //else {
                //    document.getElementById("imgDownload").style.display = "none";
                //}

                document.getElementById("startselect").style.visibility = "visible";
              }

              // Begin change for issue 165; hide download button if no sites are visible on map 11/27/2024 (change 2 of 3)
              app.numNonclusterSites = result.featureSet.features.length;
              app.numClusterSites = 0;

              if (app.numClusterSites == 0 && app.numNonclusterSites == 0 && app.numEdnaSites == 0) {
                document.getElementById("imgDownload").style.visibility = "hidden";
              }
              else {
                document.getElementById("imgDownload").style.visibility = "visible";
              }
              // End change for issue 165

              speclay = app.map.getLayer("specs");
              if (speclay) {
                app.map.removeLayer(speclay);
              }

              app.specLayer = new FeatureLayer(result, { id: "specs" });

              // Perform point selection on click
              app.specLayer.on("click", function (evt) {
                if (!document.getElementById("chkCircle").checked) {
                  var id = evt.graphic.attributes.i;

                  // Add/remove from selectedIDs
                  var index = app.selectedIDs.indexOf(id);
                  if (index === -1) {
                    // Add
                    app.selectedIDs.push(id.toString());
                    // Add yellow 'selected' symbol to map
                    app.map.graphics.add(new Graphic(evt.graphic.geometry, app.symbols.selectedSpecimen));
                  }
                  else {
                    // Remove
                    app.selectedIDs.splice(index, 1);
                  }

                  document.getElementById("clearselect").style.visibility = "visible";
                }

                evt.cancelBubble = true; // Prevents other click events (like PopupTemplate for 2020 Census layer)
              });

              if (!app.showingClusters) {
                if (app.map.loaded) {
                  app.map.addLayer(app.specLayer);
                  app.hideLoading();
                }
                else { // Delay creating layer until map is loaded
                  setTimeout(function () {
                    app.map.addLayer(app.specLayer);
                  }, 500);
                  app.hideLoading();
                }
              }
              else {
                app.hideLoading();
              }
            }
          },
          error: function (err) {
            app.handleError(err, this);
          }
        });
      }

      function createeDNALayer(boundingBox, params) {
        var eDNAlay;

        // start creating individual specimens layer
        $.ajax({
          type: "POST",
          url: "/viewer/GeteDNAMap.ashx?layer=newmap" + (app.specialMap ? "&special=" + app.specialMap.name : ""),
          dataType: "json",
          data: { params: JSON.stringify(params), colors: JSON.stringify(app.colorseDNA), extent: boundingBox, override: app.override },
          success: function (result) {
            // Begin change for issue 165; hide download button if no sites are visible on map 11/27/2024 (change 3 of 3)
            app.numEdnaSites = result.featureSet.features.length;

            if (app.numClusterSites == 0 && app.numNonclusterSites == 0 && app.numEdnaSites == 0) {
              document.getElementById("imgDownload").style.visibility = "hidden";
            }
            else {
              document.getElementById("imgDownload").style.visibility = "visible";
            }
            // End change for issue 165

            $("#dialog").dialog("close");

            eDNAlay = app.map.getLayer("eDNA");
            if (eDNAlay) {
              app.map.removeLayer(eDNAlay);
            }

            app.eDNALayer = new FeatureLayer(result, { id: "eDNA" });

            // Perform point selection when user clicks on an eDNA Detect/Non-detect
            app.eDNALayer.on("click", function (evt) {
              if (!document.getElementById("chkCircle").checked) { // if "Draw Circle" checkbox is NOT checked
                var id = evt.graphic.attributes.i; // get the eDNA detection ID

                // Add/remove from selectedIDs
                var index = app.selectedeDNAIDs.indexOf(id);
                if (index === -1) {
                  // Add ID to list
                  app.selectedeDNAIDs.push(id.toString());

                  // Add yellow 'selected' symbol to map
                  var theGraphic = new Graphic(evt.graphic.geometry, app.symbols.selectedeDNADetection);
                  theGraphic.shape = 'Square'; // so we can identify this as an eDNA highlight
                  app.map.graphics.add(theGraphic);
                }
                else {
                  // Remove ID from list
                  app.selectedeDNAIDs.splice(index, 1);
                }

                document.getElementById("clearselect").style.visibility = "visible";
              }
              evt.cancelBubble = true; // Prevents other click events (like PopupTemplate for 2020 Census layer)
            });

            if (app.map.loaded) {
              app.map.addLayer(app.eDNALayer);
              app.hideLoading();
            }
            else { // Delay creating layer until map is loaded
              setTimeout(function () {
                app.map.addLayer(app.eDNALayer);
              }, 500);
              app.hideLoading();
            }
            //}
          },
          error: function (err) {
            app.handleError(err, this);
          }
        });

      }

      writeSiteControls();

      writeReferenceLayers();

      function writeReferenceLayers() {
        var i;
        var h = "";
        var grpAdmin = "", grpHydro = "", grpEnviro = "", grpLand = "";

        for (i = 0; i < app.ref.length; i++) {
          var text = "";
          var r = app.ref[i];

          // If this ref layer is a specialMap one, it must match the given map name to be added
          if (r.specialMap) {
            if (app.specialMap && r.specialMap === app.specialMap.name) {
              // add this reference layer
            }
            else {
              continue; // i.e. skip - don't add ref layer
            }
          }

          if (r.href) {
            text = "<a href='" + r.href + "' target='_blank'>" + r.name + "</a>";
          }
          else {
            text = r.name;
          }

          var enabled = (app.zoom >= r.zoom);

          var liID = "";
          var childStyle = "";

          if (r.parent) { // If this layer has a parent, indent it and add an ID so its visibility and be toggled
            liID = " id='childOf" + r.parent + "'";
            childStyle = " style='margin-left:20px;display:none'";
            text = "Labels";
          }

          var referenceLI = "<li" + liID + childStyle + "><label id='esrimapRefLbl" + i + "'" + (enabled ? "" : " title='" + app.refTooltip + "'") + "><input id='esrimapRef" + i +
            "' class='esrimapRef' type='checkbox' value='" + i + "' " + (enabled ? "" : " disabled") + " />&nbsp;" + text + "</label></li>";

          if (r.grp) {
            if (r.grp === "admin") {
              grpAdmin += referenceLI;
            }
            else if (r.grp === "hydro") {
              grpHydro += referenceLI;
            }
            else if (r.grp === "enviro") {
              grpEnviro += referenceLI;
            }
            else if (r.grp === "land") {
              grpLand += referenceLI;
            }
          }
          else {
            app.hi("A reference layer is missing a grouping.", "hi-error");
            return false;
          }
        }

        document.getElementById("grpAdmin").innerHTML = grpAdmin;
        document.getElementById("grpHydro").innerHTML = grpHydro;
        document.getElementById("grpEnviro").innerHTML = grpEnviro;
        document.getElementById("grpLand").innerHTML = grpLand;

        // Displays reference layer and adds layer to custom legend if applicable.
        app.showRef = function (r, chkID) {
          // Find child layer checkbox and display it
          for (var rr = 0; rr < app.ref.length; rr++) {
            if (app.ref[rr].parent === r.id) {
              document.getElementById("childOf" + r.id).style.display = "block";
              break;
            }
          }

          if (r.cachedLayer) {
            // Ticket #794: Esri 3.17 causes an error here, whereas versions like 3.14 and 3.16 work
            //
            // If this previous layer was cached, add it back without querying it again.
            app.map.addLayer(r.cachedLayer);

            if (chkID) {
              document.getElementById("esrimapRef" + chkID).disabled = false;
            }

            for (i = 0; i < app.legendSymbols.length; i++) {
              if (app.legendSymbols[i].id === r.id) {
                app.legendSymbols[i].show = 1;
              }
            }

            app.createLegend();
          }
          else {
            var layer;

            if (r.feature) {
              // Create feature layer
              var template = new PopupTemplate({
                title: "{NAME}",
                description: "Population: {POP100}"
              });

              layer = new FeatureLayer(r.customUrl, {
                id: r.id,
                outFields: r.outFields,
                infoTemplate: template
              });

              // Green - yellow - red - purple renderer
              var renderer = new ClassBreaksRenderer(null, "POP100");
              renderer.addBreak(0, 500, new SimpleFillSymbol(SimpleFillSymbol.STYLE_SOLID, null, new Color([20, 80, 0, 0.30])));
              renderer.addBreak(500, 2000, new SimpleFillSymbol(SimpleFillSymbol.STYLE_SOLID, null, new Color([84, 230, 0, 0.30])));
              renderer.addBreak(500, 2000, new SimpleFillSymbol(SimpleFillSymbol.STYLE_SOLID, null, new Color([84, 230, 0, 0.30])));
              renderer.addBreak(2000, 3000, new SimpleFillSymbol(SimpleFillSymbol.STYLE_SOLID, null, new Color([111, 230, 0, 0.30])));
              renderer.addBreak(3000, 4000, new SimpleFillSymbol(SimpleFillSymbol.STYLE_SOLID, null, new Color([202, 237, 0, 0.30])));
              renderer.addBreak(4000, 5000, new SimpleFillSymbol(SimpleFillSymbol.STYLE_SOLID, null, new Color([240, 228, 0, 0.30])));
              renderer.addBreak(5000, 6000, new SimpleFillSymbol(SimpleFillSymbol.STYLE_SOLID, null, new Color([242, 178, 0, 0.30])));
              renderer.addBreak(6000, 7000, new SimpleFillSymbol(SimpleFillSymbol.STYLE_SOLID, null, new Color([245, 126, 0, 0.30])));
              renderer.addBreak(7000, 8000, new SimpleFillSymbol(SimpleFillSymbol.STYLE_SOLID, null, new Color([247, 87, 0, 0.30])));
              renderer.addBreak(8000, 9000, new SimpleFillSymbol(SimpleFillSymbol.STYLE_SOLID, null, new Color([240, 25, 0, 0.30])));
              renderer.addBreak(9000, 12000, new SimpleFillSymbol(SimpleFillSymbol.STYLE_SOLID, null, new Color([255, 0, 0, 0.30])));
              renderer.addBreak(12000, 16000, new SimpleFillSymbol(SimpleFillSymbol.STYLE_SOLID, null, new Color([120, 0, 255, 0.30])));
              renderer.addBreak(16000, Infinity, new SimpleFillSymbol(SimpleFillSymbol.STYLE_SOLID, null, new Color([255, 0, 255, 0.30])));

              layer.setRenderer(renderer);

              // Add above styles in renderer to legend
              var html = "<div><span class='legend-title'>2020 Population</span></div>";
              for (i = 0; i < renderer.infos.length; i++) {
                var info = renderer.infos[i];
                var min = info.minValue;
                var max = info.maxValue;
                var color = info.symbol.color;

                html += "<div><div style='margin-left:2px;margin-right:4px;width:16px;height:16px;float:left;background-color:rgba(" +
                  color.r + "," + color.g + "," + color.b + "," + color.a + ")'></div> <span class='legend-item'>" +
                  min + (max === Infinity ? "+" : " - " + max) +
                  "</span></div>" +
                  "<div style='clear:both;margin-bottom:2px'></div>";
              }

              r.cachedLayer = layer; // Cache layer for future use

              // hack to legendSymbol that contains h
              var symbolInfo = {
                id: r.id,
                html: html,
                show: 1
              };

              app.legendSymbols.push(symbolInfo); // Save symbolInfo so that it will be seen by createLegend()
              app.createLegend();
            }
            else if (r.customUrl) {
              //if (r.customUrl.indexOf("https://services1.arcgis.com/Hp6G80Pky0om7QvQ") > -1 ||
              //    r.customUrl.indexOf("https://services3.arcgis.com/3v060JiGlgJytIRe") > -1) {

              if (r.customUrl.indexOf("https://services3.arcgis.com/3v060JiGlgJytIRe") > -1) {
                // AGOL layers
                layer = new FeatureLayer(r.customUrl, {
                  id: r.id,
                  opacity: r.opacity
                });

                var line = new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([0, 0, 0]), 1);
                layer.renderer = new SimpleRenderer(line);
              }
              else {
                // Added to accommodate offsite layers such as National Map Congressional Districts

                if (r.id.indexOf("_label") > -1) {
                  // Labels can be dynamic
                  var imgParams = new ImageParameters();
                  imgParams.layerIds = r.layerIDs; // NOTE: this is an array of IDs
                  imgParams.layerOption = ImageParameters.LAYER_OPTION_SHOW;
                  imgParams.transparent = true;

                  // r here is ref[i]
                  layer = new DynamicServiceLayer(r.customUrl, {
                    id: r.id,
                    imageParameters: imgParams,
                    opacity: r.opacity
                  });
                }
                else {
                  // Ticket 974: feature layers to get ordering working
                  layer = new FeatureLayer(r.customUrl + "/" + r.layerIDs[0], {
                    id: r.id,
                    opacity: r.opacity
                  });
                }
              }

              r.cachedLayer = layer; // Cache layer for future use

              // HACK for counties (legend endpoint on AGOL does not work, so hard-coding image to add to legend)
              if (r.id === "NAS_counties_2017") {
                var symbolInfo = {
                  layerName: "Counties",
                  legend: [{
                    label: "",
                    imageData: "iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAYAAAA7bUf6AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAL0lEQVQ4y+3UsQ0AIBDDQBux/8phB3iJJh7gSguExzZAEm8BNYuBihQp8hFx4icHEtUGIWXbIgwAAAAASUVORK5CYII=",
                    contentType: "image/png"
                  }]
                };

                symbolInfo.id = r.id;
                symbolInfo.show = 1;
                symbolInfo.opacity = r.opacity;

                app.legendSymbols.push(symbolInfo); // Save symbolInfo so that it will be seen by createLegend()

                app.createLegend();
              }
              else if (r.legend) {
                // Retrieve JSON describing layer symbology
                $.ajax({
                  url: r.customUrl + "/legend?f=json",
                  success: function (json) {
                    // Some services return a JSON object instead of string
                    if (typeof (json) !== "object") {
                      json = JSON.parse(json);
                    }

                    if (json.layers) {
                      for (i = 0; i < json.layers.length; i++) {
                        if (json.layers[i].layerId === r.layerIDs[0]) { // HACK! - layerIDs can have multi-values
                          var symbolInfo = json.layers[i];

                          symbolInfo.id = r.id;
                          symbolInfo.show = 1;
                          symbolInfo.opacity = r.opacity;

                          app.legendSymbols.push(symbolInfo); // Save symbolInfo so that it will be seen by createLegend()

                          break;
                        }
                      }
                    }
                    else {
                      // Cf. ticket #888: show error message when a layer fails
                      var err = "Reference layer error";

                      if (json && json.error) {
                        if (json.error.code) {
                          err += " (" + json.error.code + ")";
                        }
                        if (json.error.message) {
                          err += ": " + json.error.message;
                        }
                      }

                      app.hi(err, "hi-error");
                    }

                    app.createLegend();
                  },
                  error: function (err) {
                    app.handleError(err, this, "someoneElsesFault");
                  }
                });
              }
            }
            else {
              console.error("Unsupported - no longer using services on nwrcgis10");
            }

            app.map.addLayer(layer);

            // Enable checkbox only after layer is added
            app.map.on("layer-add-result", function (layer) {
              if (chkID) {
                document.getElementById("esrimapRef" + chkID).disabled = false;
              }
            });
          }
        };

        hideRef = function (r) {
          // Find child layer checkbox and hide it
          for (var rr = 0; rr < app.ref.length; rr++) {
            if (app.ref[rr].parent === r.id) {
              var chk = document.getElementById("esrimapRef" + rr);
              chk.checked = false; // Uncheck the child layer checkbox
              hideRef(app.ref[rr]); // Turn off the child layer if it's on
              document.getElementById("childOf" + r.id).style.display = "none";
              break;
            }
          }

          var layerOnMap = app.map.getLayer(r.id);

          if (layerOnMap) {
            app.map.removeLayer(layerOnMap);

            if (r.legend || r.id === "NAS_counties_2017") {
              // Set "show" to null so that this layer will be removed from custom legend
              for (var i = 0; i < app.legendSymbols.length; i++) {
                if (app.legendSymbols[i].id === r.id) {
                  app.legendSymbols[i].show = null;
                  break;
                }
              }

              app.createLegend();
            }
          }
        };

        handleRef = function (id) {
          var zoom = app.map.getZoom();
          var r = app.ref[id];
          var chk = document.getElementById("esrimapRef" + id);
          var lbl = document.getElementById("esrimapRefLbl" + id);

          if (zoom >= r.zoom) {
            chk.disabled = false;
            lbl.title = "";

            var layerOnMap = app.map.getLayer(r.id);
            if (layerOnMap && !chk.checked) {
              hideRef(r);
            }
            else if (chk.checked) {
              chk.disabled = true; // Disable this checkbox and don't re-enable it until layer is drawn, to prevent bug when user rapidly clicks checkbox

              app.showRef(r, id);

              // Handle HUC 2, 6, 8 order
              reorderHUCs(r);
            }
          }
          else {
            chk.disabled = true;
            chk.checked = false;
            lbl.title = app.refTooltip;
            hideRef(r);
          }
        };

        // Handle ref changing
        $(".esrimapRef").click(function (e) {
          var id = e.target.id.replace("esrimapRef", "");
          this.disabled = true;
          handleRef(id);
        });
      }

      // Redraws HUC 2 on top 6; and HUC 6 on top 8 given the most recent HUC drawn
      function reorderHUCs(layerDrawn) {
        var huc2 = app.map.getLayer("HUC2");
        var ref = null;

        if (layerDrawn.id === "HUC6") {
          // Redraw 2 on top of 6
          if (huc2) {
            ref = getRefGivenID("HUC2");
            hideRef(huc2);
            app.showRef(ref);
          }
        }
        else if (layerDrawn.id === "HUC8") {
          // Redraw 6 and 2 on top of 8 if applicable
          var huc6 = app.map.getLayer("HUC6");
          if (huc6) {
            ref = getRefGivenID("HUC6");
            hideRef(huc6);
            app.showRef(ref);
            reorderHUCs(huc6); // repeat but for HUC 6
          }
          else {
            if (huc2) {
              ref = getRefGivenID("HUC2");
              hideRef(huc2);
              app.showRef(ref);
            }
          }
        }
      }

      function getRefGivenID(id) {
        for (var i = 0; i < app.ref.length; i++) {
          var r = app.ref[i];
          if (r.id === id) {
            return r;
          }
        }
        return null;
      }

      // Redraws all reference layers to comply with Ticket 974
      function redrawReferenceLayers() {
        for (var i = 0; i < app.ref.length; i++) {
          var r = app.ref[i];

          var layerOnMap = app.map.getLayer(r.id);
          if (layerOnMap) {
            hideRef(layerOnMap);
            app.showRef(r);
          }
        }
      }

      // Builds and returns a params object literal containing all parameters to be supplied to a database query.
      function buildParams() {
        // Used to build multi-valued parameters (OR-logic)
        var tempParams = {};
        var inputs = document.getElementsByClassName("inputParam");
        var currentParameter;
        var inLen = inputs.length;

        for (var i = 0; i < inLen; i++) {
          var j = inputs[i];
          var c = j.className.replace("inputParam ", "");
          var theValue = "";
          var index;

          if (c.indexOf("txt") !== -1) {
            index = c.replace("txt ", "");
            theValue = j.value.replace(/'/g, "`");
          }
          else if (c.indexOf("ddl") !== -1) {
            index = c.replace("ddl ", "");
            theValue = j.options[j.selectedIndex].value;
          }
          else if (c.indexOf("range") !== -1) {
            index = c.replace("range ", "");

            // 'range' here applies to a div containing two year inputs
            var years = j.getElementsByTagName("input");
            var start = years[0].value;
            var end = years[1].value;
            var re = /^\d{4}$/;

            if (start.match(re) || end.match(re)) {
              // Possible values:
              // 1)   1962        >= 1962
              // 2)   1962-2007   between 1962 & 2007
              // 3)   -2007       <= 2007
              theValue = start + (end ? "-" : "") + end;
            }
          }

          if (index.indexOf("ui-autocomplete-input") > -1) {
            index = index.replace(" ui-autocomplete-input", "");
          }

          var thisObject = app.searchFields[index];

          // If a non-empty value was supplied...
          if (theValue) {
            currentParameter = { name: thisObject.column, values: [] };
            currentParameter.values.push(theValue);

            // Check if we've processed a value for this in a previous loop iteration
            if (!tempParams[thisObject.column]) {
              // Store in tempParams so that we can add more values to it later in this loop
              tempParams[thisObject.column] = currentParameter;
            }
            else {
              // Store another value in this temp object's "values'
              tempParams[thisObject.column].values.push(theValue);
            }
          }
        }

        var params = [];

        // Move temporary parameters into params
        for (var x in tempParams) {
          if (x) {
            params.push(tempParams[x]);
          }
        }

        // Include species from taxonomic tree
        if (app.treeIDs.length) {
          params.push({ name: "tree", values: app.treeIDs });
        }

        // Parse and handle WKT string
        if (document.getElementById("wkt") && document.getElementById("chkWKT").checked) {
          // esri doesn't like spaces after the comma between polygon within a multipolygon
          var wkt = document.getElementById("wkt").value.replace(/[)], /gi, "),");
          //  var wkt = document.getElementById("wkt").value;

          if (!wkt) {
            app.hi("Please supply well-known text to draw a polygon.", "hi-error");
            return false;
          }

          app.circle = null;
          app.polygon = null;
          app.geometry = null;

          params.push({ name: "wkt", values: [wkt] });

          var poly = app.wktToEsriPolygon(Polygon, wkt);

          if (!poly) {
            app.hi("The WKT is either invalid or not yet supported by this map.", "hi-error");
            return false;
          }
          else if (poly.isSelfIntersecting(poly)) {
            app.hi("The map cannot process a polygon that crosses itself. Please draw a new one.", "hi-error");
            return false;
          }
          else {
            // WKT zooming isn't as easy as zooming after a draw event. Zooming at this point in code calls buildParams() again which would cause an
            // infinite loop, so look at whether WKT has changed to decide whether to zoom to its polygon.
            if (!app.wkt || app.wkt !== wkt) {
              app.wkt = wkt;
              app.map.setExtent(poly.getExtent().expand(1.5));
            }
          }
        }

        // Validate circle radius
        if (app.circle && (!isNaN(app.circle.radius) && (parseInt(app.circle.radius) >= 0 || parseFloat(app.circle.radius) >= 0))) {
          params.push({ name: "circle", values: [app.circleX, app.circleY, app.circle.radius, app.circle.unit] });
        }

        if (app.polygon) {
          params.push({ name: "polygon", values: [app.polygon.join("|")] });
        }

        // Add special "not" parameter to exclude speciesIDs in excluded array. This is done only if there are other parameters
        // since a small exclusion list by itself would often yield a very large search result.
        if (app.excluded.length && params.length) {
          params.push({ name: "not", values: app.excluded });
        }
        if (app.excludedeDNA.length && params.length) {
          params.push({ name: "exclude_eDNA", values: app.excludedeDNA });
        }



        //if (app.specialMap) {

        //    if (app.specialMap.queryOnLoad) {
        //        // For ANSTF maps, NAS wants full query of data on page load. Do this by adding a parameter with values of 
        //        // each ANSTF state if there are not yet any other parameters specified.
        //        if (!params.length) {
        //            var vals = [];
        //            for (var k = 0; k < app.specialMap.states.length; k++) {
        //                vals.push(app.specialMap.states[k].id);
        //            }
        //            params.push({ name: "state", values: vals });
        //        }
        //    }
        //}

        // Cache parameters that were just built
        app.params = params;

        return params;
      }

      $(".doSearch").click(function () {
        app.hi();
        app.showLoading();

        // Since we are resetting the search, the "eDNA" tab should be hidden 
        document.getElementById("lieDNARecords").style.display = "none";

        // if the 'edNA Records' tab was the active one, we need to redirect user to the "Map" tab
        if (document.getElementById("lieDNARecords").className.indexOf(" ui-tabs-active ui-state-active") !== -1) {
          // take user back to 'Map' tab (index 0)
          $("#tabR").tabs({
            active: 0
          });
        }

        // Clear out excluded Species IDs in preparation for a new query
        app.excluded = [];
        app.excludedeDNA = [];

        removeNativeRanges();

        if (app.geometry) {
          // If a polygon has been drawn, zoom to it first before querying (query will happen on extent-change)
          app.redrawSpecimens = true;
          app.map.setExtent(app.geometry.getExtent().expand(1.5));

          // Turn off drawing tools if they were previously activated
          deactivatePolygonDrawing();
          deactivateCircleDrawing();
          app.map.enableMapNavigation();
        }
        else {
          // Otherwise, perform query immediately
          doQuery(true);
        }

        app.clearSelection();
        app.drawing.redrawPolygons();
      });

      // Redraw accordion to keep it from extending onto disclaimer during fullsize and tab toggling
      $("#liQuery").click(function () {
        $("#accordion").accordion("refresh");
      });

      // param reDoSpecies: true will force re-querying species. false is used to NOT re-query when Exclude is clicked
      function doQuery(reDoSpecies) {
        app.querySpecimenRecords = true;
        app.queryeDNARecords = true;
        app.querySpecies = reDoSpecies;

        // Clear color/species ID assignments since search is being completely refreshed
        if (reDoSpecies) {
          for (var i = 0; i < app.colors.length; i++) {
            app.colorseDNA[i].speciesID = null;
            app.colors[i].speciesID = null;
          }
        }

        document.getElementById("speciesInner").innerHTML = app.waitText;
        document.getElementById("observations").style.display = "none";
        document.getElementById("recordsTab").innerHTML = app.waitText;

        var p = buildParams();
        if (p.length) {
          populateSpecies(p);
        }
        else {
          // Similar to a search reset. Clear most elements from map.
          hideClusters();
          if (app.specLayer) {
            app.map.removeLayer(app.specLayer);
          }
          if (app.eDNALayer) {
            app.map.removeLayer(app.eDNALayer);
          }
          app.hideLoading();

          document.getElementById("speciesInner").innerHTML = app.resetText;
          document.getElementById("recordsTab").innerHTML = app.resetText;
          document.getElementById("eDNArecordsTab").innerHTML = app.resetText;
          document.getElementById("imgDownload").style.visibility = "hidden";
          document.getElementById("startselect").style.visibility = "hidden";
        }

        // Update records if it's the active (currently visible) tab
        if (document.getElementById("liRecords").className.indexOf("ui-tabs-active ui-state-active") !== -1) {
          if (p.length) {
            app.records.populate(p);
          }
        }
        else if (document.getElementById("lieDNARecords").className.indexOf("ui-tabs-active ui-state-active") !== -1) {
          if (p.length) {
            app.eDNArecords.populate(p);
          }
        }
        else {
          // show records msg
          document.getElementById("recordsTab").innerHTML = app.resetText;
        }
      }

      // Remove all parameters and reset map/records/species
      $(".reset-search").click(function () {
        document.getElementById("divParamArea").innerHTML = "";

        if (app.speciesID) {
          if (app.specialMap) {
            window.history.pushState("", "", "/viewer/ANSTF_regions/" + app.specialMap.name + ".aspx");
          }
          else {
            window.history.pushState("", "", "/viewer/omap.aspx");
          }

          app.speciesID = null; // This stops native HUC selection if the user resets and searches again
        }

        app.treeIDs = [];

        if (app.specialMap) {
          // Show clusters by defaults since Reset triggers a potentially large query
          app.showingClusters = true;
          app.showingSpecimens = false;
          document.getElementById("sitesVisible1").checked = true;
          document.getElementById("sitesVisible2").checked = false;

          if (app.specialMap) {
            // MAPAIS wants to show Genus, Species, Common Name
            addParameter(3, "");
            addParameter(4, "");
            addParameter(5, "");
          }
        }

        // Turn off all reference layers
        for (var k = 0; k < app.ref.length; k++) {
          if (app.ref[k].specialMap) {
            // Keep ANSTF layers on the map
            continue;
          }
          hideRef(app.ref[k]);
          document.getElementById("esrimapRef" + k.toString()).checked = false;
        }

        app.params = "";
        app.circle = null;
        app.polygon = null;
        app.wkt = null;
        app.geometry = null;
        document.getElementById("chkCircle").checked = false;
        document.getElementById("chkPolygon").checked = false;

        if (document.getElementById("wkt")) {
          document.getElementById("chkWKT").checked = false;
          document.getElementById("wkt").value = "";
          $("#wktControl").slideUp();
        }

        $("#circleControl").slideUp();

        // HACK: duplicated code to disable spatial drawing
        if (app.poly) {
          deactivatePolygonDrawing();
          app.map.enableMapNavigation();
        }
        if (app.circle) {
          deactivateCircleDrawing();
        }
        // end hack

        deactivateSelection();

        app.clearSelection();

        app.querySpecies = false;
        app.querySpecimenRecords = false;
        app.queryeDNARecords = false;

        document.getElementById("speciesInner").innerHTML = app.resetText;
        document.getElementById("observations").style.display = "none";
        document.getElementById("recordsTab").innerHTML = app.resetText;
        document.getElementById("imgDownload").style.visibility = "hidden";
        document.getElementById("startselect").style.visibility = "hidden";

        hideClusters();

        // Hide sites
        if (app.specLayer) {
          app.map.removeLayer(app.specLayer);
          app.specLayer = null;
        }

        removeNativeRanges();

        app.huc8.clearHUC8();

        app.hi();

        tree.init();

        // Reset to default extent
        app.map.setExtent(new Extent(app.usExtent.xmin, app.usExtent.ymin, app.usExtent.xmax, app.usExtent.ymax, app.usExtent.spatialReference));
      });

      function removeNativeRanges() {
        for (var i = 0; i < app.nativehuc.length; i++) {
          app.map.removeLayer(app.nativehuc[i].layer);
        }
        app.nativehuc = [];
      }

      // Creates individual-specimen and/or clustered site layers and adds them to map. Layers are populated with data matching params.
      function createLayers(params) {
        app.showLoading();

        if (app.showingClusters) {
          createClusterLayer(getBoundingBox(app.map.extent), params);
        }
        else {
          createSpecimenLayer(getBoundingBox(app.map.extent), params);
        }

        createeDNALayer(getBoundingBox(app.map.extent), params);
      }

      app.clearSelection = function () {
        app.selectedIDs = [];
        app.selectedeDNAIDs = [];
        app.selectedSites = [];
        app.map.graphics.clear();
        document.getElementById("clearselect").style.visibility = "hidden";
        deactivateSelection();
        app.querySpecimenRecords = true; // we may be able to avoid re-querying if we can instead turn off all highlighting.
        app.queryeDNARecords = true;
      };

      app.clearSelectionExcepteDNA = function () {
        app.selectedIDs = [];
        app.selectedSites = [];
        app.map.graphics.clear();
        if (!app.selectedeDNAIDs.length) {
          // don't hide clearselect button if there are still eDNA ID's selected
          document.getElementById("clearselect").style.visibility = "hidden";
        }
        deactivateSelection();
        app.querySpecimenRecords = true; // we may be able to avoid re-querying if we can instead turn off all highlighting.
        //app.queryeDNARecords = true;
      };

      // When user navigates to Species tab
      $("#liSpecies").click(function () {
        if (app.querySpecies) {
          var p = buildParams();
          if (app.params.length || p.length) {
            app.showLoading();
            document.getElementById("speciesInner").innerHTML = app.waitText;
            document.getElementById("observations").style.display = "none";
            populateSpecies(app.params || p);
          }
        }
      });

      // When user navigates to Map tab
      // Re-do the highlighting for individual (non-clustered) specimens and eDNA detections
      // Leave clustered highlighting in place since there is no reverse-highlighting.
      $("#liMap").click(function () {
        document.getElementById("clearselect").style.visibility = "visible"; // enable "clear" option

        if (app.showingSpecimens) {
          // if individual specimens are being shown
          // clear everything; highlighted specimens and highlighted eDNA detections will be redrawn.
          app.map.graphics.clear(); // clears all highlighting

          // re-do individual specimen highlighting based on app.selectedIDs
          for (var i = 0; i < app.selectedIDs.length; i++) {
            for (var j = 0; j < app.specLayer.graphics.length; j++) {
              var id = app.specLayer.graphics[j].attributes.i;
              if (id.toString() === app.selectedIDs[i]) {
                var geo = app.specLayer.graphics[j].geometry;
                app.map.graphics.add(new Graphic(new Point(geo.x, geo.y), app.symbols.selectedSpecimen));
              }
            }
          }
        }

        // If we are clustering, we do not want to remove all highlighting, we want to keep it for clustered layer.
        // So, we delete ONLY the eDNA-specific highlights (which will be squares).
        // It won't hurt anything if we do this in non-clustering mode as well.
        for (var i = 0; i < app.map.graphics.graphics.length; i++) {
          var theGraphic = app.map.graphics.graphics[i];
          if (theGraphic.shape && theGraphic.shape === "Square") {
            app.map.graphics.remove(theGraphic); // remove all square highlights (only eDNA detections are square)
            i--; // this accounts for the fact that the length will decrease once a graphic is deleted
          }
        }

        // Now we re-draw the highlighting for eDNA detections.
        for (var i = 0; i < app.selectedeDNAIDs.length; i++) {
          for (var j = 0; j < app.eDNALayer.graphics.length; j++) {
            var id = app.eDNALayer.graphics[j].attributes.i;
            if (id.toString() === app.selectedeDNAIDs[i]) {
              var geo = app.eDNALayer.graphics[j].geometry;
              var theGraphic = new Graphic(new Point(geo.x, geo.y), app.symbols.selectedeDNADetection);
              theGraphic.shape = 'Square'; // so we can identify this as an eDNA highlight
              app.map.graphics.add(theGraphic);
            }
          }
        }
      });

      // When user navigates to Records tab
      $("#liRecords").click(function () {
        deactivateSelection();

        if (app.querySpecimenRecords || app.selectedIDs.length || app.selectedSites.length) { // we need to re-query if there are selected sites becuase it may change the ordering (selected records are first)
          //if (app.querySpecimenRecords) { // JR I'm not seeing why we need to requery just because we have highlighted records.  Just re-do the highlighting instead.
          //alert('requerying');
          var p = buildParams();

          if (app.params.length || p.length) {
            if (app.selectedSites.length || app.selectedIDs.length) {
              document.getElementById("recordsTab").innerHTML = app.hlText;
            }
            else {
              document.getElementById("recordsTab").innerHTML = app.waitText;
            }

            app.showLoading();
            app.records.populate(app.params || p);
          }
        }
        else {
          //alert('not requerying');
          // Highlight rows matching selected Specimen IDs

          // Check for existing selections
          var tbl = document.getElementById("recordsTab").innerHTML;
          var len = app.selectedIDs.length;

          // clear all highlighting
          tbl = clearHighlighting(tbl);

          if (len) {
            for (var i = 0; i < len; i++) {
              var id = app.selectedIDs[i];

              tbl = tbl.replace("<tr id=\"row" + id + "\">", "<tr id=\"row" + id + "\" class='hl'>");
            }

            //document.getElementById("recordsTab").innerHTML = tbl;
            //app.records.setUpSorting();

          }
          else {
            // If none, then search for any linked to any selected sites
            if (app.selectedSites.length) {
              $.ajax({
                url: "/viewer/GetSpecimenInfo.ashx?sites=" + app.selectedSites.toString() + (app.specialMap ? "&special=" + app.specialMap.name : ""),
                success: function (specs) {
                  app.selectedIDs = specs; // Try saving in global var for later
                  len = specs.length;

                  // clear all highlighting
                  tbl = clearHighlighting(tbl);

                  if (len) {
                    /* TODO: fix dup. code as above */
                    for (var i = 0; i < len; i++) {
                      var id = specs[i];

                      tbl = tbl.replace("<tr id=\"row" + id + "\">", "<tr id=\"row" + id + "\" class='hl'>");
                    }

                    document.getElementById("recordsTab").innerHTML = tbl;
                    app.records.setUpSorting();
                    /* end dup. code as above */


                  }
                },
                error: function (err) {
                  console.error("Error in Records tab: " + err);
                  app.handleError(err, this);
                }
              });
            }
          }
          document.getElementById("recordsTab").innerHTML = tbl;
          app.records.setUpSorting();
          app.records.setUpSpecimenClickEvent(); // set up reverse highlighting, if applicable
        }
      });

      // When user navigates to the eDNA Detections tab
      $("#lieDNARecords").click(function () {
        deactivateSelection();
        //alert(app.selectedeDNAIDs);
        //if (app.queryeDNARecords || app.selectedeDNAIDs.length) { // we need to re-query if there are selected sites becuase it may change the ordering (selected records are first)
        if (app.queryeDNARecords) { // we no longer need to re-query after point selection; we can order existing records in javascript instead
          //if (app.queryeDNARecords) { // JR I'm not seeing why we need to requery just because we have highlighted records.  Just re-do the highlighting instead.
          //alert('requerying');
          var p = buildParams();

          if (app.params.length || p.length) {
            if (app.selectedSites.length || app.selectedeDNAIDs.length) {
              document.getElementById("eDNArecordsTab").innerHTML = app.hlText;
            }
            else {
              document.getElementById("eDNArecordsTab").innerHTML = app.waitText;
            }

            app.showLoading();
            app.eDNArecords.populate(app.params || p);
          }
        }
        else {
          //alert('not requerying');
          // re-query not necessary, but re-do highlighting from scratch

          var tbl = document.getElementById("eDNArecordsTab").innerHTML;
          var len = app.selectedeDNAIDs.length;

          //alert(tbl);

          // clear all highlighting
          tbl = clearHighlighting(tbl);

          // redo highlighting back based on latest list of IDs
          if (len) {
            for (var i = 0; i < len; i++) {
              var id = app.selectedeDNAIDs[i];
              tbl = tbl.replace("<tr id=\"row" + id + "\">", "<tr id=\"row" + id + "\" class='hl'>");
            }
          }

          // If points are stacked on top of each other because they have the same coordinates,
          // only one is selectable on the map.  So find the one, get its coordinates, and also
          // highlight all other records with the same coordinates. 2/21/2023
          tbl = app.HighlighteDNASpeciesWithSameCoordinates(tbl);

          document.getElementById("eDNArecordsTab").innerHTML = tbl;
          app.eDNArecords.setUpSorting();
          // 2/22/2023: After discussion with Matt Neilson, we will not enable reverse highlighting
          // from the eDNA tab at this time.  There are issues when a user unselects some, but not all,
          // points with the same coordinates.
          //app.eDNArecords.setUpeDNAClickEvent(); // set up reverse highlighting
        }
      });

      // This is the first step in running a map query. It builds a list of distinct Species and populates the Species tab. It then 
      // calls createLayers() to create the cluster or specimen layers, taking into account any species marked as excluded by the user.
      function populateSpecies(params) {
        app.querySpecies = false;

        var colorNumber = app.colors.length;

        if (app.querySpecimenRecords) {
          app.records.populate(params);
        }

        document.getElementById("nature").style.display = "none";

        $.ajax({
          type: "POST",
          url: "/viewer/GetSpecies.ashx?s=1" + (app.specialMap ? "&special=" + app.specialMap.name : ""),
          data: JSON.stringify(params),
          dataType: "json",
          success: function (species) {
            var len = species.length;
            // Initialize HTML with help icon
            var html = "<div style='width:274px;text-align:right;padding-top:4px;padding-right:4px'><a id='help-5' href='#' class='highslide help'><img src='/images/icons/question.png' alt='Help' title='Help' /></a></div>";
            var color, s, nativeHucAlreadyShown, nativeHuc, noHTML;

            for (var i = 0; i < len; i++) {
              s = species[i];

              app.excludedeDNA[i] = s.SpeciesID; // all queried species start off as excluded from eDNA display

              // Assign species to a color
              if (i < colorNumber) {
                // Assign specific color
                app.colors[i].speciesID = s.SpeciesID;
                app.colorseDNA[i].speciesID = s.SpeciesID;
                // app.excludedeDNA[i].speciesID = s.SpeciesID;
                color = app.colors[i].color;
              }
              else {
                color = app.defaultColor;
              }

              // HR to separate species
              if (i > 0 && i < len) {
                html += "<div style='clear:both'></div><div><hr /></div><div style='clear:both'></div>";
              }

              // Remove sci name HTML for image alt text
              noHTML = s.SciName.replace("<i>", "").replace("</i>", "").trim();

              nativeHuc = "";
              // Reset any prior HUC 8 queries
              app.huc8.clearHUC8();

              if (i < colorNumber && s.NativeExotic.indexOf("Native") !== -1) {

                // Set this species' Native HUC checkbox to checked if it's already shown on map
                nativeHucAlreadyShown = false;
                for (var n = 0; n < app.nativehuc.length; n++) {
                  if (app.nativehuc[n].id === s.SpeciesID) {
                    if (app.nativehuc[n].layer && app.nativehuc[n].shown === "1") {
                      nativeHucAlreadyShown = true;
                      break;
                    }
                  }
                }

                nativeHuc = "<br /><label><input id='nativeHucChk" + s.SpeciesID + "' type='checkbox' class='nativeRange'" +
                  (s.Excluded ? " disabled" : "") + (nativeHucAlreadyShown ? " checked='true' " : " ") + "/> Native Range</label>";

                // Display NatureServe link if any species in results have native ranges
                document.getElementById("nature").style.display = "block";
              }

              var huc8 = "";
              // For any single species, show its HUC 8 range layer
              if (len === 1) {
                huc8 = "<br /><label><input id='huc8Chk" + s.SpeciesID + "' type='checkbox' class='huc8'/> HUC8 Level Records</label>";

                //if (nativeHuc) { // Push HUC 8 checkbox down below Include and Native Range
                //  huc8 = "<div>" + huc8 + "</div>";
                //}
              }

              var eDNA = "";
              // add eDNA checkbox IF the species has at least one eDNA detection record with the "Display on Point Map" flag set
              if (s.Has_eDNA) {
                // SHOW eDNA layer
                eDNA = "<br /><label><input id='eDNAChk" + s.SpeciesID + "' type='checkbox' class='eDNA' /> eDNA Records<br />&nbsp;&nbsp;&nbsp;&nbsp;(<img src='newmap/images/eDNA_detect.png' alt='green square'> = Detect, <img src='newmap/images/eDNA_nondetect.png' alt='black square'> = Nondetect)</label>";

                //if (nativeHuc || huc8) { // Push eDNA checkbox down if needed
                //  eDNA = "<div>" + eDNA + "</div>";
                //}
              }

              html += "<div " + (s.Excluded ? "class='exclude' " : "") + "class='box-main'>" +
                "<div class='box-img'>" +
                (s.ImageLocation ?
                  "<a href='" + app.imagePath + "XIMAGESERVERX/" + s.ImageLocation.replace("\\", "/") + "' class='highslide pic'>" +
                  "<img src='/Thumbnail.ashx?filename=/XIMAGESERVERX/" + s.ImageLocation.replace("\\", "/") + "&height=80' style='border:0' alt='" + noHTML + "' /> " +
                  "</a>"
                  : "<img src='/ImageUnavailable.gif' class='no-img' alt='Image unavailable' />") +
                "</div>" + // end image

                "<div class='box-info'>" +

                "<a href='/queries/FactSheet.aspx?SpeciesID=" + s.SpeciesID + "' target='_blank' title='Species Profile'>" + s.SciName + "</a>" +
                "<br />" + (s.CommonName ? s.CommonName + "<br />" : "") + s.Group + "<br />" + s.NativeExotic +
                "</div>" + // end species info

                "<div class='box-diam'>" + // last right-most div
                "<div class='diamond' style='background-color:rgba(" + color[0] + "," + color[1] + "," + color[2] + ",1)'></div>" +
                "</div>" + // end diamond

                "<div class='box-chk'>" +
                "<label><input id='chk" + s.SpeciesID + "' type='checkbox' class='ex'" + (s.Excluded ? "" : " checked='true'") + "/> Specimen Records</label>" +
                nativeHuc + huc8 + eDNA + "</div>" + // end checkboxes

                "</div>";
            }

            // add list of excluded eDNA species to the parameters
            // after a fresh query, this will consist of all species since the default is non-visible
            if (app.excludedeDNA.length && params.length) {
              params.push({ name: "exclude_eDNA", values: app.excludedeDNA });
            }

            createLayers(params);

            if (len) {
              document.getElementById("speciesInner").innerHTML = html;
              document.getElementById("observations").style.display = "block";
            }
            else {
              document.getElementById("speciesInner").innerHTML = app.noneText;
              document.getElementById("observations").style.display = "none";
            }

            $(".pic").on("click", function () {
              // Return to "basic" Highslide options
              hs.align = "auto";
              hs.dimmingOpacity = 0;
              return hs.expand(this);
            });

            $(".ex").click(function () {
              var speciesID = this.id.replace("chk", "");
              var nativeHucChk = document.getElementById("nativeHucChk" + speciesID);

              app.querySpecimenRecords = true; // Forces Records to be rebuilt when species is toggled on/off
              app.queryeDNARecords = true; // Forces Records to be rebuilt when species is toggled on/off

              if (!this.checked) {
                // Exclude this species
                // disabled graying out 2/16/2023 because this checkbox now only drives specimen data on map/tab, not disabling of entire species
                //$(this).parent().parent().parent().addClass("exclude");

                app.excluded.push(speciesID);

                // Hide Native Range layer for this species if visible
                //if (nativeHucChk) {
                // nativeHucChk.checked = false;
                // nativeHucChk.disabled = true;

                // for (var i = 0; i < app.nativehuc.length; i++) {
                //   if (app.nativehuc[i].id === speciesID) {
                //     app.map.removeLayer(app.nativehuc[i].layer);
                //     app.nativehuc[i].shown = "";
                //   }
                /// }
                //}
              }
              else {
                // Include this species
                $(this).parent().parent().parent().removeClass("exclude");

                app.excluded.splice(app.excluded.indexOf(speciesID), 1);

                if (nativeHucChk) {
                  nativeHucChk.disabled = false;
                }
              }

              // 8/17 - when species is toggled on/off, do NOT rebuild entire query. Keep query to maintain color assignments.
              // Just need to re-query clusters or specimens as need be.
              var params = buildParams();
              if (params.length) {
                createLayers(params);

                // Update records if it's the active (currently visible) tab
                if (document.getElementById("liRecords").className.indexOf("ui-tabs-active ui-state-active") !== -1) {
                  app.records.populate(params);
                }
              }
            });

            $(".eDNA").click(function () {


              var speciesID = this.id.replace("eDNAChk", ""); // get species ID

              var i = app.excludedeDNA.indexOf(speciesID);

              if (this.checked) {
                // User checked 'eDNA' box
                // show disclaimer
                if (app.showeDNADisclaimer) {
                  $("#eDNADisclaimer").dialog("open");
                  app.showeDNADisclaimer = false;
                }

                var eDNACheckboxList = document.querySelectorAll('[id^="eDNAChk"]');
                var didAnyGetUnchecked = false;

                // make sure 'eDNA Records' tab is not hidden
                document.getElementById("lieDNARecords").style.display = "block";

                for (var j = 0; j < eDNACheckboxList.length; j++) {
                  if (eDNACheckboxList[j].checked && eDNACheckboxList[j].id !== this.id) {  // unselect other eDNA checkboxes, but not the one being selected
                    eDNACheckboxList[j].checked = false;
                    app.excludedeDNA.push(eDNACheckboxList[j].id.replace("eDNAChk", ""));
                    didAnyGetUnchecked = true;
                  }
                }

                if (didAnyGetUnchecked) {
                  // document.getElementById("disclaimer").style.display = "inline";
                  //alert('unselecting others');
                  $("#eDNADialog").dialog("open");
                }

                document.getElementById(this.id).checked = true;

                //Remove species from "Exclude" list(if it exists)
                if (i > -1) {
                  app.excludedeDNA.splice(i, 1);
                }
              }
              else {
                // only one should be active at a time.  So if we un-select it, the 'eDNA Records' tab should disappear.
                document.getElementById("lieDNARecords").style.display = "none";

                // if the 'edNA Records' tab was the active one, we need to redirect user to the "Map" tab
                if (document.getElementById("lieDNARecords").className.indexOf(" ui-tabs-active ui-state-active") !== -1) {
                  // take user back to 'Map' tab (index 0)
                  $("#tabR").tabs({
                    active: 0
                  });
                }

                // User unchecked 'eDNA' box; Add species to "exclude" list (if it doesn't already exist)
                if (i = -1) {
                  app.excludedeDNA.push(speciesID);
                }
              }

              // Why aren't we using this?
              // createeDNALayer(getBoundingBox(app.map.extent), params);

              // 8/17 - when species is toggled on/off, do NOT rebuild entire query. Keep query to maintain color assignments.
              // Just need to re-query clusters or specimens as need be.
              var params = buildParams();
              if (params.length) {
                createeDNALayer(getBoundingBox(app.map.extent), params);
                //  createLayers(params);

                // Update records if it's the active (currently visible) tab
                if (document.getElementById("lieDNARecords").className.indexOf("ui-tabs-active ui-state-active") !== -1) {
                  app.eDNArecords.populate(params);
                }
              }

              app.queryeDNARecords = true;  // If we changed the value of an eDNA checkbox, we definitely have to re-query
            });

            // BEGIN - re-select eDNA checkboxes based on mapState
            if (app.mapState) {
              var p = (JSON.parse(app.mapState)).p; // get parameters, which includes exclude_eDNA array

              var eDNAFromSaveState = []; // array of IDs from savestate

              for (var i = 0; i < p.length; i++) {
                if (p[i].name === 'exclude_eDNA') {
                  eDNAFromSaveState = p[i].values; // pick out the array with name "exclude_eDNA"
                }
              }

              var eDNACheckboxes = document.querySelectorAll('[id^="eDNAChk"]'); // find all eDNA checkboxes on the screen
              var eDNACheckboxIDs = []; // list of species eDNA checkbox IDs

              for (var i = 0; i < eDNACheckboxes.length; i++) {
                eDNACheckboxIDs.push(eDNACheckboxes[i].id.replace("eDNAChk", ""));
              }

              for (var i = 0; i < eDNACheckboxIDs.length; i++) {
                if (!eDNAFromSaveState.includes(eDNACheckboxIDs[i])) {
                  document.getElementById("eDNAChk" + eDNACheckboxIDs[i]).click(); // simulate user clicking on eDNA checkbox
                }
              }
              app.excludedeDNA = eDNAFromSaveState;
              app.mapState = ''; // so we don't restore mapstate a second time 
            }


            // END - re-select eDNA checkboxes based on mapState

            // Turn on any native HUC layers that were in save state
            if (app.hucFromSaveState && app.hucFromSaveState.length) {
              for (var j = 0; j < app.hucFromSaveState.length; j++) {
                var speciesID = app.hucFromSaveState[j];
                document.getElementById("nativeHucChk" + speciesID).checked = true; // Check this species' Native Range box
                toggleNativeHuc(speciesID); // Turn on actual layer
              }
              app.hucFromSaveState = null;
            }
            else if (app.speciesID) {
              // Show native HUC layer for the species ID given
              var chks = document.getElementsByClassName("nativeRange");
              if (chks && chks.length) {
                chks[0].checked = true;
                toggleNativeHuc(app.speciesID);
              }
            }

            $(".nativeRange").click(function () {
              toggleNativeHuc(this.id.replace("nativeHucChk", ""));
            });

            $(".huc8").click(function () {
              app.huc8.toggleHUC8(this.id.replace("huc8Chk", ""));

              // Redraws all reference layers to comply with Ticket 974
              redrawReferenceLayers();
            });

            $(".eDNA").click(function () {
              // createeDNALayer(getBoundingBox(app.map.extent), params);
            });
          },
          error: function (err) {
            console.error("Error in populateSpecies(): " + err);
            app.handleError(err, this);
          }
        });
      }

      /* PARAMETER MENU */

      // Build first level of tree
      tree.init();

      // Build Advanced Search parameter menu
      var ddl = "<select id='paramSelect'><option>(Select search fields)</option>";

      for (var z = 0; z < app.searchFields.length; z++) {
        var field = app.searchFields[z];

        // Add Species ID as a "hidden" parameter
        if (field.inputType !== "h") {
          ddl += "<option value='" + z + "'>" + field.title + "</option>";
        }
      }
      ddl += "</select>";

      document.getElementById("divDDL").innerHTML = ddl;

      if (app.specialMap) {
        // MAPAIS wants to show Genus, Species, Common Name
        if (!app.mapState) {
          addParameter(3, "");
          addParameter(4, "");
          addParameter(5, "");
        }
      }

      // Handle change event
      $("#paramSelect").change(function () {
        var val = this.options[this.selectedIndex].value;
        addParameter(val);
        this.selectedIndex = 0;
      });

      // Adds new HTML element to allow parameter input
      //   val: Index of app.searchFields array
      //   defaultValue: optional value of the parameter (e.g. used for .aspx?speciesid=)
      function addParameter(val, defaultValue) {
        var item = app.searchFields[val];
        var inputType = item.inputType;
        var title = item.title;
        var rem = "<span class='remove' aria-label='Remove field' title='Remove field'>&times;</span>";
        var paramDiv = "paramDiv" + val;
        var restOfHTML;
        var randID = "p" + (Math.random() * 100000).toFixed(0); // Create random ID to focus on new parameter element

        // val inside <input> will be used in buildParams() to lookup parameter object in app.searchFields array
        switch (inputType) {
          case "t":
            // TEXT input

            restOfHTML = "<br /><input id='" + randID + "' class='inputParam txt " + val + "' maxlength='" +
              (item.maxLength ? item.maxLength : "80") +
              "' type='text'" + (defaultValue ? " value='" + defaultValue + "'" : "") + " /></label> " + rem +
              "</div></div>";

            if ($("." + paramDiv).length) {
              // Insert additional fields with OR logic
              $("." + paramDiv).last().after(
                "<div class='" + paramDiv + "'><div class='ui-widget'><label><span class='paramOr'>(OR)</span>" + restOfHTML
              );
            }
            else {
              // Insert first field
              $("#divParamArea").append(
                "<div class='" + paramDiv + " first'><div class='ui-widget'><label><span class='paramTitle'>" + title + "</span>" + restOfHTML
              );
            }

            addAutoComplete(randID, item.column);

            break;
          case "d":
            // DROPDOWN input (select list)
            var o = item.options;
            var len = o.length;

            var opts = "";
            for (var i = 0; i < len; i++) {

              if (o[i].id) {
                // id, name
                opts += "<option value='" + o[i].id + "'" + (o[i].id === defaultValue ? " selected" : "") + ">" + o[i].name + "</option>";
              }
              else {
                // single value
                opts += "<option" + (o[i] === defaultValue ? " selected" : "") + ">" + o[i] + "</option>";
              }
            }

            restOfHTML = "<br /><select id='" + randID + "' class='inputParam ddl " + val + "'>" + opts + "</select></label> " + rem + "</div></div>";

            if ($("." + paramDiv).length) {
              // Insert additional fields with OR logic
              $("." + paramDiv).last().after(
                "<div class='" + paramDiv + "'><div><label><span class='paramOr'>(OR)</span>" + restOfHTML
              );
            }
            else {
              // Insert first field
              $("#divParamArea").append(
                "<div class='" + paramDiv + " first'><div><label><span class='paramTitle'>" + title + "</span>" + restOfHTML
              );
            }

            break;
          case "r":
            // RANGE input (two textboxes)
            var st, en;
            if (defaultValue) { // Parse potential defaultValue passed in
              if (defaultValue.indexOf("-") === 0) {
                en = defaultValue.replace("-", ""); // End only
              }
              else if (defaultValue.indexOf("-") > 0) {
                st = defaultValue.substring(0, defaultValue.indexOf("-"));
                en = defaultValue.substring(defaultValue.indexOf("-") + 1, defaultValue.length); // Both
              }
              else {
                // Start only
                st = defaultValue;
              }
            }

            restOfHTML = "<br /><input id='" + randID + "' style='width:80px' maxlength='4' type='text'" + (st ? " value='" + st + "'" : "") + " /> to " +
              "<input style='width:80px' maxlength='4' type='text'" + (en ? " value='" + en + "'" : "") + " /></label> " + rem + "</div>";

            if ($("." + paramDiv).length) {
              // Insert additional fields with OR logic
              $("." + paramDiv).last().after(
                "<div class='" + paramDiv + "'><div class='inputParam range " +
                val + "'><label><span class='paramOr'>(OR)</span>" + restOfHTML + "</div>"
              );
            }
            else {
              // Insert first field
              $("#divParamArea").append(
                "<div class='" + paramDiv + " first'><div class='inputParam range " +
                val + "'><label><span class='paramTitle'>" + title + "</span>" + restOfHTML + "</div>"
              );
            }

            break;
          case "h":
            // Add a hidden field - make it behave similar to single text box
            $("#divParamArea").append(
              "<input class='inputParam txt " + val + "' id='" + randID + "' type='hidden' " + (defaultValue ? " value='" + defaultValue + "'" : "") + " />"
            );
            break;
          default:
            break;
        }

        document.getElementById("btnReset").style.visibility = "visible";
        document.getElementById(randID).focus();
      }
      /* END PARAMETER MENU */

      function addAutoComplete(inputID, column) {
        var method;
        var special = ", specialName:''";

        if (app.specialMap) {
          // handle special-case maps like MAPAIS region
          special = (app.specialMap.name ? ", specialName: '" + app.specialMap.name + "'" : "");
        }

                /*if (column === "specimen_ID") {
                    method = "GetSpecimenID";
                }
                else*/ if (column === "County") {
          method = "GetCounties";
        }
        else if (column === "Family") {
          method = "GetFamilyForMap";
        }
        else if (column === "Genus") {
          method = "GetGenusForMap";
        }
        else if (column === "Species") {
          method = "GetSpeciesForMap";
        }
        else if (column === "common_name") {
          method = "GetCommonNameForMap";
        }
        else if (column === "HUC8_name") {
          method = "GetHUC8Name";
        }
        else if (column === "HUC8_number") {
          method = "GetHUC8Number";
        }
        else if (column !== "specimen_ID") {
          console.log("Unhandled autocomplete column " + column);
        }

        if (method) {
          $("#" + inputID).autocomplete({
            source: function (request, response) {
              $.ajax({
                type: "POST",
                data: "{prefixText:'" + request.term.replace(/'/g, "`") + "', count: 10" + special + "}",
                url: "/Services/AutoCompleteServicePublic.asmx/" + method,
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                success: function (results) {
                  response(results.d);
                }
              });
            },
            minLength: 2
          });
        }
      }

      // Species tree click event
      $(document).on("click", ".tree-chk", function () {
        var speciesID = this.value;

        if (this.checked) {
          app.treeIDs.push(speciesID);
        }
        else {
          app.treeIDs.splice(app.treeIDs.indexOf(speciesID), 1);
        }

        doQuery(true);
      });

      // smatis - Opens and close accordion and shifts map and toolbar
      function toggleAccordion() {
        if (document.getElementById("mainMenu").style.left !== "-300px") {
          $("#mainMenu").animate({ left: "-=300" }, 600);
          document.getElementById("menuToggle").innerHTML = app.labelShow;
          $("#menuToggle").animate({ left: "-=300" }, 200);
          document.getElementById("main").style.left = 0;
          document.getElementById("loading").style.left = "200px";
        }
        else {
          $("#mainMenu").animate({ left: "+=300" }, 600);
          document.getElementById("menuToggle").innerHTML = app.labelHide;
          $("#menuToggle").animate({ left: "+=300" }, 200);
          document.getElementById("main").style.left = "300px";
          document.getElementById("loading").style.left = "500px";
        }
      }

      function createBasemaps(initialBasemap) {
        var basemaps = [];

        // Topo
        var _topo = new BasemapLayer({
          url: "https://www.arcgis.com/sharing/rest/content/items/27e89eb03c1e4341a1d75e597f0291e6/resources/styles/root.json",
          type: "VectorTile"
        });
        var topo = new Basemap({
          id: "topo",
          layers: [_topo],
          title: "Topographic",
          thumbnailUrl: "/viewer/newmap/images/topo.jpg"
        });
        basemaps.push(topo);

        // National Map (USGS)
        var _national = new BasemapLayer({
          url: "https://basemap.nationalmap.gov/arcgis/rest/services/USGSTopo/MapServer"
        });
        var national = new Basemap({
          id: "national",
          layers: [_national],
          title: "National Map",
          maxZoom: 16, // doesn't seem to do anything
          //thumbnailUrl: "/viewer/newmap/images/topo.jpg"
          thumbnailUrl: "/viewer/newmap/images/topo_usgs.jpg"
        });
        basemaps.push(national);

        // Hydro
        var _hydro = new BasemapLayer({
          url: "https://basemap.nationalmap.gov/arcgis/rest/services/USGSHydroCached/MapServer"
        });
        var hydro = new Basemap({
          id: "hydro",
          layers: [_hydro],
          title: "Hydrologic",
          thumbnailUrl: "/viewer/newmap/images/hydro.jpg"
        });
        basemaps.push(hydro);

        // Streets
        // Disabled 2/21/2025 because there is not currently an equivalent that labels the Gulf of Mexico as "Gulf of America"
        //var _street = new BasemapLayer({
        //  url: "https://services.arcgisonline.com/arcgis/rest/services/World_Street_Map/MapServer"
        //});
        //var street = new Basemap({
        //  id: "streets",
        //  layers: [_street],
        //  title: "Streets",
        //  thumbnailUrl: "/viewer/newmap/images/streets.jpg"
        //});
        //basemaps.push(street);

        // Imagery
        var _sat = new BasemapLayer({
          url: "https://services.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer"
        });
        var sat = new Basemap({
          id: "satellite",
          layers: [_sat],
          title: "Satellite",
          thumbnailUrl: "/viewer/newmap/images/satellite.jpg"
        });
        basemaps.push(sat);

        // Light gray
        // Disabled 2/21/2025 because there is not currently an equivalent that labels the Gulf of Mexico as "Gulf of America"
        //var _gray = new BasemapLayer({
        //  url: "https://services.arcgisonline.com/arcgis/rest/services/Canvas/World_Light_Gray_Base/MapServer"
        //});
        //var gray = new Basemap({
        //  id: "gray",
        //  layers: [_gray],
        //  title: "Grayscale",
        //  thumbnailUrl: "/viewer/newmap/images/gray.jpg"
        //});
        //basemaps.push(gray);

        // Dark gray
        // Disabled 2/21/2025 because there is not currently an equivalent that labels the Gulf of Mexico as "Gulf of America"
        //var _dark = new BasemapLayer({
        //  url: "https://services.arcgisonline.com/arcgis/rest/services/Canvas/World_Dark_Gray_Base/MapServer"
        //});
        //var dark = new Basemap({
        //  id: "dark-gray",
        //  layers: [_dark],
        //  title: "Dark",
        //  thumbnailUrl: "/viewer/newmap/images/dark.jpg"
        //});
        //basemaps.push(dark);

        // Basic (custom layer from mxd)
        var _basic = new BasemapLayer({
          url: "https://nas.er.usgs.gov/ag-nasgeo01/rest/services/NAS2/nas/MapServer",
          //visibleLayers: [7, 9, 12, 13]
          visibleLayers: [9, 11, 14, 15]
        });
        var basic = new Basemap({
          id: "basic",
          layers: [_basic],
          title: "Basic",
          thumbnailUrl: "/viewer/newmap/images/basic.jpg"
        });
        basemaps.push(basic);

        // Dark gray
        // Disabled 2/21/2025 because there is not currently an equivalent that labels the Gulf of Mexico as "Gulf of America"
        //var _dark = new BasemapLayer({
        //  url: "https://services.arcgisonline.com/arcgis/rest/services/Canvas/World_Dark_Gray_Base/MapServer"
        //});
        //var dark = new Basemap({
        //  id: "dark-gray",
        //  layers: [_dark],
        //  title: "Dark",
        //  thumbnailUrl: "/viewer/newmap/images/dark.jpg"
        //});
        //basemaps.push(dark);

        app.gallery = new BasemapGallery({
          map: app.map,
          basemaps: basemaps,
          showArcGISBasemaps: false
        }, "basemaps");

        app.gallery.startup();

        if (!app.gallery.getSelected()) {
          if (app.basemap.id == 'basic') {
            app.gallery.select('basic');
          }
          else {
            app.gallery.select(initialBasemap);
          }

          if (app.gallery.getSelected()) {
            app.basemap = app.gallery.getSelected(); // if we're entering from a saved state, nothing will be selected but we already have the basemap from the savestate.
     
            // serviceInfoResponse is bulky and not necessary.  For satellite layer, it causes
            // issues with non-escaped equal signs.  So, we just strip it out.
            for (var j = 0; j < app.basemap.layers.length; j++) {
              app.basemap.layers[j].serviceInfoResponse = "";
            }
          }
          app.map.setBasemap(app.basemap);
        }

        // Set to initial
        //if (initialBasemap && app.gallery.getSelected() && initialBasemap !== app.gallery.getSelected().id) {
        //  app.gallery.select(initialBasemap);
        //}
      }

    }); // End require

  $("#sitesVisible1").click(function () {
    showLayer();
  });

  function writeSiteControls() {
    if (app.showingSpecimens) {
      document.getElementById("sitesVisible2").checked = true;
    }

    $("#sitesVisible2").click(function () {
      showLayer();
    });
  }

  function hideClusters() {
    var cluster = app.map.getLayer("cluster");
    if (cluster) {
      app.map.removeLayer(cluster);
    }
  }

  // This function toggles between "specimens" and "clustered sites" layers
  function showLayer() {
    var layerCheckboxes = document.getElementsByName("sitesVisible");

    // Clear any selected points or clusters
    app.clearSelection();
    app.drawing.redrawPolygons();

    if (layerCheckboxes.length > 1) {
      if (app.showingSpecimens && layerCheckboxes[0].checked) {
        app.showLoading();

        // Hide specimens layer
        if (app.specLayer) {
          app.map.removeLayer(app.specLayer);
        }

        // Re-query clusters and show cluster layer
        createNewClusterLayer();

        app.showingSpecimens = false;
        app.showingClusters = true;
      }

      if (!app.showingSpecimens && layerCheckboxes[1].checked) {
        app.showLoading();

        hideClusters();

        // Show specimens layer
        createNewSpecimenLayer();

        app.showingSpecimens = true;
        app.showingClusters = false;
      }

      // If user is viewing Records tab and switches from one layer to another, redraw Records to enable/disable reverse-record highlighting
      if (document.getElementById("liRecords").className.indexOf("ui-tabs-active ui-state-active") !== -1) {
        app.records.populate(app.params);
      }
    }
  }

  function removeDuplicates(arr) {
    var uniqueValues = [];

    for (i = 0; i < arr.length; i++) {
      if (!uniqueValues.includes(arr[i])) {
        uniqueValues.push(arr[i]);
      }
    }

    return uniqueValues;
  }

  function clearHighlighting(v) {
    // remove class="hl"
    while (v.includes(" class=\"hl\"")) {
      v = v.replace(" class=\"hl\"", "");
    }

    // remove class='hl'
    while (v.includes(" class='hl'")) {
      v = v.replace(" class='hl'", "");
    }

    // remove class=""
    while (v.includes(" class=\"\"")) {
      v = v.replace(" class=\"\"", "");
    }

    // remove class=''
    while (v.includes(" class=''")) {
      v = v.replace(" class=''", "");
    }

    return v;
  }

  // Removes a dynamic parameter
  $(document).on("click", ".remove", function () {
    var thisClass = this.parentNode.parentNode.className;

    // When a text parameter is removed, also remove its autocomplete functionality
    var children = this.previousElementSibling.childNodes;
    for (var k = 0; k < children.length; k++) {
      var child = children[k];
      if (child.className && child.className.indexOf("ui-autocomplete-input") > -1) {
        $("#" + child.id).autocomplete("destroy");
        break; // Breaking since (as of now) only text parameters have autocomplete (and can only be removed one at a time)
      }
    }

    var first = (thisClass.indexOf("first") > -1);

    thisClass = thisClass.replace(" first", "").replace("first", "");

    var numberOfSameParams = $("." + thisClass).length;

    if (numberOfSameParams > 1 && first) {
      // Preserve first element's label
      var label = $(this).parent().parent().find(".paramTitle").html();

      // Set "paramOr" label to be the paramTitle that's being deleted.
      $(this).parent().parent()
        .next()
        .find(".paramOr")
        .html(label)
        .removeClass("paramOr")
        .addClass("paramTitle");

      // Label 'next' elements as the new "first" one
      $(this).parent().parent().next().addClass("first");
    }

    $(this).parent().parent().remove();
  });
});;
"use strict";

app.saveState = {

    // Reads map state passed in and sets app variables to later re-create the map
    readSaveState: function (mapState) {

        require(["esri/geometry/Point", "esri/geometry/Polygon"], function (Point, Polygon) {
            var _saveState = JSON.parse(mapState);

            if (_saveState.n) {
                // _saveState.n contains species IDs whose native HUCs we must show on load. Load the IDs into
                // app.hucFromSaveState to be activated later on within populateSpecies()
                app.hucFromSaveState = [];
                for (var k = 0; k < _saveState.n.length; k++) {
                    app.hucFromSaveState.push(_saveState.n[k]);
                }
            }

            if (_saveState.b) { app.basemap = _saveState.b; }
            if (_saveState.z) { app.zoom = _saveState.z; }
            if (_saveState.e) { app.extent = _saveState.e; }
            if (_saveState.p) {
                // build "tuples" to translate later into "addParameter()" calls
                for (var i = 0; i < _saveState.p.length; i++) {
                    var param = _saveState.p[i];

                    for (var j = 0; j < app.searchFields.length; j++) {

                        var col = app.searchFields[j].column;

                        if (param.name === col) {
                            var tuple = {};
                            tuple.id = j; // "ID" = is simply the position in the app.searchFields array. This "ID" is passed into addParameter() as the first argument
                            tuple.values = [];

                            // Handle all values in p.values
                            for (var qq = 0; qq < param.values.length; qq++) {
                                tuple.values.push(param.values[qq]);
                            }

                            app.paramTuples.push(tuple);
                        }
                    }

                    if (param.name === "tree") {
                        app.treeIDs = param.values;
                    }
                    else if (param.name === "not") {
                        app.excluded = param.values;
                    }
                    else if (param.name === "circle") {
                        var parts = param.values;
                        var radius = parts[2];
                        var point = new Point(parts[0], parts[1]);
                        var unit = parts[3];

                        app.circle = { "point": point, "radius": radius, "unit": unit };

                        // Assign radius and unit
                        document.getElementById("radius").value = radius;
                        var options = document.getElementById("ddlUnit").options;
                        for (var m = 0; m < options.length; m++) {
                            if (options[m].value === unit) {
                                document.getElementById("ddlUnit").selectedIndex = m;
                                break;
                            }
                        }
                    }
                    else if (param.name === "polygon") {
                        var par = param.values[0]; // "-77.27783203125199,19.2996987631317|-78.23913574218945,19.180412737042396|-77.27783203125199,19.2996987631317"
                        var arr = par.split("|");
                        var p = [];
                        for (var gg = 0; gg < arr.length; gg++) {
                            p.push(arr[gg].split(","));
                        }
                        app.temp = p; // Store polygon so it can be drawn later (once remainder of map is set up)
                    }
                    else if (param.name === "wkt") {
                        app.wkt = param.values[0];

                        var poly = app.wktToEsriPolygon(Polygon, app.wkt);

                        if (!poly) {
                            app.hi("The WKT is either invalid or not yet supported by this map.", "hi-error");
                            return false;
                        }
                        else if (poly.isSelfIntersecting(poly)) {
                            app.hi("The map cannot process a polygon that crosses itself. Please draw a new one.", "hi-error");
                            return false;
                        }
                        else {
                            app.tempWKT = poly; // Store polygon WKT so it can be drawn later (once map loads); similar to how drawn polygon is handled above
                        }
                    }
                }
            }

            if (_saveState.l && _saveState.l === "s") {
                app.showingClusters = false;
                app.showingSpecimens = true;
                document.getElementById("sitesVisible2").checked = true;
            }

            // Handle map save state on map load
            if (_saveState.r) {
                // Display any reference layers

                // Store ref layers to be shown
                app.refLayersFromSaveState = [];

                for (i = 0; i < _saveState.r.length; i++) {
                    for (j = 0; j < app.ref.length; j++) {
                        if (_saveState.r[i] === app.ref[j].id) {
                            // Save the ref layer-to-be-shown in an array to be used once map and layer controls have been loaded
                            app.refLayersFromSaveState.push(j);
                        }
                    }
                }
            }
        });
    },

    // Returns true if parameters of state a match those of b exactly
    statesEqual: function (a, b) {
        // compare only a.p and b.p
        var ap = a.p,
            bp = b.p;

        var aLen = ap.length;

        if (aLen === bp.length) {
            for (var i = 0; i < aLen; i++) {
                if (ap[i].name === bp[i].name) {

                    var aVal = ap[i].values,
                        bVal = bp[i].values;

                    var aValLen = aVal.length;

                    if (aValLen === bVal.length) {

                        for (var j = 0; j < aValLen; j++) {
                            if (aVal[j] !== bVal[j]) {
                                return false;
                            }
                        }
                    }
                    else {
                        return false;
                    }
                }
                else {
                    return false;
                }
            }
        }
        else {
            return false;
        }

        return true;
    }
};;
/* global app */

// Returns object describing current state of map
app.createMapState = function () {
  var state = {}, i;

  // in case user has same query criteria entered twice, eliminate duplicates
  for (var j = 0; j < app.params.length; j++) {
    app.params[j].values = removeDuplicates2(app.params[j].values);
  }
  state.p = app.params;
  state.z = app.map.getZoom();
  state.b = app.basemap;
  state.e = app.map.extent;

  if (state.b.id === "national" || state.b.id === "hydro" || state.b.id === "satellite") {
    state.z++;  // correct zoom issue when saving state of these types of base layers.
  }

  // Save reference layers selected
  state.r = [];
  for (i = 0; i < app.ref.length; i++) {
    var r = app.ref[i];

    // Changed 9/13/16 to check app.map layer list instead of r.newLayer. This in effect excludes from the mapstate any
    // layers that were turned on and then turned off.
    var layer = app.map.getLayer(r.id);
    if (layer) {
      state.r.push(r.id);
    }
  }

  // Save which native HUC layers are activated
  state.n = [];
  for (i = 0; i < app.nativehuc.length; i++) {
    var huc = app.nativehuc[i];
    if (huc && huc.shown) {
      state.n.push(huc.id);
    }
  }

  if (!$("#usgsfooter").is(":visible")) {
    state.f = "1"; // Save fullscreen
  }
  if (app.showingSpecimens) {
    state.l = "s";
  }

  return state;
};

// Returns true if a's coordinates match b's
app.extentsEqual = function (a, b) {
  return (a.xmax === b.xmax && a.xmin === b.xmin && a.ymax === b.ymax && a.ymin === b.ymin);
};

app.getColor = function (speciesID) {
  for (var i = 0; i < app.colors.length; i++) {
    if (app.colors[i].speciesID === speciesID) {
      return app.colors[i].color;
    }
  }
  return app.defaultColor;
};

// Change map elements to blend better with dark-gray basemap
app.toggleDarkGrayContrast = function (basemap) {
  if (basemap === "dark-gray") {
    $("#coords").addClass("dark");
    $(".esriScalebarLabel").addClass("scalebar-dark");
  }
  else {
    $("#coords").removeClass("dark");
    $(".esriScalebarLabel").removeClass("scalebar-dark");
  }
};

// Calls service to send an error email; and alerts user 
app.handleError = function (err, state, someoneElsesFault) {
  if (err) {
    if (err.responseText && err.responseText.indexOf("The specified URL cannot be found") !== -1) {
      var msg = "Problem in NAS service";

      if (state) {
        if (state.url) {
          msg += ": " + encodeURIComponent(state.url);
        }
        if (state.type) {
          msg += " (" + state.type + ")";
        }

        $.ajax({
          url: "/Services/Email.ashx?c=s&body=" + msg
        });
      }

      app.hideLoading();

      alert("We're sorry, but part of the NAS map is not working due to an internal USGS error.\n\nThe development team has been emailed and will fix this problem as soon as possible.");
    }
    else if (someoneElsesFault) {
      console.log("third party problem?");
      console.log(err);
      console.log(state);

      $.ajax({
        url: "/Services/Email.ashx?c=s&body=thirdPartyProblem"
      });
    }
    else {
      console.log(err);
      console.log(state);
    }
  }
};

// No longer using regex to parse
app.validPolygonWKT = function (str) {
  str = str.trim().toUpperCase();

  if (str.indexOf("POLYGON") !== 0) {
    return false;
  }
  else {
    var re = /^[-\d.,\s]+$/;

    str = str.replace("POLYGON((", "");
    str = str.replace("POLYGON ((", "");
    str = str.replace("POLYGON  ((", "");
    str = str.replace("))", "");

    // Test that at least "contents" of string contain only certain characters
    if (!re.test(str)) {
      return false;
    }
  }

  return true;
};

app.validMultiPolygonWKT = function (str) {
  str = str.trim().toUpperCase();

  if (str.indexOf("MULTIPOLYGON") !== 0) {
    return false;
  }
  else {
    var re = /^[()-\d.,\s]+$/;

    // HACK: handling spaces that may occur
    str = str.replace("MULTIPOLYGON(", "");
    str = str.replace("MULTIPOLYGON (", "");
    str = str.replace("MULTIPOLYGON  (", "");
    str = str.replace(")))", "))");

    // Test that at least "contents" of string contain only certain characters
    if (!re.test(str)) {
      return false;
    }
  }

  return true;
};

app.wktToEsriPolygon = function (Polygon, wkt) {
  var esriArgs = [];

  if (app.validPolygonWKT(wkt)) {
    var w = wkt.toUpperCase();
    w = w.replace(/\s*\(\s*/g, "(");
    w = w.replace(/\s*\)\s*/g, ")");
    w = w.replace(/,\s*/g, ", ");
    w = w.trim();
    w = w.replace(/\s*POLYGON\s*\(\s*\(\s*/g, "");
    w = w.replace(/\s*\)\s*\)\s*/g, "");

    var arr = w.split(", ");

    var len = arr.length;
    for (var i = 0; i < len; i++) {
      var lonlat = arr[i].split(" ");
      esriArgs.push([parseFloat(lonlat[0]), parseFloat(lonlat[1])]);
    }

    document.getElementById("wkt").value = document.getElementById("wkt").value.trim().toUpperCase();
  }
  else if (app.validMultiPolygonWKT(wkt)) {
    var w = wkt.toUpperCase();
    w = w.replace("MULTIPOLYGON(", "");
    w = w.replace("MULTIPOLYGON (", "");
    w = w.replace(")))", "))");

    var polys = w.split(")),");
    var multi = [];

    for (var i = 0; i < polys.length; i++) {
      var p = polys[i];

      esriArgs = [];

      p = p.replace("((", "").replace("))", "");

      var arr = p.split(", ");

      var len = arr.length;
      for (var j = 0; j < len; j++) {
        var lonlat = arr[j].split(" ");
        esriArgs.push([parseFloat(lonlat[0]), parseFloat(lonlat[1])]);
      }

      multi.push(esriArgs);
    }

    esriArgs = multi;

    document.getElementById("wkt").value = document.getElementById("wkt").value.trim().toUpperCase();
  }
  else {
    app.hi("The WKT is either invalid or not yet supported by this map.", "hi-error");
    return false;
  }

  return new Polygon(esriArgs);
}

function removeDuplicates2(arr) {
  var uniqueValues = [];

  for (i = 0; i < arr.length; i++) {
    if (!uniqueValues.includes(arr[i])) {
      uniqueValues.push(arr[i]);
    }
  }

  return uniqueValues;
};
/* global app */
app.records = {
  populate: function (params, orderBy) {
    if (params && params.length) {
      if (!orderBy) {
        app.order = "";
      }

      app.querySpecimenRecords = false;

      // Build POST values with map parameters and any selected sites or specimens
      var data = { a: JSON.stringify(params) };
      if (app.selectedSites.length) {
        https://nas.er.usgs.gov/viewer/newmap/images/icons/expand.png
        data.sites = app.selectedSites.toString();
      }
      if (app.selectedIDs.length) {
        data.specimens = app.selectedIDs.toString();
      }

      // todo: remove z=1 below - not needed
      $.ajax({
        type: "POST",
        url: "/viewer/GetSpecimenInfo.ashx?z=1" + (orderBy ? "&o=" + orderBy : "") + (app.specialMap ? "&special=" + app.specialMap.name : ""),
        dataType: "json",
        data: data,
        success: function (result) {
          var len = result.Specimens.length;
          var msg = "";
          if (len >= app.maxRecords) {
            var displaying = "";
            if (result.TotalRecords) {
              displaying = app.maxRecords + " of " + result.TotalRecords;
            }
            else {
              displaying = app.maxRecords;
            }
            msg = "<span class='hi-error'>Displaying the first " + displaying + " records. Click Download button to export all records.</span>";
          }
          var table = "<div id='recTop'><b>" + len + " record" + (len > 1 ? "s" : "") + "</b> " +
            "<a id='help-8' href='#' class='highslide help'><img src='/viewer/newmap/images/icons/question.png' style='vertical-align:middle' alt='Help' title='Help' /></a>" +
            "<a href='#' id='btnDownload' class='download' style='margin-left:8px'>" +
            "<img src='/viewer/newmap/images/icons/download.png' style='vertical-align:middle' alt='Download data' title='Download data' />" +
            "</a> " + msg +
            "</div>" +
            "<div id='recTable'>" +
            "<table " + (app.showingSpecimens ? "class='cursorRow' " : "") + "cellspacing='0' cellpadding='5px' style='width:100%;border-collapse:collapse'><thead><tr>" +
            "<th><a href='#' class='sort'>Specimen ID</a></th>" +
            "<th><a href='#' class='sort'>Scientific Name</a></th>" +
            (result.ShowCountry ? "<th><a href='#' class='sort'>Country</a></th>" : "") +
            "<th><a href='#' class='sort'>State</a></th>" +
            "<th><a href='#' class='sort'>County</a></th>" +
            "<th><a href='#' class='sort'>Locality</a></th>" +
            "<th><a href='#' class='sort'>Year</a></th>" +
            "<th><a href='#' class='sort'>HUC 8 Number</a></th>" +
            "<th><a href='#' class='sort'>Drainage Name</a></th>" +
            "<th><a href='#' class='sort'>Accuracy</a></th>" +
            "<th><a href='#' class='sort'>Status</a></th>" +
            "</tr></thead><tbody>";

          for (var i = 0; i < len; i++) {
            var s = result.Specimens[i];
            var cls = (s.Selected || app.selectedIDs.indexOf(s.SpecimenID) !== -1 ? " class='hl'" : "");

            table += "<tr id='row" + s.SpecimenID + "'" + cls + "><td><a href='/queries/SpecimenViewer.aspx?SpecimenID=" + s.SpecimenID + "' target='_blank' />" + s.SpecimenID +
              "</a></td><td>" + s.SciName + "</td>" + (result.ShowCountry ? "<td>" + s.Country + "</td>" : "") + "<td>" + s.State + "</td><td>" + s.County + "</td>" +
              "<td>" + s.Locality + "</td><td>" + s.Year + "</td><td>" + s.HUC8Number + "</td><td>" + s.HUC8Name + "</td><td>" + s.Accuracy + "</td><td>" + s.Status + "</td></tr>";
          }

          document.getElementById("recordsTab").innerHTML = (len ? table + "</tbody></table></div>" : app.noRecordsText);

          app.records.setUpSorting();

          app.hideLoading();


          app.records.setUpSpecimenClickEvent();
        },
        error: function (err) {
          console.error("Error in populateRecords(): " + err);
          app.handleError(err, this);
        }
      });
    }
    else {
      console.log("  - No params supplied. Exiting.");
    }
  }, // end populate()

  setUpSorting: function () {
    $(".sort").click(function () {
      app.showLoading();

      var col = this.innerHTML;

      switch (col) {
        case "Specimen ID":
          col = "specimen_ID";
          break;
        case "Scientific Name":
          col = "Genus, Species, Subspecies, variety";
          break;
        case "HUC 8 Number":
          col = "HUC8_number";
          break;
        case "Drainage Name":
          col = "HUC8_name";
          break;
        case "Accuracy":
          col = "lat_long_accuracy";
          break;
        default:
          break;
      }

      // If same field was just clicked, toggle ascending/descending
      if (app.order === col) {

        if (col.indexOf("Genus, Species, Subspecies, variety") !== -1) {
          col = "Genus DESC, Species DESC, Subspecies DESC, variety DESC";
        }
        else if (col.indexOf("Genus DESC, Species DESC, Subspecies DESC, variety DESC") !== -1) {
          col = "Genus, Species, Subspecies, variety";
        }
        else {
          col = (col.indexOf(" DESC") !== -1 ? col + " ASC" : col + " DESC");
        }
      }

      app.order = col;

      app.records.populate(app.params, col);
    });
  },

  // Reverse-highlighting. Click a record row to highlight its matching specimen on the map (in some cases). The below code adds
  // or removes the specimen ID from app.selectedIDs as necessary. The map tab click event handles the actual graphics.
  setUpSpecimenClickEvent: function () {
    if (app.showingSpecimens) {
      $("#recTable tbody tr").on("click", function () {
        var specimen = this.id.replace("row", "");
        var row = document.getElementById(this.id);
        var index;
        // Toggle row highlighted class and its ID within selectedIDs
        if (row.className.indexOf("hl") === -1) {
          row.className += " hl";
          index = app.selectedIDs.indexOf(specimen);
          if (index === -1) {
            app.selectedIDs.push(specimen);
          }
        }
        else {
          row.className = row.className.replace(" hl", "").replace("hl", "");
          index = app.selectedIDs.indexOf(specimen);
          if (index !== -1) {
            app.selectedIDs.splice(index, 1);
          }
        }
      });
    }
  }


};;
/* global app */
app.eDNArecords = {
  populate: function (params, orderBy) {
    if (params && params.length) {
      if (!orderBy) {
        app.order = "";
      }

      app.queryeDNARecords = false;

      // Build POST values with map parameters and any selected sites or specimens
      var data = { a: JSON.stringify(params) };

      if (app.selectedeDNAIDs.length) {
        data.detections = app.selectedeDNAIDs.toString();
      }

      // todo: remove z=1 below - not needed
      $.ajax({
        type: "POST",
        url: "/viewer/GeteDNADetectionInfo.ashx?z=1" + (orderBy ? "&o=" + orderBy : "") + (app.specialMap ? "&special=" + app.specialMap.name : ""),
        dataType: "json",
        data: data,
        success: function (result) {
          var len = result.Detections.length;
          var msg = "";
          if (len >= app.maxRecords) {
            var displaying = "";
            if (result.TotalRecords) {
              displaying = app.maxRecords + " of " + result.TotalRecords;
            }
            else {
              displaying = app.maxRecords;
            }
            msg = "<span class='hi-error'>Displaying the first " + displaying + " records. Click Download button to export all records.</span>";
          }
          var table = "<div id='recTopeDNA'><b>" + len + " record" + (len > 1 ? "s" : "") + "</b> " +
            "<a id='help-8' href='#' class='highslide help'><img src='/viewer/newmap/images/icons/question.png' style='vertical-align:middle' alt='Help' title='Help' /></a>" +
            "<a href='#' id='btnDownloadeDNA' class='download' style='margin-left:8px'>" +
            "<img src='/viewer/newmap/images/icons/download.png' style='vertical-align:middle' alt='Download data' title='Download data' />" +
            "</a> " + msg +
            "</div>" +
            "<div id='recTableeDNA'>" +
            "<table " + (app.showingSpecimens ? "class='cursorRow' " : "") + "cellspacing='0' cellpadding='5px' style='width:100%;border-collapse:collapse'><thead><tr>" +
            "<th><a href='#' class='sort'>Detection ID</a></th>" +
            "<th><a href='#' class='sort'>Scientific Name</a></th>" +
            (result.ShowCountry ? "<th><a href='#' class='sort'>Country</a></th>" : "") +
            "<th><a href='#' class='sort'>State</a></th>" +
            "<th><a href='#' class='sort'>County</a></th>" +
            "<th><a href='#' class='sort'>Locality</a></th>" +
            "<th><a href='#' class='sort'>Year</a></th>" +
            "<th><a href='#' class='sort'>HUC 8 Number</a></th>" +
            "<th><a href='#' class='sort'>Drainage Name</a></th>" +
            "<th><a href='#' class='sort'>Accuracy</a></th>" +
            "<th><a href='#' class='sort'>Detection Status</a></th>" +
            "<th style=\"display:none\">lat</th>" +
            "<th style=\"display:none\">lon</th>" +
            "</tr></thead><tbody>";

          var LatLongToHighlight = [];

          for (var i = 0; i < len; i++) {
            var s = result.Detections[i];
            var cls = (s.Selected || app.selectedeDNAIDs.indexOf(s.DetectionID) !== -1 ? " class='hl'" : "");

            table += "<tr id='row" + s.DetectionID + "'" + cls + "><td><a href='/eDNA/DetectionRecord.aspx?DetectionID=" + s.DetectionID + "' target='_blank' />" + s.DetectionID + "</a></td><td>"
              + s.SciName + "</td>"
              + (result.ShowCountry ? "<td>" + s.Country + "</td>" : "") + "<td>"
              + s.State + "</td><td>"
              + s.County + "</td><td>"
              + s.Locality + "</td><td>"
              + s.Year + "</td><td>"
              + s.HUC8Number + "</td><td>"
              + s.HUC8Name + "</td><td>"
              + s.Accuracy + "</td><td>"
              + s.DetectionStatus + "</td><td style=\"display:none\">"
              + s.lat + "</td><td style=\"display:none\">"
              + s.lon + "</td></tr>";


          }

          // If points are stacked on top of each other because they have the same coordinates,
          // only one is selectable on the map.  So find the one, get its coordinates, and also
          // highlight all other records with the same coordinates. 2/21/2023
          table = app.HighlighteDNASpeciesWithSameCoordinates(table);

          document.getElementById("eDNArecordsTab").innerHTML = (len ? table + "</tbody></table></div>" : app.noRecordsText);

          app.eDNArecords.setUpSorting();

          app.hideLoading();

          // 2/22/2023: After discussion with Matt Neilson, we will not enable reverse highlighting
          // from the eDNA tab at this time.  There are issues when a user unselects some, but not all,
          // points with the same coordinates.
          //app.eDNArecords.setUpeDNAClickEvent();

          // if (document.getElementById("eDNArecordsTab").innerHTML.replaceAll("\"", "'").includes(app.noRecordsText.replaceAll("\"", "'"))) {
          //   alert('hide tab');
          //
          //   // if 'eDNA Records' tab is active
          //   if (document.getElementById("lieDNARecords").className.indexOf(" ui-tabs-active ui-state-active") !== -1) {
          //     // take user back to 'Map' tab (index 0)
          //     $("#tabR").tabs({
          //       active: 0
          //     });
          //   }
          //
          //   // when we get here we know we are not on the 'eDNA Records' tab
          //   // completely hide the eDNA tab
          //   document.getElementById("lieDNARecords").style.display = "none";
          //   
          // }
          // else {
          //   alert('show tab');
          //   document.getElementById("lieDNARecords").style.display = "block";
          // }
        },
        error: function (err) {
          console.error("Error in populateRecords(): " + err);
          app.handleError(err, this);
        }
      });
    }
    else {
      console.log("  - No params supplied. Exiting.");
    }


  }, // end populate()

  setUpSorting: function () {
    $(".sort").click(function () {
      app.showLoading();

      var col = this.innerHTML;

      switch (col) {
        case "Detection ID":
          col = "detection_ID";
          break;
        case "Scientific Name":
          col = "Genus, Species, Subspecies, variety";
          break;
        case "HUC 8 Number":
          col = "HUC8_number";
          break;
        case "Drainage Name":
          col = "HUC8_name";
          break;
        case "Accuracy":
          col = "lat_long_accuracy";
          break;
        case "Detection Status":
          col = "detection_status";
          break;
        default:
          break;
      }

      // If same field was just clicked, toggle ascending/descending
      if (app.order === col) {

        if (col.indexOf("Genus, Species, Subspecies, variety") !== -1) {
          col = "Genus DESC, Species DESC, Subspecies DESC, variety DESC";
        }
        else if (col.indexOf("Genus DESC, Species DESC, Subspecies DESC, variety DESC") !== -1) {
          col = "Genus, Species, Subspecies, variety";
        }
        else {
          col = (col.indexOf(" DESC") !== -1 ? col + " ASC" : col + " DESC");
        }
      }

      app.order = col;

      app.eDNArecords.populate(app.params, col);
    });
  },

  // Reverse-highlighting. Click a record row to highlight its matching specimen on the map. The below code adds
  // or removes the detection ID from app.selectedeDNAIDs as necessary. The map tab click event handles the actual graphics.
  setUpeDNAClickEvent: function () {
    $("#recTableeDNA tbody tr").on("click", function () {
      var detection = this.id.replace("row", "");
      var row = document.getElementById(this.id);
      var index;
      // Toggle row highlighted class and its ID within selectedeDNAIDs
      if (row.className.indexOf("hl") === -1) {
        row.className += " hl";
        index = app.selectedeDNAIDs.indexOf(detection);
        if (index === -1) {
          app.selectedeDNAIDs.push(detection);
        }
      }
      else {
        row.className = row.className.replace(" hl", "").replace("hl", "");
        index = app.selectedeDNAIDs.indexOf(detection);
        if (index !== -1) {
          app.selectedeDNAIDs.splice(index, 1);
        }
      }
      // if user unselected the last remaining point, we want to start from scratch and requery
      if (app.selectedeDNAIDs.length === 0) {
        app.queryeDNARecords = true;
      }
    });
  }



};;
/* global app */
// Builds species tree menu and checkboxes

var tree = {};

// Builds collapsed tree showing only Group-level nodes
tree.init = function () {
    var groups = app.param_groups;
    var h = "";
    for (var i = 0; i < groups.length; i++) {
        h += "<div id='Group_" + groups[i].replace(" ", "_") + "' class='tree-1'>" +    // Group_Reptiles
            "<span class='treespan closed'>+</span> " + groups[i] + "</div>" +
            "<div id='Sub_Group_" + groups[i].replace(" ", "_") + "'></div>";           // Sub_Group_Reptiles - where children div are placed
    }
    document.getElementById("tree").innerHTML = h;
};

$(document).on("click", ".treespan", function () {
    $(this).toggleClass("open", "closed");

    var id = $(this).parent()[0].id; // Group_Reptiles
    var IsFish = "N/A";

    // The tree is mostly heirarchial, EXCEPT "Fishes" and "Marine Fishes" share some common orders.
    // So we need to know at all levels whether we got there via the "Fishes" or "Marine Fishes" branch so we can query the appropriate subsequent levels.
    // If it is some other group (non-fish) than it IS heirarchial so we don't need this info, we just use a dummy value of "N/A".
    if ($(this).closest("#Sub_Group_Fishes").length > 0)
        IsFish = "Fishes";
    else if ($(this).closest("#Sub_Group_Marine_Fishes").length > 0)
        IsFish = "Marine Fishes";

    if ($(this).html() === "+") {

        $(this).html("-");

        var sub = id.split("_");
        var column = sub[0];
        var search = sub[1];
        var clsName = document.getElementById(id).className;

        var newClass = "";
        if (clsName.indexOf("tree-1") > -1) {
            newClass = "tree-2";
        }
        else if (clsName.indexOf("tree-2") > -1) {
            newClass = "tree-3";
        }
        else if (clsName.indexOf("tree-3") > -1) {
            newClass = "tree-4";
        }
        else if (clsName.indexOf("tree-4") > -1) {
            newClass = "tree-5";
        }

        $.ajax({
            url: "/viewer/newmap/NewMapHandler.ashx?rank=" + column + "," + search + (app.specialMap ? "&special=" + app.specialMap.name : "" + "&IsFish=" + IsFish),
            success: function (results) {
                if (results) {
                    var j;
                    var rank = results.RankName;
                    var values = results.RankValues;

                    if (values.length) {

                        if (rank === "Species") {
                            // add clickable species
                            var species = "";
                            var check;
                            for (j = 0; j < values.length; j++) {

                                // Loop through saved-state 'tree' list and check any matching species that are being added to view
                                check = false;
                                for (var k = 0; k < app.treeIDs.length; k++) {
                                    if (values[j].SpeciesID === app.treeIDs[k]) {
                                        check = true;
                                        break;
                                    }
                                }

                                species += "<div class='" + newClass + "'><label><input class='tree-chk' type='checkbox' value='" +
                                    values[j].SpeciesID + "' " + (check ? "checked='true' " : "") + "/> " + values[j].Name + (values[j].CommonName ? " (" + values[j].CommonName + ")" : "") + "</label></div>";
                            }

                            document.getElementById("Sub_" + id).innerHTML = species;

                        }
                        else {
                            // Add new values below item that was just clicked

                            var html = "";
                            for (j = 0; j < values.length; j++) {
                                html += "<div id='" + rank + "_" + values[j].Name + "' class='" + newClass + "'>" +
                                    "<span class='treespan closed'>+</span> " +
                                    values[j].Name +
                                    "</div>" +
                                    "<div id='Sub_" + rank + "_" + values[j].Name + "'></div>";
                            }

                            document.getElementById("Sub_" + id).innerHTML = html;
                        }
                    }
                }
            }
        });

        // end query
    }
    else {
        $(this).html("+");

        // hide sub-divs
        document.getElementById("Sub_" + id).innerHTML = "";
    }
});;
/* global app */
/* global require */
app.huc8 = function () {
  var huc8 = null;
  var visible = false;
  return {
    clearHUC8: function () {
      // Reset any prior HUC 8 queries
      if (huc8) {
        app.map.removeLayer(huc8);
        huc8 = null;
        visible = false;
      }
    },
    toggleHUC8: function (speciesID) {
      if (huc8) {
        if (visible) {
          app.map.removeLayer(huc8);
          visible = false;
        }
        else {
          app.map.addLayer(huc8);
          visible = true;
        }
      }
      else {
        require([
          "esri/layers/FeatureLayer",
          "esri/symbols/SimpleFillSymbol",
          "esri/symbols/SimpleLineSymbol",
          "esri/renderers/SimpleRenderer",
          "dojo/domReady!"],
          function (FeatureLayer, SimpleFillSymbol, SimpleLineSymbol, SimpleRenderer) {
            $.ajax({
              url: "/viewer/newmap/NewMapHandler.ashx?r=8&speciesid=" + speciesID,
              success: function (huc) {
                if (huc.length) {

                  huc = huc.join("','");

                  var layer = new FeatureLayer(app.warcGeoUrl + "/2", { // NOTE: this uses HUC8 layer (not the old SpeciesHUC8)
                    id: "huc8",
                    definitionExpression: "huc8 IN ('" + huc + "')",
                    opacity: 0.5
                  });

                  var color = "#884545";
                  var sym = new SimpleFillSymbol(SimpleFillSymbol.STYLE_SOLID, new SimpleLineSymbol("solid", color, 1), color);
                  layer.setRenderer(new SimpleRenderer(sym));
                  app.map.addLayer(layer);
                  huc8 = layer;
                  visible = true;
                }
                else {
                  console.log("NO HUC 8 RANGE FOR " + speciesID);
                }
              },
              error: function (err) {
                console.error("Error in toggleHUC8(): " + err);
              }
            });
          });
      }
    }
  };
}();;
"use strict";
app.drawing = {

  // Draws circle graphic onto map
  drawCircle: function (circle) {
    require(["esri/geometry/geometryEngine", "esri/graphic"], function (geoEngine, Graphic) {
      app.polygon = null;

      // Add a graphic representing a radius-unit buffer around the clicked point
      var buffer = geoEngine.geodesicBuffer(circle.point, circle.radius, circle.unit);

      app.map.graphics.add(new Graphic(buffer, app.symbols.lineSymbol));

      // Save geometry for zooming
      app.geometry = buffer;
    });
  },

  drawPolygon: function (evt, wkid) {

    require(["esri/geometry/Polygon", "esri/graphic", "esri/geometry/webMercatorUtils"], function (Polygon, Graphic, webMercatorUtils) {
      var i, ring;
      app.circle = null;
      app.clearSelection();
      app.hi();
      var checkPolygon = new Polygon(evt.geometry.rings);
      var tempGraphic = new Graphic(evt.geometry, app.symbols.lineSymbol);

      // Show the supplied polygon now for user feedback, even if it self-intersects and has to be rejected
      app.map.graphics.add(tempGraphic);

      // Occasionally polygons are created with duplicate points (not including the beginning and end). This causes isSelfIntersecting to return true below when handling
      // a save state. To prevent this, loop through inner vertices below and remove any duplicates. This assumes duplicate points are contiguous in the array.
      ring = evt.geometry.rings[0];
      if (ring.length > 3) {
        // Search between i = 1 and i = n - 1 inclusive and remove any duplicate points
        var previous, current;
        var st = ring.length;

        for (i = 1; i < st - 1; i++) {
          if (i >= ring.length) {
            // i-- below sometimes pushes traversal to the end of the array. Break if this happens since the polygon has been completely traversed.
            break;
          }

          current = ring[i];

          if (previous && (previous[0] === current[0] && previous[1] === current[1])) {
            // Remove the current point from the actual polygon since it was just seen in the previous iteration
            checkPolygon.removePoint(0, i);
            i--; // removePoint() seems to be affecting length of ring which was disturbing the loop iteration. Added this decrement to back up 

          }
          previous = current;
        }
      }

      if (checkPolygon.isSelfIntersecting(checkPolygon)) {
        app.hi("The map cannot process a polygon that crosses itself. Please draw a new one.", "hi-error");
        app.map.graphics.clear();

        // Reject the self-intersecting and re-draw a prior *good* polygon if it exists
        if (app.polygonGraphic) {
          app.map.graphics.add(app.polygonGraphic);
        }
      }
      else {
        app.polygonGraphic = tempGraphic;

        // Construct new ring with coordinates in 4326
        var newRing = [];

        var geo = evt.geometry;

        // Save geometry for zooming
        app.geometry = geo;

        if (geo && geo.rings.length) {

          if (geo.rings.length === 1) {
            ring = geo.rings[0];

            if (wkid === "4326") {
              // In this case, we've passed a correctly-positioned polygon in via a save state, so no transformation is needed
              app.polygon = geo.rings[0];
            }
            else {
              // In this case we must convert the new polygon's coordinates to 4326. In addition we reverse the orientation of the new polygon.
              var pos = 0, neg = 0, ll, lon;
              for (i = ring.length - 1; i >= 0; i--) {
                ll = webMercatorUtils.xyToLngLat(ring[i][0], ring[i][1]);
                lon = ll[0];

                if (lon < 0) {
                  neg++;
                }
                else {
                  pos++;
                }

                newRing.push([lon, ll[1]]);
              }

              // Cannot handle a polygon that crosses 180° (west of Hawaii)
              if (neg > 0 && pos > 0) {
                app.hi("The map cannot process polygons that cross the 0° or 180° meridians. Please draw a smaller polygon.", "hi-error");
                app.map.graphics.clear();
              }
              else {
                app.polygon = newRing;
              }
            }
          }
          else {
            console.log("Warning - this polygon case is not handled yet (multiple rings)");
            console.log(geo.rings);
          }
        }
      }
      app.map.setExtent(evt.geometry.getExtent().expand(1.5)); // added 4/19/2021
    });
  },

  drawExtent: function (evt, wkid) {
    require(["esri/graphic"], function (Graphic) {
      app.circle = null;
      app.clearSelection();
      app.hi();
      app.map.graphics.add(new Graphic(evt.geometry, app.symbols.lineSymbol));
      app.map.setExtent(evt.geometry.getExtent().expand(1.5));
    });
  },

  // Redraws a circle or polygon using saved graphic info in app.circle, app.polygon, or app.wkt
  redrawPolygons: function () {
    if (app.circle) {
      app.drawing.drawCircle(app.circle);
    }
    if (app.polygon) {
      app.map.graphics.add(app.polygonGraphic);
    }
    if (app.wkt) {
      app.hi();

      require(["esri/geometry/Polygon", "esri/graphic"], function (Polygon, Graphic) {
        var poly = app.wktToEsriPolygon(Polygon, app.wkt);
        if (!poly) {
          app.hi("The WKT is either invalid or not yet supported by this map.", "hi-error");
          return false;
        }
        else if (poly.isSelfIntersecting(poly)) {
          app.hi("The map cannot process a polygon that crosses itself. Please draw a new one.", "hi-error");
          return false;
        }
        else {
          var a = new Graphic(poly, app.symbols.lineSymbol);
          app.map.graphics.add(new Graphic(poly, app.symbols.lineSymbol));
        }
      });
    }
  }
};;
"use strict";

function download(params, guid) {
    // Changed to POST map parameters to handle large polygons
    var specialParam = (app.specialMap ? "&special=" + app.specialMap.name : "");

    // Ticket 923: passing in GUID for citation file
    var guidParam = (guid ? "&guid=" + guid : "");
    $.ajax({
        type: "POST",
        url: "/viewer/newmap/NewMapHandler.ashx?d=1" + specialParam + guidParam + "&url=" + window.location.href,
        data: params,
        async: false, // Keep showing loading spinner until file is downloaded
        success: function (url) {
            window.location = url;
            app.hideLoading();
        },
        error: function (err) {
            app.handleError(err, this);
        }
    });
}

$(document).on("click", ".download", function () {
    app.showLoading();
    var newState = app.createMapState();
    var params = JSON.stringify(newState.p);
    var action = "Download";

    if (app.mapState) {
        if (app.saveState.statesEqual(JSON.parse(app.mapState), newState)) {
            console.log("states are equal");

            // State parameters are equal. Don't create new GUID. Log 'Download' and perform the download.
            $.ajax({
                url: "/viewer/newmap/NewMapHandler.ashx?log=1&guid=" + app.guid + "&action=" + action,
                success: function () {
                    download(params, app.guid);
                },
                error: function (err) {
                    app.handleError(err, this);
                }
            });
        }
        else {
            // State parameters are different. Create new GUID. Log 'Download' and perform the download.
            $.ajax({
                // Create GUID
                type: "POST",
                url: "/viewer/newmap/NewMapHandler.ashx?s=1",
                data: JSON.stringify(newState),
                success: function (guid) {

                    // Log download
                    $.ajax({
                        url: "/viewer/newmap/NewMapHandler.ashx?log=1&guid=" + guid + "&action=" + action,
                        success: function () {
                            download(params, guid);
                        },
                        error: function (err) {
                            app.handleError(err, this);
                        }
                    });
                }
            });
        }
    }
    else {
        // This map had not been previously saved. Create new GUID. Log 'Download' and perform the download.
        $.ajax({
            // Create GUID
            type: "POST",
            url: "/viewer/newmap/NewMapHandler.ashx?s=1",
            data: JSON.stringify(newState),
            success: function (guid) {

                // Log download
                $.ajax({
                    url: "/viewer/newmap/NewMapHandler.ashx?log=1&guid=" + guid + "&action=" + action,
                    success: function () {
                        download(params, guid);
                    },
                    error: function (err) {
                        app.handleError(err, this);
                    }
                });
            }
        });
    }
});;
/*!
 * clipboard.js v1.5.12
 * https://zenorocha.github.io/clipboard.js
 *
 * Licensed MIT © Zeno Rocha
 */
!function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var e;e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,e.Clipboard=t()}}(function(){var t,e,n;return function t(e,n,o){function i(a,c){if(!n[a]){if(!e[a]){var s="function"==typeof require&&require;if(!c&&s)return s(a,!0);if(r)return r(a,!0);var l=new Error("Cannot find module '"+a+"'");throw l.code="MODULE_NOT_FOUND",l}var u=n[a]={exports:{}};e[a][0].call(u.exports,function(t){var n=e[a][1][t];return i(n?n:t)},u,u.exports,t,e,n,o)}return n[a].exports}for(var r="function"==typeof require&&require,a=0;a<o.length;a++)i(o[a]);return i}({1:[function(t,e,n){var o=t("matches-selector");e.exports=function(t,e,n){for(var i=n?t:t.parentNode;i&&i!==document;){if(o(i,e))return i;i=i.parentNode}}},{"matches-selector":5}],2:[function(t,e,n){function o(t,e,n,o,r){var a=i.apply(this,arguments);return t.addEventListener(n,a,r),{destroy:function(){t.removeEventListener(n,a,r)}}}function i(t,e,n,o){return function(n){n.delegateTarget=r(n.target,e,!0),n.delegateTarget&&o.call(t,n)}}var r=t("closest");e.exports=o},{closest:1}],3:[function(t,e,n){n.node=function(t){return void 0!==t&&t instanceof HTMLElement&&1===t.nodeType},n.nodeList=function(t){var e=Object.prototype.toString.call(t);return void 0!==t&&("[object NodeList]"===e||"[object HTMLCollection]"===e)&&"length"in t&&(0===t.length||n.node(t[0]))},n.string=function(t){return"string"==typeof t||t instanceof String},n.fn=function(t){var e=Object.prototype.toString.call(t);return"[object Function]"===e}},{}],4:[function(t,e,n){function o(t,e,n){if(!t&&!e&&!n)throw new Error("Missing required arguments");if(!c.string(e))throw new TypeError("Second argument must be a String");if(!c.fn(n))throw new TypeError("Third argument must be a Function");if(c.node(t))return i(t,e,n);if(c.nodeList(t))return r(t,e,n);if(c.string(t))return a(t,e,n);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function i(t,e,n){return t.addEventListener(e,n),{destroy:function(){t.removeEventListener(e,n)}}}function r(t,e,n){return Array.prototype.forEach.call(t,function(t){t.addEventListener(e,n)}),{destroy:function(){Array.prototype.forEach.call(t,function(t){t.removeEventListener(e,n)})}}}function a(t,e,n){return s(document.body,t,e,n)}var c=t("./is"),s=t("delegate");e.exports=o},{"./is":3,delegate:2}],5:[function(t,e,n){function o(t,e){if(r)return r.call(t,e);for(var n=t.parentNode.querySelectorAll(e),o=0;o<n.length;++o)if(n[o]==t)return!0;return!1}var i=Element.prototype,r=i.matchesSelector||i.webkitMatchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector;e.exports=o},{}],6:[function(t,e,n){function o(t){var e;if("INPUT"===t.nodeName||"TEXTAREA"===t.nodeName)t.focus(),t.setSelectionRange(0,t.value.length),e=t.value;else{t.hasAttribute("contenteditable")&&t.focus();var n=window.getSelection(),o=document.createRange();o.selectNodeContents(t),n.removeAllRanges(),n.addRange(o),e=n.toString()}return e}e.exports=o},{}],7:[function(t,e,n){function o(){}o.prototype={on:function(t,e,n){var o=this.e||(this.e={});return(o[t]||(o[t]=[])).push({fn:e,ctx:n}),this},once:function(t,e,n){function o(){i.off(t,o),e.apply(n,arguments)}var i=this;return o._=e,this.on(t,o,n)},emit:function(t){var e=[].slice.call(arguments,1),n=((this.e||(this.e={}))[t]||[]).slice(),o=0,i=n.length;for(o;i>o;o++)n[o].fn.apply(n[o].ctx,e);return this},off:function(t,e){var n=this.e||(this.e={}),o=n[t],i=[];if(o&&e)for(var r=0,a=o.length;a>r;r++)o[r].fn!==e&&o[r].fn._!==e&&i.push(o[r]);return i.length?n[t]=i:delete n[t],this}},e.exports=o},{}],8:[function(e,n,o){!function(i,r){if("function"==typeof t&&t.amd)t(["module","select"],r);else if("undefined"!=typeof o)r(n,e("select"));else{var a={exports:{}};r(a,i.select),i.clipboardAction=a.exports}}(this,function(t,e){"use strict";function n(t){return t&&t.__esModule?t:{"default":t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}var i=n(e),r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol?"symbol":typeof t},a=function(){function t(t,e){for(var n=0;n<e.length;n++){var o=e[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(t,o.key,o)}}return function(e,n,o){return n&&t(e.prototype,n),o&&t(e,o),e}}(),c=function(){function t(e){o(this,t),this.resolveOptions(e),this.initSelection()}return t.prototype.resolveOptions=function t(){var e=arguments.length<=0||void 0===arguments[0]?{}:arguments[0];this.action=e.action,this.emitter=e.emitter,this.target=e.target,this.text=e.text,this.trigger=e.trigger,this.selectedText=""},t.prototype.initSelection=function t(){this.text?this.selectFake():this.target&&this.selectTarget()},t.prototype.selectFake=function t(){var e=this,n="rtl"==document.documentElement.getAttribute("dir");this.removeFake(),this.fakeHandlerCallback=function(){return e.removeFake()},this.fakeHandler=document.body.addEventListener("click",this.fakeHandlerCallback)||!0,this.fakeElem=document.createElement("textarea"),this.fakeElem.style.fontSize="12pt",this.fakeElem.style.border="0",this.fakeElem.style.padding="0",this.fakeElem.style.margin="0",this.fakeElem.style.position="absolute",this.fakeElem.style[n?"right":"left"]="-9999px",this.fakeElem.style.top=(window.pageYOffset||document.documentElement.scrollTop)+"px",this.fakeElem.setAttribute("readonly",""),this.fakeElem.value=this.text,document.body.appendChild(this.fakeElem),this.selectedText=(0,i.default)(this.fakeElem),this.copyText()},t.prototype.removeFake=function t(){this.fakeHandler&&(document.body.removeEventListener("click",this.fakeHandlerCallback),this.fakeHandler=null,this.fakeHandlerCallback=null),this.fakeElem&&(document.body.removeChild(this.fakeElem),this.fakeElem=null)},t.prototype.selectTarget=function t(){this.selectedText=(0,i.default)(this.target),this.copyText()},t.prototype.copyText=function t(){var e=void 0;try{e=document.execCommand(this.action)}catch(n){e=!1}this.handleResult(e)},t.prototype.handleResult=function t(e){e?this.emitter.emit("success",{action:this.action,text:this.selectedText,trigger:this.trigger,clearSelection:this.clearSelection.bind(this)}):this.emitter.emit("error",{action:this.action,trigger:this.trigger,clearSelection:this.clearSelection.bind(this)})},t.prototype.clearSelection=function t(){this.target&&this.target.blur(),window.getSelection().removeAllRanges()},t.prototype.destroy=function t(){this.removeFake()},a(t,[{key:"action",set:function t(){var e=arguments.length<=0||void 0===arguments[0]?"copy":arguments[0];if(this._action=e,"copy"!==this._action&&"cut"!==this._action)throw new Error('Invalid "action" value, use either "copy" or "cut"')},get:function t(){return this._action}},{key:"target",set:function t(e){if(void 0!==e){if(!e||"object"!==("undefined"==typeof e?"undefined":r(e))||1!==e.nodeType)throw new Error('Invalid "target" value, use a valid Element');if("copy"===this.action&&e.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if("cut"===this.action&&(e.hasAttribute("readonly")||e.hasAttribute("disabled")))throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes');this._target=e}},get:function t(){return this._target}}]),t}();t.exports=c})},{select:6}],9:[function(e,n,o){!function(i,r){if("function"==typeof t&&t.amd)t(["module","./clipboard-action","tiny-emitter","good-listener"],r);else if("undefined"!=typeof o)r(n,e("./clipboard-action"),e("tiny-emitter"),e("good-listener"));else{var a={exports:{}};r(a,i.clipboardAction,i.tinyEmitter,i.goodListener),i.clipboard=a.exports}}(this,function(t,e,n,o){"use strict";function i(t){return t&&t.__esModule?t:{"default":t}}function r(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function a(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function c(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}function s(t,e){var n="data-clipboard-"+t;if(e.hasAttribute(n))return e.getAttribute(n)}var l=i(e),u=i(n),f=i(o),d=function(t){function e(n,o){r(this,e);var i=a(this,t.call(this));return i.resolveOptions(o),i.listenClick(n),i}return c(e,t),e.prototype.resolveOptions=function t(){var e=arguments.length<=0||void 0===arguments[0]?{}:arguments[0];this.action="function"==typeof e.action?e.action:this.defaultAction,this.target="function"==typeof e.target?e.target:this.defaultTarget,this.text="function"==typeof e.text?e.text:this.defaultText},e.prototype.listenClick=function t(e){var n=this;this.listener=(0,f.default)(e,"click",function(t){return n.onClick(t)})},e.prototype.onClick=function t(e){var n=e.delegateTarget||e.currentTarget;this.clipboardAction&&(this.clipboardAction=null),this.clipboardAction=new l.default({action:this.action(n),target:this.target(n),text:this.text(n),trigger:n,emitter:this})},e.prototype.defaultAction=function t(e){return s("action",e)},e.prototype.defaultTarget=function t(e){var n=s("target",e);return n?document.querySelector(n):void 0},e.prototype.defaultText=function t(e){return s("text",e)},e.prototype.destroy=function t(){this.listener.destroy(),this.clipboardAction&&(this.clipboardAction.destroy(),this.clipboardAction=null)},e}(u.default);t.exports=d})},{"./clipboard-action":8,"good-listener":4,"tiny-emitter":7}]},{},[9])(9)});;
