text: /**
   * H5UI (http://h5ui.io)
   * Copyright (C) 2017 H5UI.io
   * Licensed under the MIT license (https://mit-license.org)
   */
  ;(function () {
  	'use strict';
  
  	/**
  	 * @preserve FastClick: polyfill to remove click delays on browsers with touch UIs.
  	 *
  	 * @codingstandard ftlabs-jsv2
  	 * @copyright The Financial Times Limited [All Rights Reserved]
  	 * @license MIT License (see LICENSE.txt)
  	 */
  
  	/*jslint browser:true, node:true*/
  	/*global define, Event, Node*/
  
  
  	/**
  	 * Instantiate fast-clicking listeners on the specified layer.
  	 *
  	 * @constructor
  	 * @param {Element} layer The layer to listen on
  	 * @param {Object} [options={}] The options to override the defaults
  	 */
  	function FastClick(layer, options) {
  		var oldOnClick;
  
  		options = options || {};
  
  		/**
  		 * Whether a click is currently being tracked.
  		 *
  		 * @type boolean
  		 */
  		this.trackingClick = false;
  
  
  		/**
  		 * Timestamp for when click tracking started.
  		 *
  		 * @type number
  		 */
  		this.trackingClickStart = 0;
  
  
  		/**
  		 * The element being tracked for a click.
  		 *
  		 * @type EventTarget
  		 */
  		this.targetElement = null;
  
  
  		/**
  		 * X-coordinate of touch start event.
  		 *
  		 * @type number
  		 */
  		this.touchStartX = 0;
  
  
  		/**
  		 * Y-coordinate of touch start event.
  		 *
  		 * @type number
  		 */
  		this.touchStartY = 0;
  
  
  		/**
  		 * ID of the last touch, retrieved from Touch.identifier.
  		 *
  		 * @type number
  		 */
  		this.lastTouchIdentifier = 0;
  
  
  		/**
  		 * Touchmove boundary, beyond which a click will be cancelled.
  		 *
  		 * @type number
  		 */
  		this.touchBoundary = options.touchBoundary || 10;
  
  
  		/**
  		 * The FastClick layer.
  		 *
  		 * @type Element
  		 */
  		this.layer = layer;
  
  		/**
  		 * The minimum time between tap(touchstart and touchend) events
  		 *
  		 * @type number
  		 */
  		this.tapDelay = options.tapDelay || 200;
  
  		/**
  		 * The maximum time for a tap
  		 *
  		 * @type number
  		 */
  		this.tapTimeout = options.tapTimeout || 700;
  
  		if (FastClick.notNeeded(layer)) {
  			return;
  		}
  
  		// Some old versions of Android don't have Function.prototype.bind
  		function bind(method, context) {
  			return function() { return method.apply(context, arguments); };
  		}
  
  
  		var methods = ['onMouse', 'onClick', 'onTouchStart', 'onTouchMove', 'onTouchEnd', 'onTouchCancel'];
  		var context = this;
  		for (var i = 0, l = methods.length; i < l; i++) {
  			context[methods[i]] = bind(context[methods[i]], context);
  		}
  
  		// Set up event handlers as required
  		if (deviceIsAndroid) {
  			layer.addEventListener('mouseover', this.onMouse, true);
  			layer.addEventListener('mousedown', this.onMouse, true);
  			layer.addEventListener('mouseup', this.onMouse, true);
  		}
  
  		layer.addEventListener('click', this.onClick, true);
  		layer.addEventListener('touchstart', this.onTouchStart, false);
  		layer.addEventListener('touchmove', this.onTouchMove, false);
  		layer.addEventListener('touchend', this.onTouchEnd, false);
  		layer.addEventListener('touchcancel', this.onTouchCancel, false);
  
  		// Hack is required for browsers that don't support Event#stopImmediatePropagation (e.g. Android 2)
  		// which is how FastClick normally stops click events bubbling to callbacks registered on the FastClick
  		// layer when they are cancelled.
  		if (!Event.prototype.stopImmediatePropagation) {
  			layer.removeEventListener = function(type, callback, capture) {
  				var rmv = Node.prototype.removeEventListener;
  				if (type === 'click') {
  					rmv.call(layer, type, callback.hijacked || callback, capture);
  				} else {
  					rmv.call(layer, type, callback, capture);
  				}
  			};
  
  			layer.addEventListener = function(type, callback, capture) {
  				var adv = Node.prototype.addEventListener;
  				if (type === 'click') {
  					adv.call(layer, type, callback.hijacked || (callback.hijacked = function(event) {
  						if (!event.propagationStopped) {
  							callback(event);
  						}
  					}), capture);
  				} else {
  					adv.call(layer, type, callback, capture);
  				}
  			};
  		}
  
  		// If a handler is already declared in the element's onclick attribute, it will be fired before
  		// FastClick's onClick handler. Fix this by pulling out the user-defined handler function and
  		// adding it as listener.
  		if (typeof layer.onclick === 'function') {
  
  			// Android browser on at least 3.2 requires a new reference to the function in layer.onclick
  			// - the old one won't work if passed to addEventListener directly.
  			oldOnClick = layer.onclick;
  			layer.addEventListener('click', function(event) {
  				oldOnClick(event);
  			}, false);
  			layer.onclick = null;
  		}
  	}
  
  	/**
  	* Windows Phone 8.1 fakes user agent string to look like Android and iPhone.
  	*
  	* @type boolean
  	*/
  	var deviceIsWindowsPhone = navigator.userAgent.indexOf("Windows Phone") >= 0;
  
  	/**
  	 * Android requires exceptions.
  	 *
  	 * @type boolean
  	 */
  	var deviceIsAndroid = navigator.userAgent.indexOf('Android') > 0 && !deviceIsWindowsPhone;
  
  
  	/**
  	 * iOS requires exceptions.
  	 *
  	 * @type boolean
  	 */
  	var deviceIsIOS = /iP(ad|hone|od)/.test(navigator.userAgent) && !deviceIsWindowsPhone;
  
  
  	/**
  	 * iOS 4 requires an exception for select elements.
  	 *
  	 * @type boolean
  	 */
  	var deviceIsIOS4 = deviceIsIOS && (/OS 4_\d(_\d)?/).test(navigator.userAgent);
  
  
  	/**
  	 * iOS 6.0-7.* requires the target element to be manually derived
  	 *
  	 * @type boolean
  	 */
  	var deviceIsIOSWithBadTarget = deviceIsIOS && (/OS [6-7]_\d/).test(navigator.userAgent);
  
  	/**
  	 * BlackBerry requires exceptions.
  	 *
  	 * @type boolean
  	 */
  	var deviceIsBlackBerry10 = navigator.userAgent.indexOf('BB10') > 0;
  
  	/**
  	 * Determine whether a given element requires a native click.
  	 *
  	 * @param {EventTarget|Element} target Target DOM element
  	 * @returns {boolean} Returns true if the element needs a native click
  	 */
  	FastClick.prototype.needsClick = function(target) {
  		switch (target.nodeName.toLowerCase()) {
  
  		// Don't send a synthetic click to disabled inputs (issue #62)
  		case 'button':
  		case 'select':
  		case 'textarea':
  			if (target.disabled) {
  				return true;
  			}
  
  			break;
  		case 'input':
  
  			// File inputs need real clicks on iOS 6 due to a browser bug (issue #68)
  			if ((deviceIsIOS && target.type === 'file') || target.disabled) {
  				return true;
  			}
  
  			break;
  		case 'label':
  		case 'iframe': // iOS8 homescreen apps can prevent events bubbling into frames
  		case 'video':
  			return true;
  		}
  
  		return (/\bneedsclick\b/).test(target.className);
  	};
  
  
  	/**
  	 * Determine whether a given element requires a call to focus to simulate click into element.
  	 *
  	 * @param {EventTarget|Element} target Target DOM element
  	 * @returns {boolean} Returns true if the element requires a call to focus to simulate native click.
  	 */
  	FastClick.prototype.needsFocus = function(target) {
  		switch (target.nodeName.toLowerCase()) {
  		case 'textarea':
  			return true;
  		case 'select':
  			return !deviceIsAndroid;
  		case 'input':
  			switch (target.type) {
  			case 'button':
  			case 'checkbox':
  			case 'file':
  			case 'image':
  			case 'radio':
  			case 'submit':
  				return false;
  			}
  
  			// No point in attempting to focus disabled inputs
  			return !target.disabled && !target.readOnly;
  		default:
  			return (/\bneedsfocus\b/).test(target.className);
  		}
  	};
  
  
  	/**
  	 * Send a click event to the specified element.
  	 *
  	 * @param {EventTarget|Element} targetElement
  	 * @param {Event} event
  	 */
  	FastClick.prototype.sendClick = function(targetElement, event) {
  		var clickEvent, touch;
  
  		// On some Android devices activeElement needs to be blurred otherwise the synthetic click will have no effect (#24)
  		if (document.activeElement && document.activeElement !== targetElement) {
  			document.activeElement.blur();
  		}
  
  		touch = event.changedTouches[0];
  
  		// Synthesise a click event, with an extra attribute so it can be tracked
  		clickEvent = document.createEvent('MouseEvents');
  		clickEvent.initMouseEvent(this.determineEventType(targetElement), true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null);
  		clickEvent.forwardedTouchEvent = true;
  		targetElement.dispatchEvent(clickEvent);
  	};
  
  	FastClick.prototype.determineEventType = function(targetElement) {
  
  		//Issue #159: Android Chrome Select Box does not open with a synthetic click event
  		if (deviceIsAndroid && targetElement.tagName.toLowerCase() === 'select') {
  			return 'mousedown';
  		}
  
  		return 'click';
  	};
  
  
  	/**
  	 * @param {EventTarget|Element} targetElement
  	 */
  	FastClick.prototype.focus = function(targetElement) {
  		var length;
  
  		// Issue #160: on iOS 7, some input elements (e.g. date datetime month) throw a vague TypeError on setSelectionRange. These elements don't have an integer value for the selectionStart and selectionEnd properties, but unfortunately that can't be used for detection because accessing the properties also throws a TypeError. Just check the type instead. Filed as Apple bug #15122724.
  		if (deviceIsIOS && targetElement.setSelectionRange && targetElement.type.indexOf('date') !== 0 && targetElement.type !== 'time' && targetElement.type !== 'month') {
  			length = targetElement.value.length;
  			targetElement.setSelectionRange(length, length);
  		} else {
  			targetElement.focus();
  		}
  	};
  
  
  	/**
  	 * Check whether the given target element is a child of a scrollable layer and if so, set a flag on it.
  	 *
  	 * @param {EventTarget|Element} targetElement
  	 */
  	FastClick.prototype.updateScrollParent = function(targetElement) {
  		var scrollParent, parentElement;
  
  		scrollParent = targetElement.fastClickScrollParent;
  
  		// Attempt to discover whether the target element is contained within a scrollable layer. Re-check if the
  		// target element was moved to another parent.
  		if (!scrollParent || !scrollParent.contains(targetElement)) {
  			parentElement = targetElement;
  			do {
  				if (parentElement.scrollHeight > parentElement.offsetHeight) {
  					scrollParent = parentElement;
  					targetElement.fastClickScrollParent = parentElement;
  					break;
  				}
  
  				parentElement = parentElement.parentElement;
  			} while (parentElement);
  		}
  
  		// Always update the scroll top tracker if possible.
  		if (scrollParent) {
  			scrollParent.fastClickLastScrollTop = scrollParent.scrollTop;
  		}
  	};
  
  
  	/**
  	 * @param {EventTarget} targetElement
  	 * @returns {Element|EventTarget}
  	 */
  	FastClick.prototype.getTargetElementFromEventTarget = function(eventTarget) {
  
  		// On some older browsers (notably Safari on iOS 4.1 - see issue #56) the event target may be a text node.
  		if (eventTarget.nodeType === Node.TEXT_NODE) {
  			return eventTarget.parentNode;
  		}
  
  		return eventTarget;
  	};
  
  
  	/**
  	 * On touch start, record the position and scroll offset.
  	 *
  	 * @param {Event} event
  	 * @returns {boolean}
  	 */
  	FastClick.prototype.onTouchStart = function(event) {
  		var targetElement, touch, selection;
  
  		// Ignore multiple touches, otherwise pinch-to-zoom is prevented if both fingers are on the FastClick element (issue #111).
  		if (event.targetTouches.length > 1) {
  			return true;
  		}
  
  		targetElement = this.getTargetElementFromEventTarget(event.target);
  		touch = event.targetTouches[0];
  
  		if (deviceIsIOS) {
  
  			// Only trusted events will deselect text on iOS (issue #49)
  			selection = window.getSelection();
  			if (selection.rangeCount && !selection.isCollapsed) {
  				return true;
  			}
  
  			if (!deviceIsIOS4) {
  
  				// Weird things happen on iOS when an alert or confirm dialog is opened from a click event callback (issue #23):
  				// when the user next taps anywhere else on the page, new touchstart and touchend events are dispatched
  				// with the same identifier as the touch event that previously triggered the click that triggered the alert.
  				// Sadly, there is an issue on iOS 4 that causes some normal touch events to have the same identifier as an
  				// immediately preceeding touch event (issue #52), so this fix is unavailable on that platform.
  				// Issue 120: touch.identifier is 0 when Chrome dev tools 'Emulate touch events' is set with an iOS device UA string,
  				// which causes all touch events to be ignored. As this block only applies to iOS, and iOS identifiers are always long,
  				// random integers, it's safe to to continue if the identifier is 0 here.
  				if (touch.identifier && touch.identifier === this.lastTouchIdentifier) {
  					event.preventDefault();
  					return false;
  				}
  
  				this.lastTouchIdentifier = touch.identifier;
  
  				// If the target element is a child of a scrollable layer (using -webkit-overflow-scrolling: touch) and:
  				// 1) the user does a fling scroll on the scrollable layer
  				// 2) the user stops the fling scroll with another tap
  				// then the event.target of the last 'touchend' event will be the element that was under the user's finger
  				// when the fling scroll was started, causing FastClick to send a click event to that layer - unless a check
  				// is made to ensure that a parent layer was not scrolled before sending a synthetic click (issue #42).
  				this.updateScrollParent(targetElement);
  			}
  		}
  
  		this.trackingClick = true;
  		this.trackingClickStart = event.timeStamp;
  		this.targetElement = targetElement;
  
  		this.touchStartX = touch.pageX;
  		this.touchStartY = touch.pageY;
  
  		// Prevent phantom clicks on fast double-tap (issue #36)
  		if ((event.timeStamp - this.lastClickTime) < this.tapDelay) {
  			event.preventDefault();
  		}
  
  		return true;
  	};
  
  
  	/**
  	 * Based on a touchmove event object, check whether the touch has moved past a boundary since it started.
  	 *
  	 * @param {Event} event
  	 * @returns {boolean}
  	 */
  	FastClick.prototype.touchHasMoved = function(event) {
  		var touch = event.changedTouches[0], boundary = this.touchBoundary;
  
  		if (Math.abs(touch.pageX - this.touchStartX) > boundary || Math.abs(touch.pageY - this.touchStartY) > boundary) {
  			return true;
  		}
  
  		return false;
  	};
  
  
  	/**
  	 * Update the last position.
  	 *
  	 * @param {Event} event
  	 * @returns {boolean}
  	 */
  	FastClick.prototype.onTouchMove = function(event) {
  		if (!this.trackingClick) {
  			return true;
  		}
  
  		// If the touch has moved, cancel the click tracking
  		if (this.targetElement !== this.getTargetElementFromEventTarget(event.target) || this.touchHasMoved(event)) {
  			this.trackingClick = false;
  			this.targetElement = null;
  		}
  
  		return true;
  	};
  
  
  	/**
  	 * Attempt to find the labelled control for the given label element.
  	 *
  	 * @param {EventTarget|HTMLLabelElement} labelElement
  	 * @returns {Element|null}
  	 */
  	FastClick.prototype.findControl = function(labelElement) {
  
  		// Fast path for newer browsers supporting the HTML5 control attribute
  		if (labelElement.control !== undefined) {
  			return labelElement.control;
  		}
  
  		// All browsers under test that support touch events also support the HTML5 htmlFor attribute
  		if (labelElement.htmlFor) {
  			return document.getElementById(labelElement.htmlFor);
  		}
  
  		// If no for attribute exists, attempt to retrieve the first labellable descendant element
  		// the list of which is defined here: http://www.w3.org/TR/html5/forms.html#category-label
  		return labelElement.querySelector('button, input:not([type=hidden]), keygen, meter, output, progress, select, textarea');
  	};
  
  
  	/**
  	 * On touch end, determine whether to send a click event at once.
  	 *
  	 * @param {Event} event
  	 * @returns {boolean}
  	 */
  	FastClick.prototype.onTouchEnd = function(event) {
  		var forElement, trackingClickStart, targetTagName, scrollParent, touch, targetElement = this.targetElement;
  
  		if (!this.trackingClick) {
  			return true;
  		}
  
  		// Prevent phantom clicks on fast double-tap (issue #36)
  		if ((event.timeStamp - this.lastClickTime) < this.tapDelay) {
  			this.cancelNextClick = true;
  			return true;
  		}
  
  		if ((event.timeStamp - this.trackingClickStart) > this.tapTimeout) {
  			return true;
  		}
  
  		// Reset to prevent wrong click cancel on input (issue #156).
  		this.cancelNextClick = false;
  
  		this.lastClickTime = event.timeStamp;
  
  		trackingClickStart = this.trackingClickStart;
  		this.trackingClick = false;
  		this.trackingClickStart = 0;
  
  		// On some iOS devices, the targetElement supplied with the event is invalid if the layer
  		// is performing a transition or scroll, and has to be re-detected manually. Note that
  		// for this to function correctly, it must be called *after* the event target is checked!
  		// See issue #57; also filed as rdar://13048589 .
  		if (deviceIsIOSWithBadTarget) {
  			touch = event.changedTouches[0];
  
  			// In certain cases arguments of elementFromPoint can be negative, so prevent setting targetElement to null
  			targetElement = document.elementFromPoint(touch.pageX - window.pageXOffset, touch.pageY - window.pageYOffset) || targetElement;
  			targetElement.fastClickScrollParent = this.targetElement.fastClickScrollParent;
  		}
  
  		targetTagName = targetElement.tagName.toLowerCase();
  		if (targetTagName === 'label') {
  			forElement = this.findControl(targetElement);
  			if (forElement) {
  				this.focus(targetElement);
  				if (deviceIsAndroid) {
  					return false;
  				}
  
  				targetElement = forElement;
  			}
  		} else if (this.needsFocus(targetElement)) {
  
  			// Case 1: If the touch started a while ago (best guess is 100ms based on tests for issue #36) then focus will be triggered anyway. Return early and unset the target element reference so that the subsequent click will be allowed through.
  			// Case 2: Without this exception for input elements tapped when the document is contained in an iframe, then any inputted text won't be visible even though the value attribute is updated as the user types (issue #37).
  			if ((event.timeStamp - trackingClickStart) > 100 || (deviceIsIOS && window.top !== window && targetTagName === 'input')) {
  				this.targetElement = null;
  				return false;
  			}
  
  			this.focus(targetElement);
  			this.sendClick(targetElement, event);
  
  			// Select elements need the event to go through on iOS 4, otherwise the selector menu won't open.
  			// Also this breaks opening selects when VoiceOver is active on iOS6, iOS7 (and possibly others)
  			if (!deviceIsIOS || targetTagName !== 'select') {
  				this.targetElement = null;
  				event.preventDefault();
  			}
  
  			return false;
  		}
  
  		if (deviceIsIOS && !deviceIsIOS4) {
  
  			// Don't send a synthetic click event if the target element is contained within a parent layer that was scrolled
  			// and this tap is being used to stop the scrolling (usually initiated by a fling - issue #42).
  			scrollParent = targetElement.fastClickScrollParent;
  			if (scrollParent && scrollParent.fastClickLastScrollTop !== scrollParent.scrollTop) {
  				return true;
  			}
  		}
  
  		// Prevent the actual click from going though - unless the target node is marked as requiring
  		// real clicks or if it is in the whitelist in which case only non-programmatic clicks are permitted.
  		if (!this.needsClick(targetElement)) {
  			event.preventDefault();
  			this.sendClick(targetElement, event);
  		}
  
  		return false;
  	};
  
  
  	/**
  	 * On touch cancel, stop tracking the click.
  	 *
  	 * @returns {void}
  	 */
  	FastClick.prototype.onTouchCancel = function() {
  		this.trackingClick = false;
  		this.targetElement = null;
  	};
  
  
  	/**
  	 * Determine mouse events which should be permitted.
  	 *
  	 * @param {Event} event
  	 * @returns {boolean}
  	 */
  	FastClick.prototype.onMouse = function(event) {
  
  		// If a target element was never set (because a touch event was never fired) allow the event
  		if (!this.targetElement) {
  			return true;
  		}
  
  		if (event.forwardedTouchEvent) {
  			return true;
  		}
  
  		// Programmatically generated events targeting a specific element should be permitted
  		if (!event.cancelable) {
  			return true;
  		}
  
  		// Derive and check the target element to see whether the mouse event needs to be permitted;
  		// unless explicitly enabled, prevent non-touch click events from triggering actions,
  		// to prevent ghost/doubleclicks.
  		if (!this.needsClick(this.targetElement) || this.cancelNextClick) {
  
  			// Prevent any user-added listeners declared on FastClick element from being fired.
  			if (event.stopImmediatePropagation) {
  				event.stopImmediatePropagation();
  			} else {
  
  				// Part of the hack for browsers that don't support Event#stopImmediatePropagation (e.g. Android 2)
  				event.propagationStopped = true;
  			}
  
  			// Cancel the event
  			event.stopPropagation();
  			event.preventDefault();
  
  			return false;
  		}
  
  		// If the mouse event is permitted, return true for the action to go through.
  		return true;
  	};
  
  
  	/**
  	 * On actual clicks, determine whether this is a touch-generated click, a click action occurring
  	 * naturally after a delay after a touch (which needs to be cancelled to avoid duplication), or
  	 * an actual click which should be permitted.
  	 *
  	 * @param {Event} event
  	 * @returns {boolean}
  	 */
  	FastClick.prototype.onClick = function(event) {
  		var permitted;
  
  		// It's possible for another FastClick-like library delivered with third-party code to fire a click event before FastClick does (issue #44). In that case, set the click-tracking flag back to false and return early. This will cause onTouchEnd to return early.
  		if (this.trackingClick) {
  			this.targetElement = null;
  			this.trackingClick = false;
  			return true;
  		}
  
  		// Very odd behaviour on iOS (issue #18): if a submit element is present inside a form and the user hits enter in the iOS simulator or clicks the Go button on the pop-up OS keyboard the a kind of 'fake' click event will be triggered with the submit-type input element as the target.
  		if (event.target.type === 'submit' && event.detail === 0) {
  			return true;
  		}
  
  		permitted = this.onMouse(event);
  
  		// Only unset targetElement if the click is not permitted. This will ensure that the check for !targetElement in onMouse fails and the browser's click doesn't go through.
  		if (!permitted) {
  			this.targetElement = null;
  		}
  
  		// If clicks are permitted, return true for the action to go through.
  		return permitted;
  	};
  
  
  	/**
  	 * Remove all FastClick's event listeners.
  	 *
  	 * @returns {void}
  	 */
  	FastClick.prototype.destroy = function() {
  		var layer = this.layer;
  
  		if (deviceIsAndroid) {
  			layer.removeEventListener('mouseover', this.onMouse, true);
  			layer.removeEventListener('mousedown', this.onMouse, true);
  			layer.removeEventListener('mouseup', this.onMouse, true);
  		}
  
  		layer.removeEventListener('click', this.onClick, true);
  		layer.removeEventListener('touchstart', this.onTouchStart, false);
  		layer.removeEventListener('touchmove', this.onTouchMove, false);
  		layer.removeEventListener('touchend', this.onTouchEnd, false);
  		layer.removeEventListener('touchcancel', this.onTouchCancel, false);
  	};
  
  
  	/**
  	 * Check whether FastClick is needed.
  	 *
  	 * @param {Element} layer The layer to listen on
  	 */
  	FastClick.notNeeded = function(layer) {
  		var metaViewport;
  		var chromeVersion;
  		var blackberryVersion;
  		var firefoxVersion;
  
  		// Devices that don't support touch don't need FastClick
  		if (typeof window.ontouchstart === 'undefined') {
  			return true;
  		}
  
  		// Chrome version - zero for other browsers
  		chromeVersion = +(/Chrome\/([0-9]+)/.exec(navigator.userAgent) || [,0])[1];
  
  		if (chromeVersion) {
  
  			if (deviceIsAndroid) {
  				metaViewport = document.querySelector('meta[name=viewport]');
  
  				if (metaViewport) {
  					// Chrome on Android with user-scalable="no" doesn't need FastClick (issue #89)
  					if (metaViewport.content.indexOf('user-scalable=no') !== -1) {
  						return true;
  					}
  					// Chrome 32 and above with width=device-width or less don't need FastClick
  					if (chromeVersion > 31 && document.documentElement.scrollWidth <= window.outerWidth) {
  						return true;
  					}
  				}
  
  			// Chrome desktop doesn't need FastClick (issue #15)
  			} else {
  				return true;
  			}
  		}
  
  		if (deviceIsBlackBerry10) {
  			blackberryVersion = navigator.userAgent.match(/Version\/([0-9]*)\.([0-9]*)/);
  
  			// BlackBerry 10.3+ does not require Fastclick library.
  			// https://github.com/ftlabs/fastclick/issues/251
  			if (blackberryVersion[1] >= 10 && blackberryVersion[2] >= 3) {
  				metaViewport = document.querySelector('meta[name=viewport]');
  
  				if (metaViewport) {
  					// user-scalable=no eliminates click delay.
  					if (metaViewport.content.indexOf('user-scalable=no') !== -1) {
  						return true;
  					}
  					// width=device-width (or less than device-width) eliminates click delay.
  					if (document.documentElement.scrollWidth <= window.outerWidth) {
  						return true;
  					}
  				}
  			}
  		}
  
  		// IE10 with -ms-touch-action: none or manipulation, which disables double-tap-to-zoom (issue #97)
  		if (layer.style.msTouchAction === 'none' || layer.style.touchAction === 'manipulation') {
  			return true;
  		}
  
  		// Firefox version - zero for other browsers
  		firefoxVersion = +(/Firefox\/([0-9]+)/.exec(navigator.userAgent) || [,0])[1];
  
  		if (firefoxVersion >= 27) {
  			// Firefox 27+ does not have tap delay if the content is not zoomable - https://bugzilla.mozilla.org/show_bug.cgi?id=922896
  
  			metaViewport = document.querySelector('meta[name=viewport]');
  			if (metaViewport && (metaViewport.content.indexOf('user-scalable=no') !== -1 || document.documentElement.scrollWidth <= window.outerWidth)) {
  				return true;
  			}
  		}
  
  		// IE11: prefixed -ms-touch-action is no longer supported and it's recomended to use non-prefixed version
  		// http://msdn.microsoft.com/en-us/library/windows/apps/Hh767313.aspx
  		if (layer.style.touchAction === 'none' || layer.style.touchAction === 'manipulation') {
  			return true;
  		}
  
  		return false;
  	};
  
  
  	/**
  	 * Factory method for creating a FastClick object
  	 *
  	 * @param {Element} layer The layer to listen on
  	 * @param {Object} [options={}] The options to override the defaults
  	 */
  	FastClick.attach = function(layer, options) {
  		return new FastClick(layer, options);
  	};
  
  
  	if (typeof define === 'function' && typeof define.amd === 'object' && define.amd) {
  
  		// AMD. Register as an anonymous module.
  		define(function() {
  			return FastClick;
  		});
  	} else if (typeof module !== 'undefined' && module.exports) {
  		module.exports = FastClick.attach;
  		module.exports.FastClick = FastClick;
  	} else {
  		window.FastClick = FastClick;
  	}
  }());
  
  /*! Lazy Load 1.9.7 - MIT license - Copyright 2010-2015 Mika Tuupola */
  !function(a,b,c,d){var e=a(b);a.fn.lazyload=function(f){function g(){var b=0;i.each(function(){var c=a(this);if(!j.skip_invisible||c.is(":visible"))if(a.abovethetop(this,j)||a.leftofbegin(this,j));else if(a.belowthefold(this,j)||a.rightoffold(this,j)){if(++b>j.failure_limit)return!1}else c.trigger("appear"),b=0})}var h,i=this,j={threshold:0,failure_limit:0,event:"scroll",effect:"show",container:b,data_attribute:"original",skip_invisible:!1,appear:null,load:null,placeholder:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC"};return f&&(d!==f.failurelimit&&(f.failure_limit=f.failurelimit,delete f.failurelimit),d!==f.effectspeed&&(f.effect_speed=f.effectspeed,delete f.effectspeed),a.extend(j,f)),h=j.container===d||j.container===b?e:a(j.container),0===j.event.indexOf("scroll")&&h.bind(j.event,function(){return g()}),this.each(function(){var b=this,c=a(b);b.loaded=!1,(c.attr("src")===d||c.attr("src")===!1)&&c.is("img")&&c.attr("src",j.placeholder),c.one("appear",function(){if(!this.loaded){if(j.appear){var d=i.length;j.appear.call(b,d,j)}a("<img />").bind("load",function(){var d=c.attr("data-"+j.data_attribute);c.hide(),c.is("img")?c.attr("src",d):c.css("background-image","url('"+d+"')"),c[j.effect](j.effect_speed),b.loaded=!0;var e=a.grep(i,function(a){return!a.loaded});if(i=a(e),j.load){var f=i.length;j.load.call(b,f,j)}}).attr("src",c.attr("data-"+j.data_attribute))}}),0!==j.event.indexOf("scroll")&&c.bind(j.event,function(){b.loaded||c.trigger("appear")})}),e.bind("resize",function(){g()}),/(?:iphone|ipod|ipad).*os 5/gi.test(navigator.appVersion)&&e.bind("pageshow",function(b){b.originalEvent&&b.originalEvent.persisted&&i.each(function(){a(this).trigger("appear")})}),a(c).ready(function(){g()}),this},a.belowthefold=function(c,f){var g;return g=f.container===d||f.container===b?(b.innerHeight?b.innerHeight:e.height())+e.scrollTop():a(f.container).offset().top+a(f.container).height(),g<=a(c).offset().top-f.threshold},a.rightoffold=function(c,f){var g;return g=f.container===d||f.container===b?e.width()+e.scrollLeft():a(f.container).offset().left+a(f.container).width(),g<=a(c).offset().left-f.threshold},a.abovethetop=function(c,f){var g;return g=f.container===d||f.container===b?e.scrollTop():a(f.container).offset().top,g>=a(c).offset().top+f.threshold+a(c).height()},a.leftofbegin=function(c,f){var g;return g=f.container===d||f.container===b?e.scrollLeft():a(f.container).offset().left,g>=a(c).offset().left+f.threshold+a(c).width()},a.inviewport=function(b,c){return!(a.rightoffold(b,c)||a.leftofbegin(b,c)||a.belowthefold(b,c)||a.abovethetop(b,c))},a.extend(a.expr[":"],{"below-the-fold":function(b){return a.belowthefold(b,{threshold:0})},"above-the-top":function(b){return!a.belowthefold(b,{threshold:0})},"right-of-screen":function(b){return a.rightoffold(b,{threshold:0})},"left-of-screen":function(b){return!a.rightoffold(b,{threshold:0})},"in-viewport":function(b){return a.inviewport(b,{threshold:0})},"above-the-fold":function(b){return!a.belowthefold(b,{threshold:0})},"right-of-fold":function(b){return a.rightoffold(b,{threshold:0})},"left-of-fold":function(b){return!a.rightoffold(b,{threshold:0})}})}(jQuery,window,document);
  /* ========================================================================
   * Bootstrap: button.js v3.3.6
   * http://getbootstrap.com/javascript/#buttons
   * ========================================================================
   * Copyright 2011-2015 Twitter, Inc.
   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
   * ======================================================================== */
  
  
  +function ($) {
    'use strict';
  
    // BUTTON PUBLIC CLASS DEFINITION
    // ==============================
  
    var Button = function (element, options) {
      this.$element  = $(element)
      this.options   = $.extend({}, Button.DEFAULTS, options)
      this.isLoading = false
    }
  
    Button.VERSION  = '3.3.6'
  
    Button.DEFAULTS = {
      loadingText: 'loading...'
    }
  
    Button.prototype.setState = function (state) {
      var d    = 'disabled'
      var $el  = this.$element
      var val  = $el.is('input') ? 'val' : 'html'
      var data = $el.data()
  
      state += 'Text'
  
      if (data.resetText == null) $el.data('resetText', $el[val]())
  
      // push to event loop to allow forms to submit
      setTimeout($.proxy(function () {
        $el[val](data[state] == null ? this.options[state] : data[state])
  
        if (state == 'loadingText') {
          this.isLoading = true
          $el.addClass(d).attr(d, d)
        } else if (this.isLoading) {
          this.isLoading = false
          $el.removeClass(d).removeAttr(d)
        }
      }, this), 0)
    }
  
    Button.prototype.toggle = function () {
      var changed = true
      var $parent = this.$element.closest('[data-toggle="buttons"]')
  
      if ($parent.length) {
        var $input = this.$element.find('input')
        if ($input.prop('type') == 'radio') {
          if ($input.prop('checked')) changed = false
          $parent.find('.active').removeClass('active')
          this.$element.addClass('active')
        } else if ($input.prop('type') == 'checkbox') {
          if (($input.prop('checked')) !== this.$element.hasClass('active')) changed = false
          this.$element.toggleClass('active')
        }
        $input.prop('checked', this.$element.hasClass('active'))
        if (changed) $input.trigger('change')
      } else {
        this.$element.attr('aria-pressed', !this.$element.hasClass('active'))
        this.$element.toggleClass('active')
      }
    }
  
  
    // BUTTON PLUGIN DEFINITION
    // ========================
  
    function Plugin(option) {
      return this.each(function () {
        var $this   = $(this)
        var data    = $this.data('bs.button')
        var options = typeof option == 'object' && option
  
        if (!data) $this.data('bs.button', (data = new Button(this, options)))
  
        if (option == 'toggle') data.toggle()
        else if (option) data.setState(option)
      })
    }
  
    var old = $.fn.button
  
    $.fn.button             = Plugin
    $.fn.button.Constructor = Button
  
  
    // BUTTON NO CONFLICT
    // ==================
  
    $.fn.button.noConflict = function () {
      $.fn.button = old
      return this
    }
  
  
    // BUTTON DATA-API
    // ===============
  
    $(document)
      .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) {
        var $btn = $(e.target)
        if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
        Plugin.call($btn, 'toggle')
        if (!($(e.target).is('input[type="radio"]') || $(e.target).is('input[type="checkbox"]'))) e.preventDefault()
      })
      .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) {
        $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type))
      })
  
  }(jQuery);
  
  /* ========================================================================
   * Bootstrap: modal.js v3.3.6
   * http://getbootstrap.com/javascript/#modals
   * ========================================================================
   * Copyright 2011-2015 Twitter, Inc.
   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
   * ======================================================================== */
  
  
  +function ($) {
    'use strict';
  
    // MODAL CLASS DEFINITION
    // ======================
  
    var Modal = function (element, options) {
      this.options             = options
      this.$body               = $(document.body)
      this.$element            = $(element)
      this.$dialog             = this.$element.find('.modal-dialog')
      this.$backdrop           = null
      this.isShown             = null
      this.originalBodyPad     = null
      this.scrollbarWidth      = 0
      this.ignoreBackdropClick = false
  
      if (this.options.remote) {
        this.$element
          .find('.modal-content')
          .load(this.options.remote, $.proxy(function () {
            this.$element.trigger('loaded.bs.modal')
          }, this))
      }
    }
  
    Modal.VERSION  = '3.3.6'
  
    Modal.TRANSITION_DURATION = 300
    Modal.BACKDROP_TRANSITION_DURATION = 150
  
    Modal.DEFAULTS = {
      backdrop: true,
      keyboard: true,
      show: true
    }
  
    Modal.prototype.toggle = function (_relatedTarget) {
      return this.isShown ? this.hide() : this.show(_relatedTarget)
    }
  
    Modal.prototype.show = function (_relatedTarget) {
      var that = this
      var e    = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
  
      this.$element.trigger(e)
  
      if (this.isShown || e.isDefaultPrevented()) return
  
      this.isShown = true
  
      this.checkScrollbar()
      this.setScrollbar()
      this.$body.addClass('modal-open')
  
      this.escape()
      this.resize()
  
      this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
  
      this.$dialog.on('mousedown.dismiss.bs.modal', function () {
        that.$element.one('mouseup.dismiss.bs.modal', function (e) {
          if ($(e.target).is(that.$element)) that.ignoreBackdropClick = true
        })
      })
  
      this.backdrop(function () {
        var transition = $.support.transition && that.$element.hasClass('fade')
  
        if (!that.$element.parent().length) {
          that.$element.appendTo(that.$body) // don't move modals dom position
        }
  
        that.$element
          .show()
          .scrollTop(0)
  
        that.adjustDialog()
  
        if (transition) {
          that.$element[0].offsetWidth // force reflow
        }
  
        that.$element.addClass('in')
  
        that.enforceFocus()
  
        var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
  
        transition ?
          that.$dialog // wait for modal to slide in
            .one('bsTransitionEnd', function () {
              that.$element.trigger('focus').trigger(e)
            })
            .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
          that.$element.trigger('focus').trigger(e)
      })
    }
  
    Modal.prototype.hide = function (e) {
      if (e) e.preventDefault()
  
      e = $.Event('hide.bs.modal')
  
      this.$element.trigger(e)
  
      if (!this.isShown || e.isDefaultPrevented()) return
  
      this.isShown = false
  
      this.escape()
      this.resize()
  
      $(document).off('focusin.bs.modal')
  
      this.$element
        .removeClass('in')
        .off('click.dismiss.bs.modal')
        .off('mouseup.dismiss.bs.modal')
  
      this.$dialog.off('mousedown.dismiss.bs.modal')
  
      $.support.transition && this.$element.hasClass('fade') ?
        this.$element
          .one('bsTransitionEnd', $.proxy(this.hideModal, this))
          .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
        this.hideModal()
    }
  
    Modal.prototype.enforceFocus = function () {
      $(document)
        .off('focusin.bs.modal') // guard against infinite focus loop
        .on('focusin.bs.modal', $.proxy(function (e) {
          if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {
            this.$element.trigger('focus')
          }
        }, this))
    }
  
    Modal.prototype.escape = function () {
      if (this.isShown && this.options.keyboard) {
        this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {
          e.which == 27 && this.hide()
        }, this))
      } else if (!this.isShown) {
        this.$element.off('keydown.dismiss.bs.modal')
      }
    }
  
    Modal.prototype.resize = function () {
      if (this.isShown) {
        $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this))
      } else {
        $(window).off('resize.bs.modal')
      }
    }
  
    Modal.prototype.hideModal = function () {
      var that = this
      this.$element.hide()
      this.backdrop(function () {
        that.$body.removeClass('modal-open')
        that.resetAdjustments()
        that.resetScrollbar()
        that.$element.trigger('hidden.bs.modal')
      })
    }
  
    Modal.prototype.removeBackdrop = function () {
      this.$backdrop && this.$backdrop.remove()
      this.$backdrop = null
    }
  
    Modal.prototype.backdrop = function (callback) {
      var that = this
      var animate = this.$element.hasClass('fade') ? 'fade' : ''
  
      if (this.isShown && this.options.backdrop) {
        var doAnimate = $.support.transition && animate
  
        this.$backdrop = $(document.createElement('div'))
          .addClass('modal-backdrop ' + animate)
          .appendTo(this.$body)
  
        this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {
          if (this.ignoreBackdropClick) {
            this.ignoreBackdropClick = false
            return
          }
          if (e.target !== e.currentTarget) return
          this.options.backdrop == 'static'
            ? this.$element[0].focus()
            : this.hide()
        }, this))
  
        if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
  
        this.$backdrop.addClass('in')
  
        if (!callback) return
  
        doAnimate ?
          this.$backdrop
            .one('bsTransitionEnd', callback)
            .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
          callback()
  
      } else if (!this.isShown && this.$backdrop) {
        this.$backdrop.removeClass('in')
  
        var callbackRemove = function () {
          that.removeBackdrop()
          callback && callback()
        }
        $.support.transition && this.$element.hasClass('fade') ?
          this.$backdrop
            .one('bsTransitionEnd', callbackRemove)
            .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
          callbackRemove()
  
      } else if (callback) {
        callback()
      }
    }
  
    // these following methods are used to handle overflowing modals
  
    Modal.prototype.handleUpdate = function () {
      this.adjustDialog()
    }
  
    Modal.prototype.adjustDialog = function () {
      var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight
  
      this.$element.css({
        paddingLeft:  !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '',
        paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : ''
      })
    }
  
    Modal.prototype.resetAdjustments = function () {
      this.$element.css({
        paddingLeft: '',
        paddingRight: ''
      })
    }
  
    Modal.prototype.checkScrollbar = function () {
      var fullWindowWidth = window.innerWidth
      if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8
        var documentElementRect = document.documentElement.getBoundingClientRect()
        fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left)
      }
      this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth
      this.scrollbarWidth = this.measureScrollbar()
    }
  
    Modal.prototype.setScrollbar = function () {
      var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
      this.originalBodyPad = document.body.style.paddingRight || ''
      if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)
    }
  
    Modal.prototype.resetScrollbar = function () {
      this.$body.css('padding-right', this.originalBodyPad)
    }
  
    Modal.prototype.measureScrollbar = function () { // thx walsh
      var scrollDiv = document.createElement('div')
      scrollDiv.className = 'modal-scrollbar-measure'
      this.$body.append(scrollDiv)
      var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth
      this.$body[0].removeChild(scrollDiv)
      return scrollbarWidth
    }
  
  
    // MODAL PLUGIN DEFINITION
    // =======================
  
    function Plugin(option, _relatedTarget) {
      return this.each(function () {
        var $this   = $(this)
        var data    = $this.data('bs.modal')
        var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)
  
        if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
        if (typeof option == 'string') data[option](_relatedTarget)
        else if (options.show) data.show(_relatedTarget)
      })
    }
  
    var old = $.fn.modal
  
    $.fn.modal             = Plugin
    $.fn.modal.Constructor = Modal
  
  
    // MODAL NO CONFLICT
    // =================
  
    $.fn.modal.noConflict = function () {
      $.fn.modal = old
      return this
    }
  
  
    // MODAL DATA-API
    // ==============
  
    $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
      var $this   = $(this)
      var href    = $this.attr('href')
      var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7
      var option  = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
  
      if ($this.is('a')) e.preventDefault()
  
      $target.one('show.bs.modal', function (showEvent) {
        if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown
        $target.one('hidden.bs.modal', function () {
          $this.is(':visible') && $this.trigger('focus')
        })
      })
      Plugin.call($target, option, this)
    })
  
  }(jQuery);
  
  /* ========================================================================
   * Bootstrap: tab.js v3.3.6
   * http://getbootstrap.com/javascript/#tabs
   * ========================================================================
   * Copyright 2011-2015 Twitter, Inc.
   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
   * ======================================================================== */
  
  
  +function ($) {
    'use strict';
  
    // TAB CLASS DEFINITION
    // ====================
  
    var Tab = function (element) {
      // jscs:disable requireDollarBeforejQueryAssignment
      this.element = $(element)
      // jscs:enable requireDollarBeforejQueryAssignment
    }
  
    Tab.VERSION = '3.3.6'
  
    Tab.TRANSITION_DURATION = 150
  
    Tab.prototype.show = function () {
      var $this    = this.element
      var $ul      = $this.closest('ul:not(.dropdown-menu)')
      var selector = $this.data('target')
  
      if (!selector) {
        selector = $this.attr('href')
        selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
      }
  
      if ($this.parent('li').hasClass('active')) return
  
      var $previous = $ul.find('.active:last a')
      var hideEvent = $.Event('hide.bs.tab', {
        relatedTarget: $this[0]
      })
      var showEvent = $.Event('show.bs.tab', {
        relatedTarget: $previous[0]
      })
  
      $previous.trigger(hideEvent)
      $this.trigger(showEvent)
  
      if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return
  
      var $target = $(selector)
  
      this.activate($this.closest('li'), $ul)
      this.activate($target, $target.parent(), function () {
        $previous.trigger({
          type: 'hidden.bs.tab',
          relatedTarget: $this[0]
        })
        $this.trigger({
          type: 'shown.bs.tab',
          relatedTarget: $previous[0]
        })
      })
    }
  
    Tab.prototype.activate = function (element, container, callback) {
      var $active    = container.find('> .active')
      var transition = callback
        && $.support.transition
        && ($active.length && $active.hasClass('fade') || !!container.find('> .fade').length)
  
      function next() {
        $active
          .removeClass('active')
          .find('> .dropdown-menu > .active')
            .removeClass('active')
          .end()
          .find('[data-toggle="tab"]')
            .attr('aria-expanded', false)
  
        element
          .addClass('active')
          .find('[data-toggle="tab"]')
            .attr('aria-expanded', true)
  
        if (transition) {
          element[0].offsetWidth // reflow for transition
          element.addClass('in')
        } else {
          element.removeClass('fade')
        }
  
        if (element.parent('.dropdown-menu').length) {
          element
            .closest('li.dropdown')
              .addClass('active')
            .end()
            .find('[data-toggle="tab"]')
              .attr('aria-expanded', true)
        }
  
        callback && callback()
      }
  
      $active.length && transition ?
        $active
          .one('bsTransitionEnd', next)
          .emulateTransitionEnd(Tab.TRANSITION_DURATION) :
        next()
  
      $active.removeClass('in')
    }
  
  
    // TAB PLUGIN DEFINITION
    // =====================
  
    function Plugin(option) {
      return this.each(function () {
        var $this = $(this)
        var data  = $this.data('bs.tab')
  
        if (!data) $this.data('bs.tab', (data = new Tab(this)))
        if (typeof option == 'string') data[option]()
      })
    }
  
    var old = $.fn.tab
  
    $.fn.tab             = Plugin
    $.fn.tab.Constructor = Tab
  
  
    // TAB NO CONFLICT
    // ===============
  
    $.fn.tab.noConflict = function () {
      $.fn.tab = old
      return this
    }
  
  
    // TAB DATA-API
    // ============
  
    var clickHandler = function (e) {
      e.preventDefault()
      Plugin.call($(this), 'show')
    }
  
    $(document)
      .on('click.bs.tab.data-api', '[data-toggle="tab"]', clickHandler)
      .on('click.bs.tab.data-api', '[data-toggle="pill"]', clickHandler)
  
  }(jQuery);
  
  /*! =======================================================
   VERSION  9.5.3
   ========================================================= */
  "use strict";
  
  function _typeof(obj) { return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj; }
  
  /*! =========================================================
   * bootstrap-slider.js
   *
   * Maintainers:
   *		Kyle Kemp
   *			- Twitter: @seiyria
   *			- Github:  seiyria
   *		Rohit Kalkur
   *			- Twitter: @Rovolutionary
   *			- Github:  rovolution
   *
   * =========================================================
   *
   * bootstrap-slider is released under the MIT License
   * Copyright (c) 2016 Kyle Kemp, Rohit Kalkur, and contributors
   *
   * Permission is hereby granted, free of charge, to any person
   * obtaining a copy of this software and associated documentation
   * files (the "Software"), to deal in the Software without
   * restriction, including without limitation the rights to use,
   * copy, modify, merge, publish, distribute, sublicense, and/or sell
   * copies of the Software, and to permit persons to whom the
   * Software is furnished to do so, subject to the following
   * conditions:
   *
   * The above copyright notice and this permission notice shall be
   * included in all copies or substantial portions of the Software.
   *
   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
   * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
   * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
   * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
   * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
   * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
   * OTHER DEALINGS IN THE SOFTWARE.
   *
   * ========================================================= */
  
  /**
   * Bridget makes jQuery widgets
   * v1.0.1
   * MIT license
   */
  var windowIsDefined = (typeof window === "undefined" ? "undefined" : _typeof(window)) === "object";
  
  (function (factory) {
      if (typeof define === "function" && define.amd) {
          define(["jquery"], factory);
      } else if ((typeof module === "undefined" ? "undefined" : _typeof(module)) === "object" && module.exports) {
          var jQuery;
          try {
              jQuery = require("jquery");
          } catch (err) {
              jQuery = null;
          }
          module.exports = factory(jQuery);
      } else if (window) {
          window.Slider = factory(window.jQuery);
      }
  })(function ($) {
      // Constants
      var NAMESPACE_MAIN = 'slider';
      var NAMESPACE_ALTERNATE = 'bootstrapSlider';
  
      // Polyfill console methods
      if (windowIsDefined && !window.console) {
          window.console = {};
      }
      if (windowIsDefined && !window.console.log) {
          window.console.log = function () {};
      }
      if (windowIsDefined && !window.console.warn) {
          window.console.warn = function () {};
      }
  
      // Reference to Slider constructor
      var Slider;
  
      (function ($) {
  
          'use strict';
  
          // -------------------------- utils -------------------------- //
  
          var slice = Array.prototype.slice;
  
          function noop() {}
  
          // -------------------------- definition -------------------------- //
  
          function defineBridget($) {
  
              // bail if no jQuery
              if (!$) {
                  return;
              }
  
              // -------------------------- addOptionMethod -------------------------- //
  
              /**
               * adds option method -> $().plugin('option', {...})
               * @param {Function} PluginClass - constructor class
               */
              function addOptionMethod(PluginClass) {
                  // don't overwrite original option method
                  if (PluginClass.prototype.option) {
                      return;
                  }
  
                  // option setter
                  PluginClass.prototype.option = function (opts) {
                      // bail out if not an object
                      if (!$.isPlainObject(opts)) {
                          return;
                      }
                      this.options = $.extend(true, this.options, opts);
                  };
              }
  
              // -------------------------- plugin bridge -------------------------- //
  
              // helper function for logging errors
              // $.error breaks jQuery chaining
              var logError = typeof console === 'undefined' ? noop : function (message) {
                  console.error(message);
              };
  
              /**
               * jQuery plugin bridge, access methods like $elem.plugin('method')
               * @param {String} namespace - plugin name
               * @param {Function} PluginClass - constructor class
               */
              function bridge(namespace, PluginClass) {
                  // add to jQuery fn namespace
                  $.fn[namespace] = function (options) {
                      if (typeof options === 'string') {
                          // call plugin method when first argument is a string
                          // get arguments for method
                          var args = slice.call(arguments, 1);
  
                          for (var i = 0, len = this.length; i < len; i++) {
                              var elem = this[i];
                              var instance = $.data(elem, namespace);
                              if (!instance) {
                                  logError("cannot call methods on " + namespace + " prior to initialization; " + "attempted to call '" + options + "'");
                                  continue;
                              }
                              if (!$.isFunction(instance[options]) || options.charAt(0) === '_') {
                                  logError("no such method '" + options + "' for " + namespace + " instance");
                                  continue;
                              }
  
                              // trigger method with arguments
                              var returnValue = instance[options].apply(instance, args);
  
                              // break look and return first value if provided
                              if (returnValue !== undefined && returnValue !== instance) {
                                  return returnValue;
                              }
                          }
                          // return this if no return value
                          return this;
                      } else {
                          var objects = this.map(function () {
                              var instance = $.data(this, namespace);
                              if (instance) {
                                  // apply options & init
                                  instance.option(options);
                                  instance._init();
                              } else {
                                  // initialize new instance
                                  instance = new PluginClass(this, options);
                                  $.data(this, namespace, instance);
                              }
                              return $(this);
                          });
  
                          if (!objects || objects.length > 1) {
                              return objects;
                          } else {
                              return objects[0];
                          }
                      }
                  };
              }
  
              // -------------------------- bridget -------------------------- //
  
              /**
               * converts a Prototypical class into a proper jQuery plugin
               *   the class must have a ._init method
               * @param {String} namespace - plugin name, used in $().pluginName
               * @param {Function} PluginClass - constructor class
               */
              $.bridget = function (namespace, PluginClass) {
                  addOptionMethod(PluginClass);
                  bridge(namespace, PluginClass);
              };
  
              return $.bridget;
          }
  
          // get jquery from browser global
          defineBridget($);
      })($);
  
      /*************************************************
       BOOTSTRAP-SLIDER SOURCE CODE
       **************************************************/
  
      (function ($) {
  
          var ErrorMsgs = {
              formatInvalidInputErrorMsg: function formatInvalidInputErrorMsg(input) {
                  return "Invalid input value '" + input + "' passed in";
              },
              callingContextNotSliderInstance: "Calling context element does not have instance of Slider bound to it. Check your code to make sure the JQuery object returned from the call to the slider() initializer is calling the method"
          };
  
          var SliderScale = {
              linear: {
                  toValue: function toValue(percentage) {
                      var rawValue = percentage / 100 * (this.options.max - this.options.min);
                      var shouldAdjustWithBase = true;
                      if (this.options.ticks_positions.length > 0) {
                          var minv,
                              maxv,
                              minp,
                              maxp = 0;
                          for (var i = 1; i < this.options.ticks_positions.length; i++) {
                              if (percentage <= this.options.ticks_positions[i]) {
                                  minv = this.options.ticks[i - 1];
                                  minp = this.options.ticks_positions[i - 1];
                                  maxv = this.options.ticks[i];
                                  maxp = this.options.ticks_positions[i];
  
                                  break;
                              }
                          }
                          var partialPercentage = (percentage - minp) / (maxp - minp);
                          rawValue = minv + partialPercentage * (maxv - minv);
                          shouldAdjustWithBase = false;
                      }
  
                      var adjustment = shouldAdjustWithBase ? this.options.min : 0;
                      var value = adjustment + Math.round(rawValue / this.options.step) * this.options.step;
                      if (value < this.options.min) {
                          return this.options.min;
                      } else if (value > this.options.max) {
                          return this.options.max;
                      } else {
                          return value;
                      }
                  },
                  toPercentage: function toPercentage(value) {
                      if (this.options.max === this.options.min) {
                          return 0;
                      }
  
                      if (this.options.ticks_positions.length > 0) {
                          var minv,
                              maxv,
                              minp,
                              maxp = 0;
                          for (var i = 0; i < this.options.ticks.length; i++) {
                              if (value <= this.options.ticks[i]) {
                                  minv = i > 0 ? this.options.ticks[i - 1] : 0;
                                  minp = i > 0 ? this.options.ticks_positions[i - 1] : 0;
                                  maxv = this.options.ticks[i];
                                  maxp = this.options.ticks_positions[i];
  
                                  break;
                              }
                          }
                          if (i > 0) {
                              var partialPercentage = (value - minv) / (maxv - minv);
                              return minp + partialPercentage * (maxp - minp);
                          }
                      }
  
                      return 100 * (value - this.options.min) / (this.options.max - this.options.min);
                  }
              },
  
              logarithmic: {
                  /* Based on http://stackoverflow.com/questions/846221/logarithmic-slider */
                  toValue: function toValue(percentage) {
                      var min = this.options.min === 0 ? 0 : Math.log(this.options.min);
                      var max = Math.log(this.options.max);
                      var value = Math.exp(min + (max - min) * percentage / 100);
                      value = this.options.min + Math.round((value - this.options.min) / this.options.step) * this.options.step;
                      /* Rounding to the nearest step could exceed the min or
                       * max, so clip to those values. */
                      if (value < this.options.min) {
                          return this.options.min;
                      } else if (value > this.options.max) {
                          return this.options.max;
                      } else {
                          return value;
                      }
                  },
                  toPercentage: function toPercentage(value) {
                      if (this.options.max === this.options.min) {
                          return 0;
                      } else {
                          var max = Math.log(this.options.max);
                          var min = this.options.min === 0 ? 0 : Math.log(this.options.min);
                          var v = value === 0 ? 0 : Math.log(value);
                          return 100 * (v - min) / (max - min);
                      }
                  }
              }
          };
  
          /*************************************************
           CONSTRUCTOR
           **************************************************/
          Slider = function (element, options) {
              createNewSlider.call(this, element, options);
              return this;
          };
  
          function createNewSlider(element, options) {
  
              /*
               The internal state object is used to store data about the current 'state' of slider.
               This includes values such as the `value`, `enabled`, etc...
               */
              this._state = {
                  value: null,
                  enabled: null,
                  offset: null,
                  size: null,
                  percentage: null,
                  inDrag: false,
                  over: false
              };
  
              // The objects used to store the reference to the tick methods if ticks_tooltip is on
              this.ticksCallbackMap = {};
              this.handleCallbackMap = {};
  
              if (typeof element === "string") {
                  this.element = document.querySelector(element);
              } else if (element instanceof HTMLElement) {
                  this.element = element;
              }
  
              /*************************************************
               Process Options
               **************************************************/
              options = options ? options : {};
              var optionTypes = Object.keys(this.defaultOptions);
  
              for (var i = 0; i < optionTypes.length; i++) {
                  var optName = optionTypes[i];
  
                  // First check if an option was passed in via the constructor
                  var val = options[optName];
                  // If no data attrib, then check data atrributes
                  val = typeof val !== 'undefined' ? val : getDataAttrib(this.element, optName);
                  // Finally, if nothing was specified, use the defaults
                  val = val !== null ? val : this.defaultOptions[optName];
  
                  // Set all options on the instance of the Slider
                  if (!this.options) {
                      this.options = {};
                  }
                  this.options[optName] = val;
              }
  
              /*
               Validate `tooltip_position` against 'orientation`
               - if `tooltip_position` is incompatible with orientation, swith it to a default compatible with specified `orientation`
               -- default for "vertical" -> "right"
               -- default for "horizontal" -> "left"
               */
              if (this.options.orientation === "vertical" && (this.options.tooltip_position === "top" || this.options.tooltip_position === "bottom")) {
  
                  this.options.tooltip_position = "right";
              } else if (this.options.orientation === "horizontal" && (this.options.tooltip_position === "left" || this.options.tooltip_position === "right")) {
  
                  this.options.tooltip_position = "top";
              }
  
              function getDataAttrib(element, optName) {
                  var dataName = "data-slider-" + optName.replace(/_/g, '-');
                  var dataValString = element.getAttribute(dataName);
  
                  try {
                      return JSON.parse(dataValString);
                  } catch (err) {
                      return dataValString;
                  }
              }
  
              /*************************************************
               Create Markup
               **************************************************/
  
              var origWidth = this.element.style.width;
              var updateSlider = false;
              var parent = this.element.parentNode;
              var sliderTrackSelection;
              var sliderTrackLow, sliderTrackHigh;
              var sliderMinHandle;
              var sliderMaxHandle;
  
              if (this.sliderElem) {
                  updateSlider = true;
              } else {
                  /* Create elements needed for slider */
                  this.sliderElem = document.createElement("div");
                  this.sliderElem.className = "slider";
  
                  /* Create slider track elements */
                  var sliderTrack = document.createElement("div");
                  sliderTrack.className = "slider-track";
  
                  sliderTrackLow = document.createElement("div");
                  sliderTrackLow.className = "slider-track-low";
  
                  sliderTrackSelection = document.createElement("div");
                  sliderTrackSelection.className = "slider-selection";
  
                  sliderTrackHigh = document.createElement("div");
                  sliderTrackHigh.className = "slider-track-high";
  
                  sliderMinHandle = document.createElement("div");
                  sliderMinHandle.className = "slider-handle min-slider-handle";
                  sliderMinHandle.setAttribute('role', 'slider');
                  sliderMinHandle.setAttribute('aria-valuemin', this.options.min);
                  sliderMinHandle.setAttribute('aria-valuemax', this.options.max);
  
                  sliderMaxHandle = document.createElement("div");
                  sliderMaxHandle.className = "slider-handle max-slider-handle";
                  sliderMaxHandle.setAttribute('role', 'slider');
                  sliderMaxHandle.setAttribute('aria-valuemin', this.options.min);
                  sliderMaxHandle.setAttribute('aria-valuemax', this.options.max);
  
                  sliderTrack.appendChild(sliderTrackLow);
                  sliderTrack.appendChild(sliderTrackSelection);
                  sliderTrack.appendChild(sliderTrackHigh);
  
                  /* Create highlight range elements */
                  this.rangeHighlightElements = [];
                  if (Array.isArray(this.options.rangeHighlights) && this.options.rangeHighlights.length > 0) {
                      for (var j = 0; j < this.options.rangeHighlights.length; j++) {
  
                          var rangeHighlightElement = document.createElement("div");
                          rangeHighlightElement.className = "slider-rangeHighlight slider-selection";
  
                          this.rangeHighlightElements.push(rangeHighlightElement);
                          sliderTrack.appendChild(rangeHighlightElement);
                      }
                  }
  
                  /* Add aria-labelledby to handle's */
                  var isLabelledbyArray = Array.isArray(this.options.labelledby);
                  if (isLabelledbyArray && this.options.labelledby[0]) {
                      sliderMinHandle.setAttribute('aria-labelledby', this.options.labelledby[0]);
                  }
                  if (isLabelledbyArray && this.options.labelledby[1]) {
                      sliderMaxHandle.setAttribute('aria-labelledby', this.options.labelledby[1]);
                  }
                  if (!isLabelledbyArray && this.options.labelledby) {
                      sliderMinHandle.setAttribute('aria-labelledby', this.options.labelledby);
                      sliderMaxHandle.setAttribute('aria-labelledby', this.options.labelledby);
                  }
  
                  /* Create ticks */
                  this.ticks = [];
                  if (Array.isArray(this.options.ticks) && this.options.ticks.length > 0) {
                      this.ticksContainer = document.createElement('div');
                      this.ticksContainer.className = 'slider-tick-container';
  
                      for (i = 0; i < this.options.ticks.length; i++) {
                          var tick = document.createElement('div');
                          tick.className = 'slider-tick';
                          if (this.options.ticks_tooltip) {
                              var tickListenerReference = this._addTickListener();
                              var enterCallback = tickListenerReference.addMouseEnter(this, tick, i);
                              var leaveCallback = tickListenerReference.addMouseLeave(this, tick);
  
                              this.ticksCallbackMap[i] = {
                                  mouseEnter: enterCallback,
                                  mouseLeave: leaveCallback
                              };
                          }
                          this.ticks.push(tick);
                          this.ticksContainer.appendChild(tick);
                      }
  
                      sliderTrackSelection.className += " tick-slider-selection";
                  }
  
                  this.tickLabels = [];
                  if (Array.isArray(this.options.ticks_labels) && this.options.ticks_labels.length > 0) {
                      this.tickLabelContainer = document.createElement('div');
                      this.tickLabelContainer.className = 'slider-tick-label-container';
  
                      for (i = 0; i < this.options.ticks_labels.length; i++) {
                          var label = document.createElement('div');
                          var noTickPositionsSpecified = this.options.ticks_positions.length === 0;
                          var tickLabelsIndex = this.options.reversed && noTickPositionsSpecified ? this.options.ticks_labels.length - (i + 1) : i;
                          label.className = 'slider-tick-label';
                          label.innerHTML = this.options.ticks_labels[tickLabelsIndex];
  
                          this.tickLabels.push(label);
                          this.tickLabelContainer.appendChild(label);
                      }
                  }
  
                  var createAndAppendTooltipSubElements = function createAndAppendTooltipSubElements(tooltipElem) {
                      var arrow = document.createElement("div");
                      arrow.className = "tooltip-arrow";
  
                      var inner = document.createElement("div");
                      inner.className = "tooltip-inner";
  
                      tooltipElem.appendChild(arrow);
                      tooltipElem.appendChild(inner);
                  };
  
                  /* Create tooltip elements */
                  var sliderTooltip = document.createElement("div");
                  sliderTooltip.className = "tooltip tooltip-main";
                  sliderTooltip.setAttribute('role', 'presentation');
                  createAndAppendTooltipSubElements(sliderTooltip);
  
                  var sliderTooltipMin = document.createElement("div");
                  sliderTooltipMin.className = "tooltip tooltip-min";
                  sliderTooltipMin.setAttribute('role', 'presentation');
                  createAndAppendTooltipSubElements(sliderTooltipMin);
  
                  var sliderTooltipMax = document.createElement("div");
                  sliderTooltipMax.className = "tooltip tooltip-max";
                  sliderTooltipMax.setAttribute('role', 'presentation');
                  createAndAppendTooltipSubElements(sliderTooltipMax);
  
                  /* Append components to sliderElem */
                  this.sliderElem.appendChild(sliderTrack);
                  this.sliderElem.appendChild(sliderTooltip);
                  this.sliderElem.appendChild(sliderTooltipMin);
                  this.sliderElem.appendChild(sliderTooltipMax);
  
                  if (this.tickLabelContainer) {
                      this.sliderElem.appendChild(this.tickLabelContainer);
                  }
                  if (this.ticksContainer) {
                      this.sliderElem.appendChild(this.ticksContainer);
                  }
  
                  this.sliderElem.appendChild(sliderMinHandle);
                  this.sliderElem.appendChild(sliderMaxHandle);
  
                  /* Append slider element to parent container, right before the original <input> element */
                  parent.insertBefore(this.sliderElem, this.element);
  
                  /* Hide original <input> element */
                  this.element.style.display = "none";
              }
              /* If JQuery exists, cache JQ references */
              if ($) {
                  this.$element = $(this.element);
                  this.$sliderElem = $(this.sliderElem);
              }
  
              /*************************************************
               Setup
               **************************************************/
              this.eventToCallbackMap = {};
              this.sliderElem.id = this.options.id;
  
              this.touchCapable = 'ontouchstart' in window || window.DocumentTouch && document instanceof window.DocumentTouch;
  
              this.touchX = 0;
              this.touchY = 0;
  
              this.tooltip = this.sliderElem.querySelector('.tooltip-main');
              this.tooltipInner = this.tooltip.querySelector('.tooltip-inner');
  
              this.tooltip_min = this.sliderElem.querySelector('.tooltip-min');
              this.tooltipInner_min = this.tooltip_min.querySelector('.tooltip-inner');
  
              this.tooltip_max = this.sliderElem.querySelector('.tooltip-max');
              this.tooltipInner_max = this.tooltip_max.querySelector('.tooltip-inner');
  
              if (SliderScale[this.options.scale]) {
                  this.options.scale = SliderScale[this.options.scale];
              }
  
              if (updateSlider === true) {
                  // Reset classes
                  this._removeClass(this.sliderElem, 'slider-horizontal');
                  this._removeClass(this.sliderElem, 'slider-vertical');
                  this._removeClass(this.tooltip, 'hide');
                  this._removeClass(this.tooltip_min, 'hide');
                  this._removeClass(this.tooltip_max, 'hide');
  
                  // Undo existing inline styles for track
                  ["left", "top", "width", "height"].forEach(function (prop) {
                      this._removeProperty(this.trackLow, prop);
                      this._removeProperty(this.trackSelection, prop);
                      this._removeProperty(this.trackHigh, prop);
                  }, this);
  
                  // Undo inline styles on handles
                  [this.handle1, this.handle2].forEach(function (handle) {
                      this._removeProperty(handle, 'left');
                      this._removeProperty(handle, 'top');
                  }, this);
  
                  // Undo inline styles and classes on tooltips
                  [this.tooltip, this.tooltip_min, this.tooltip_max].forEach(function (tooltip) {
                      this._removeProperty(tooltip, 'left');
                      this._removeProperty(tooltip, 'top');
                      this._removeProperty(tooltip, 'margin-left');
                      this._removeProperty(tooltip, 'margin-top');
  
                      this._removeClass(tooltip, 'right');
                      this._removeClass(tooltip, 'top');
                  }, this);
              }
  
              if (this.options.orientation === 'vertical') {
                  this._addClass(this.sliderElem, 'slider-vertical');
                  this.stylePos = 'top';
                  this.mousePos = 'pageY';
                  this.sizePos = 'offsetHeight';
              } else {
                  this._addClass(this.sliderElem, 'slider-horizontal');
                  this.sliderElem.style.width = origWidth;
                  this.options.orientation = 'horizontal';
                  this.stylePos = 'left';
                  this.mousePos = 'pageX';
                  this.sizePos = 'offsetWidth';
              }
              this._setTooltipPosition();
              /* In case ticks are specified, overwrite the min and max bounds */
              if (Array.isArray(this.options.ticks) && this.options.ticks.length > 0) {
                  this.options.max = Math.max.apply(Math, this.options.ticks);
                  this.options.min = Math.min.apply(Math, this.options.ticks);
              }
  
              if (Array.isArray(this.options.value)) {
                  this.options.range = true;
                  this._state.value = this.options.value;
              } else if (this.options.range) {
                  // User wants a range, but value is not an array
                  this._state.value = [this.options.value, this.options.max];
              } else {
                  this._state.value = this.options.value;
              }
  
              this.trackLow = sliderTrackLow || this.trackLow;
              this.trackSelection = sliderTrackSelection || this.trackSelection;
              this.trackHigh = sliderTrackHigh || this.trackHigh;
  
              if (this.options.selection === 'none') {
                  this._addClass(this.trackLow, 'hide');
                  this._addClass(this.trackSelection, 'hide');
                  this._addClass(this.trackHigh, 'hide');
              } else if (this.options.selection === 'after' || this.options.selection === 'before') {
                  this._removeClass(this.trackLow, 'hide');
                  this._removeClass(this.trackSelection, 'hide');
                  this._removeClass(this.trackHigh, 'hide');
              }
  
              this.handle1 = sliderMinHandle || this.handle1;
              this.handle2 = sliderMaxHandle || this.handle2;
  
              if (updateSlider === true) {
                  // Reset classes
                  this._removeClass(this.handle1, 'round triangle');
                  this._removeClass(this.handle2, 'round triangle hide');
  
                  for (i = 0; i < this.ticks.length; i++) {
                      this._removeClass(this.ticks[i], 'round triangle hide');
                  }
              }
  
              var availableHandleModifiers = ['round', 'triangle', 'custom'];
              var isValidHandleType = availableHandleModifiers.indexOf(this.options.handle) !== -1;
              if (isValidHandleType) {
                  this._addClass(this.handle1, this.options.handle);
                  this._addClass(this.handle2, this.options.handle);
  
                  for (i = 0; i < this.ticks.length; i++) {
                      this._addClass(this.ticks[i], this.options.handle);
                  }
              }
  
              this._state.offset = this._offset(this.sliderElem);
              this._state.size = this.sliderElem[this.sizePos];
              this.setValue(this._state.value);
  
              /******************************************
               Bind Event Listeners
               ******************************************/
  
              // Bind keyboard handlers
              this.handle1Keydown = this._keydown.bind(this, 0);
              this.handle1.addEventListener("keydown", this.handle1Keydown, false);
  
              this.handle2Keydown = this._keydown.bind(this, 1);
              this.handle2.addEventListener("keydown", this.handle2Keydown, false);
  
              this.mousedown = this._mousedown.bind(this);
              this.touchstart = this._touchstart.bind(this);
              this.touchmove = this._touchmove.bind(this);
  
              if (this.touchCapable) {
                  // Bind touch handlers
                  this.sliderElem.addEventListener("touchstart", this.touchstart, false);
                  this.sliderElem.addEventListener("touchmove", this.touchmove, false);
              }
              this.sliderElem.addEventListener("mousedown", this.mousedown, false);
  
              // Bind window handlers
              this.resize = this._resize.bind(this);
              window.addEventListener("resize", this.resize, false);
  
              // Bind tooltip-related handlers
              if (this.options.tooltip === 'hide') {
                  this._addClass(this.tooltip, 'hide');
                  this._addClass(this.tooltip_min, 'hide');
                  this._addClass(this.tooltip_max, 'hide');
              } else if (this.options.tooltip === 'always') {
                  this._showTooltip();
                  this._alwaysShowTooltip = true;
              } else {
                  this.showTooltip = this._showTooltip.bind(this);
                  this.hideTooltip = this._hideTooltip.bind(this);
  
                  if (this.options.ticks_tooltip) {
                      var callbackHandle = this._addTickListener();
                      //create handle1 listeners and store references in map
                      var mouseEnter = callbackHandle.addMouseEnter(this, this.handle1);
                      var mouseLeave = callbackHandle.addMouseLeave(this, this.handle1);
                      this.handleCallbackMap.handle1 = {
                          mouseEnter: mouseEnter,
                          mouseLeave: mouseLeave
                      };
                      //create handle2 listeners and store references in map
                      mouseEnter = callbackHandle.addMouseEnter(this, this.handle2);
                      mouseLeave = callbackHandle.addMouseLeave(this, this.handle2);
                      this.handleCallbackMap.handle2 = {
                          mouseEnter: mouseEnter,
                          mouseLeave: mouseLeave
                      };
                  } else {
                      this.sliderElem.addEventListener("mouseenter", this.showTooltip, false);
                      this.sliderElem.addEventListener("mouseleave", this.hideTooltip, false);
                  }
  
                  this.handle1.addEventListener("focus", this.showTooltip, false);
                  this.handle1.addEventListener("blur", this.hideTooltip, false);
  
                  this.handle2.addEventListener("focus", this.showTooltip, false);
                  this.handle2.addEventListener("blur", this.hideTooltip, false);
              }
  
              if (this.options.enabled) {
                  this.enable();
              } else {
                  this.disable();
              }
          }
  
          /*************************************************
           INSTANCE PROPERTIES/METHODS
           - Any methods bound to the prototype are considered
           part of the plugin's `public` interface
           **************************************************/
          Slider.prototype = {
              _init: function _init() {}, // NOTE: Must exist to support bridget
  
              constructor: Slider,
  
              defaultOptions: {
                  id: "",
                  min: 0,
                  max: 10,
                  step: 1,
                  precision: 0,
                  orientation: 'horizontal',
                  value: 5,
                  range: false,
                  selection: 'before',
                  tooltip: 'show',
                  tooltip_split: false,
                  handle: 'round',
                  reversed: false,
                  enabled: true,
                  formatter: function formatter(val) {
                      if (Array.isArray(val)) {
                          return val[0] + " : " + val[1];
                      } else {
                          return val;
                      }
                  },
                  natural_arrow_keys: false,
                  ticks: [],
                  ticks_positions: [],
                  ticks_labels: [],
                  ticks_snap_bounds: 0,
                  ticks_tooltip: false,
                  scale: 'linear',
                  focus: false,
                  tooltip_position: null,
                  labelledby: null,
                  rangeHighlights: []
              },
  
              getElement: function getElement() {
                  return this.sliderElem;
              },
  
              getValue: function getValue() {
                  if (this.options.range) {
                      return this._state.value;
                  } else {
                      return this._state.value[0];
                  }
              },
  
              setValue: function setValue(val, triggerSlideEvent, triggerChangeEvent) {
                  if (!val) {
                      val = 0;
                  }
                  var oldValue = this.getValue();
                  this._state.value = this._validateInputValue(val);
                  var applyPrecision = this._applyPrecision.bind(this);
  
                  if (this.options.range) {
                      this._state.value[0] = applyPrecision(this._state.value[0]);
                      this._state.value[1] = applyPrecision(this._state.value[1]);
  
                      this._state.value[0] = Math.max(this.options.min, Math.min(this.options.max, this._state.value[0]));
                      this._state.value[1] = Math.max(this.options.min, Math.min(this.options.max, this._state.value[1]));
                  } else {
                      this._state.value = applyPrecision(this._state.value);
                      this._state.value = [Math.max(this.options.min, Math.min(this.options.max, this._state.value))];
                      this._addClass(this.handle2, 'hide');
                      if (this.options.selection === 'after') {
                          this._state.value[1] = this.options.max;
                      } else {
                          this._state.value[1] = this.options.min;
                      }
                  }
  
                  if (this.options.max > this.options.min) {
                      this._state.percentage = [this._toPercentage(this._state.value[0]), this._toPercentage(this._state.value[1]), this.options.step * 100 / (this.options.max - this.options.min)];
                  } else {
                      this._state.percentage = [0, 0, 100];
                  }
  
                  this._layout();
                  var newValue = this.options.range ? this._state.value : this._state.value[0];
  
                  this._setDataVal(newValue);
                  if (triggerSlideEvent === true) {
                      this._trigger('slide', newValue);
                  }
                  if (oldValue !== newValue && triggerChangeEvent === true) {
                      this._trigger('change', {
                          oldValue: oldValue,
                          newValue: newValue
                      });
                  }
  
                  return this;
              },
  
              destroy: function destroy() {
                  // Remove event handlers on slider elements
                  this._removeSliderEventHandlers();
  
                  // Remove the slider from the DOM
                  this.sliderElem.parentNode.removeChild(this.sliderElem);
                  /* Show original <input> element */
                  this.element.style.display = "";
  
                  // Clear out custom event bindings
                  this._cleanUpEventCallbacksMap();
  
                  // Remove data values
                  this.element.removeAttribute("data");
  
                  // Remove JQuery handlers/data
                  if ($) {
                      this._unbindJQueryEventHandlers();
                      this.$element.removeData('slider');
                  }
              },
  
              disable: function disable() {
                  this._state.enabled = false;
                  this.handle1.removeAttribute("tabindex");
                  this.handle2.removeAttribute("tabindex");
                  this._addClass(this.sliderElem, 'slider-disabled');
                  this._trigger('slideDisabled');
  
                  return this;
              },
  
              enable: function enable() {
                  this._state.enabled = true;
                  this.handle1.setAttribute("tabindex", 0);
                  this.handle2.setAttribute("tabindex", 0);
                  this._removeClass(this.sliderElem, 'slider-disabled');
                  this._trigger('slideEnabled');
  
                  return this;
              },
  
              toggle: function toggle() {
                  if (this._state.enabled) {
                      this.disable();
                  } else {
                      this.enable();
                  }
                  return this;
              },
  
              isEnabled: function isEnabled() {
                  return this._state.enabled;
              },
  
              on: function on(evt, callback) {
                  this._bindNonQueryEventHandler(evt, callback);
                  return this;
              },
  
              off: function off(evt, callback) {
                  if ($) {
                      this.$element.off(evt, callback);
                      this.$sliderElem.off(evt, callback);
                  } else {
                      this._unbindNonQueryEventHandler(evt, callback);
                  }
              },
  
              getAttribute: function getAttribute(attribute) {
                  if (attribute) {
                      return this.options[attribute];
                  } else {
                      return this.options;
                  }
              },
  
              setAttribute: function setAttribute(attribute, value) {
                  this.options[attribute] = value;
                  return this;
              },
  
              refresh: function refresh() {
                  this._removeSliderEventHandlers();
                  createNewSlider.call(this, this.element, this.options);
                  if ($) {
                      // Bind new instance of slider to the element
                      $.data(this.element, 'slider', this);
                  }
                  return this;
              },
  
              relayout: function relayout() {
                  this._resize();
                  this._layout();
                  return this;
              },
  
              /******************************+
               HELPERS
               - Any method that is not part of the public interface.
               - Place it underneath this comment block and write its signature like so:
               _fnName : function() {...}
               ********************************/
              _removeSliderEventHandlers: function _removeSliderEventHandlers() {
                  // Remove keydown event listeners
                  this.handle1.removeEventListener("keydown", this.handle1Keydown, false);
                  this.handle2.removeEventListener("keydown", this.handle2Keydown, false);
  
                  //remove the listeners from the ticks and handles if they had their own listeners
                  if (this.options.ticks_tooltip) {
                      var ticks = this.ticksContainer.getElementsByClassName('slider-tick');
                      for (var i = 0; i < ticks.length; i++) {
                          ticks[i].removeEventListener('mouseenter', this.ticksCallbackMap[i].mouseEnter, false);
                          ticks[i].removeEventListener('mouseleave', this.ticksCallbackMap[i].mouseLeave, false);
                      }
                      this.handle1.removeEventListener('mouseenter', this.handleCallbackMap.handle1.mouseEnter, false);
                      this.handle2.removeEventListener('mouseenter', this.handleCallbackMap.handle2.mouseEnter, false);
                      this.handle1.removeEventListener('mouseleave', this.handleCallbackMap.handle1.mouseLeave, false);
                      this.handle2.removeEventListener('mouseleave', this.handleCallbackMap.handle2.mouseLeave, false);
                  }
  
                  this.handleCallbackMap = null;
                  this.ticksCallbackMap = null;
  
                  if (this.showTooltip) {
                      this.handle1.removeEventListener("focus", this.showTooltip, false);
                      this.handle2.removeEventListener("focus", this.showTooltip, false);
                  }
                  if (this.hideTooltip) {
                      this.handle1.removeEventListener("blur", this.hideTooltip, false);
                      this.handle2.removeEventListener("blur", this.hideTooltip, false);
                  }
  
                  // Remove event listeners from sliderElem
                  if (this.showTooltip) {
                      this.sliderElem.removeEventListener("mouseenter", this.showTooltip, false);
                  }
                  if (this.hideTooltip) {
                      this.sliderElem.removeEventListener("mouseleave", this.hideTooltip, false);
                  }
                  this.sliderElem.removeEventListener("touchstart", this.touchstart, false);
                  this.sliderElem.removeEventListener("touchmove", this.touchmove, false);
                  this.sliderElem.removeEventListener("mousedown", this.mousedown, false);
  
                  // Remove window event listener
                  window.removeEventListener("resize", this.resize, false);
              },
              _bindNonQueryEventHandler: function _bindNonQueryEventHandler(evt, callback) {
                  if (this.eventToCallbackMap[evt] === undefined) {
                      this.eventToCallbackMap[evt] = [];
                  }
                  this.eventToCallbackMap[evt].push(callback);
              },
              _unbindNonQueryEventHandler: function _unbindNonQueryEventHandler(evt, callback) {
                  var callbacks = this.eventToCallbackMap[evt];
                  if (callbacks !== undefined) {
                      for (var i = 0; i < callbacks.length; i++) {
                          if (callbacks[i] === callback) {
                              callbacks.splice(i, 1);
                              break;
                          }
                      }
                  }
              },
              _cleanUpEventCallbacksMap: function _cleanUpEventCallbacksMap() {
                  var eventNames = Object.keys(this.eventToCallbackMap);
                  for (var i = 0; i < eventNames.length; i++) {
                      var eventName = eventNames[i];
                      delete this.eventToCallbackMap[eventName];
                  }
              },
              _showTooltip: function _showTooltip() {
                  if (this.options.tooltip_split === false) {
                      this._addClass(this.tooltip, 'in');
                      this.tooltip_min.style.display = 'none';
                      this.tooltip_max.style.display = 'none';
                  } else {
                      this._addClass(this.tooltip_min, 'in');
                      this._addClass(this.tooltip_max, 'in');
                      this.tooltip.style.display = 'none';
                  }
                  this._state.over = true;
              },
              _hideTooltip: function _hideTooltip() {
                  if (this._state.inDrag === false && this.alwaysShowTooltip !== true) {
                      this._removeClass(this.tooltip, 'in');
                      this._removeClass(this.tooltip_min, 'in');
                      this._removeClass(this.tooltip_max, 'in');
                  }
                  this._state.over = false;
              },
              _setToolTipOnMouseOver: function _setToolTipOnMouseOver(tempState) {
                  var formattedTooltipVal = this.options.formatter(!tempState ? this._state.value[0] : tempState.value[0]);
                  var positionPercentages = !tempState ? getPositionPercentages(this._state, this.options.reversed) : getPositionPercentages(tempState, this.options.reversed);
                  this._setText(this.tooltipInner, formattedTooltipVal);
  
                  this.tooltip.style[this.stylePos] = positionPercentages[0] + '%';
                  if (this.options.orientation === 'vertical') {
                      this._css(this.tooltip, 'margin-top', -this.tooltip.offsetHeight / 2 + 'px');
                  } else {
                      this._css(this.tooltip, 'margin-left', -this.tooltip.offsetWidth / 2 + 'px');
                  }
  
                  function getPositionPercentages(state, reversed) {
                      if (reversed) {
                          return [100 - state.percentage[0], this.options.range ? 100 - state.percentage[1] : state.percentage[1]];
                      }
                      return [state.percentage[0], state.percentage[1]];
                  }
              },
              _addTickListener: function _addTickListener() {
                  return {
                      addMouseEnter: function addMouseEnter(reference, tick, index) {
                          var enter = function enter() {
                              var tempState = reference._state;
                              var idString = index >= 0 ? index : this.attributes['aria-valuenow'].value;
                              var hoverIndex = parseInt(idString, 10);
                              tempState.value[0] = hoverIndex;
                              tempState.percentage[0] = reference.options.ticks_positions[hoverIndex];
                              reference._setToolTipOnMouseOver(tempState);
                              reference._showTooltip();
                          };
                          tick.addEventListener("mouseenter", enter, false);
                          return enter;
                      },
                      addMouseLeave: function addMouseLeave(reference, tick) {
                          var leave = function leave() {
                              reference._hideTooltip();
                          };
                          tick.addEventListener("mouseleave", leave, false);
                          return leave;
                      }
                  };
              },
              _layout: function _layout() {
                  var positionPercentages;
  
                  if (this.options.reversed) {
                      positionPercentages = [100 - this._state.percentage[0], this.options.range ? 100 - this._state.percentage[1] : this._state.percentage[1]];
                  } else {
                      positionPercentages = [this._state.percentage[0], this._state.percentage[1]];
                  }
  
                  this.handle1.style[this.stylePos] = positionPercentages[0] + '%';
                  this.handle1.setAttribute('aria-valuenow', this._state.value[0]);
                  if (isNaN(this.options.formatter(this._state.value[0]))) {
                      this.handle1.setAttribute('aria-valuetext', this.options.formatter(this._state.value[0]));
                  }
  
                  this.handle2.style[this.stylePos] = positionPercentages[1] + '%';
                  this.handle2.setAttribute('aria-valuenow', this._state.value[1]);
                  if (isNaN(this.options.formatter(this._state.value[1]))) {
                      this.handle2.setAttribute('aria-valuetext', this.options.formatter(this._state.value[1]));
                  }
  
                  /* Position highlight range elements */
                  if (this.rangeHighlightElements.length > 0 && Array.isArray(this.options.rangeHighlights) && this.options.rangeHighlights.length > 0) {
                      for (var _i = 0; _i < this.options.rangeHighlights.length; _i++) {
                          var startPercent = this._toPercentage(this.options.rangeHighlights[_i].start);
                          var endPercent = this._toPercentage(this.options.rangeHighlights[_i].end);
  
                          if (this.options.reversed) {
                              var sp = 100 - endPercent;
                              endPercent = 100 - startPercent;
                              startPercent = sp;
                          }
  
                          var currentRange = this._createHighlightRange(startPercent, endPercent);
  
                          if (currentRange) {
                              if (this.options.orientation === 'vertical') {
                                  this.rangeHighlightElements[_i].style.top = currentRange.start + "%";
                                  this.rangeHighlightElements[_i].style.height = currentRange.size + "%";
                              } else {
                                  this.rangeHighlightElements[_i].style.left = currentRange.start + "%";
                                  this.rangeHighlightElements[_i].style.width = currentRange.size + "%";
                              }
                          } else {
                              this.rangeHighlightElements[_i].style.display = "none";
                          }
                      }
                  }
  
                  /* Position ticks and labels */
                  if (Array.isArray(this.options.ticks) && this.options.ticks.length > 0) {
  
                      var styleSize = this.options.orientation === 'vertical' ? 'height' : 'width';
                      var styleMargin = this.options.orientation === 'vertical' ? 'marginTop' : 'marginLeft';
                      var labelSize = this._state.size / (this.options.ticks.length - 1);
  
                      if (this.tickLabelContainer) {
                          var extraMargin = 0;
                          if (this.options.ticks_positions.length === 0) {
                              if (this.options.orientation !== 'vertical') {
                                  this.tickLabelContainer.style[styleMargin] = -labelSize / 2 + 'px';
                              }
  
                              extraMargin = this.tickLabelContainer.offsetHeight;
                          } else {
                              /* Chidren are position absolute, calculate height by finding the max offsetHeight of a child */
                              for (i = 0; i < this.tickLabelContainer.childNodes.length; i++) {
                                  if (this.tickLabelContainer.childNodes[i].offsetHeight > extraMargin) {
                                      extraMargin = this.tickLabelContainer.childNodes[i].offsetHeight;
                                  }
                              }
                          }
                          if (this.options.orientation === 'horizontal') {
                              this.sliderElem.style.marginBottom = extraMargin + 'px';
                          }
                      }
                      for (var i = 0; i < this.options.ticks.length; i++) {
  
                          var percentage = this.options.ticks_positions[i] || this._toPercentage(this.options.ticks[i]);
  
                          if (this.options.reversed) {
                              percentage = 100 - percentage;
                          }
  
                          this.ticks[i].style[this.stylePos] = percentage + '%';
  
                          /* Set class labels to denote whether ticks are in the selection */
                          this._removeClass(this.ticks[i], 'in-selection');
                          if (!this.options.range) {
                              if (this.options.selection === 'after' && percentage >= positionPercentages[0]) {
                                  this._addClass(this.ticks[i], 'in-selection');
                              } else if (this.options.selection === 'before' && percentage <= positionPercentages[0]) {
                                  this._addClass(this.ticks[i], 'in-selection');
                              }
                          } else if (percentage >= positionPercentages[0] && percentage <= positionPercentages[1]) {
                              this._addClass(this.ticks[i], 'in-selection');
                          }
  
                          if (this.tickLabels[i]) {
                              this.tickLabels[i].style[styleSize] = labelSize + 'px';
  
                              if (this.options.orientation !== 'vertical' && this.options.ticks_positions[i] !== undefined) {
                                  this.tickLabels[i].style.position = 'absolute';
                                  this.tickLabels[i].style[this.stylePos] = percentage + '%';
                                  this.tickLabels[i].style[styleMargin] = -labelSize / 2 + 'px';
                              } else if (this.options.orientation === 'vertical') {
                                  this.tickLabels[i].style['marginLeft'] = this.sliderElem.offsetWidth + 'px';
                                  this.tickLabelContainer.style['marginTop'] = this.sliderElem.offsetWidth / 2 * -1 + 'px';
                              }
                          }
                      }
                  }
  
                  var formattedTooltipVal;
  
                  if (this.options.range) {
                      formattedTooltipVal = this.options.formatter(this._state.value);
                      this._setText(this.tooltipInner, formattedTooltipVal);
                      this.tooltip.style[this.stylePos] = (positionPercentages[1] + positionPercentages[0]) / 2 + '%';
  
                      if (this.options.orientation === 'vertical') {
                          this._css(this.tooltip, 'margin-top', -this.tooltip.offsetHeight / 2 + 'px');
                      } else {
                          this._css(this.tooltip, 'margin-left', -this.tooltip.offsetWidth / 2 + 'px');
                      }
  
                      if (this.options.orientation === 'vertical') {
                          this._css(this.tooltip, 'margin-top', -this.tooltip.offsetHeight / 2 + 'px');
                      } else {
                          this._css(this.tooltip, 'margin-left', -this.tooltip.offsetWidth / 2 + 'px');
                      }
  
                      var innerTooltipMinText = this.options.formatter(this._state.value[0]);
                      this._setText(this.tooltipInner_min, innerTooltipMinText);
  
                      var innerTooltipMaxText = this.options.formatter(this._state.value[1]);
                      this._setText(this.tooltipInner_max, innerTooltipMaxText);
  
                      this.tooltip_min.style[this.stylePos] = positionPercentages[0] + '%';
  
                      if (this.options.orientation === 'vertical') {
                          this._css(this.tooltip_min, 'margin-top', -this.tooltip_min.offsetHeight / 2 + 'px');
                      } else {
                          this._css(this.tooltip_min, 'margin-left', -this.tooltip_min.offsetWidth / 2 + 'px');
                      }
  
                      this.tooltip_max.style[this.stylePos] = positionPercentages[1] + '%';
  
                      if (this.options.orientation === 'vertical') {
                          this._css(this.tooltip_max, 'margin-top', -this.tooltip_max.offsetHeight / 2 + 'px');
                      } else {
                          this._css(this.tooltip_max, 'margin-left', -this.tooltip_max.offsetWidth / 2 + 'px');
                      }
                  } else {
                      formattedTooltipVal = this.options.formatter(this._state.value[0]);
                      this._setText(this.tooltipInner, formattedTooltipVal);
  
                      this.tooltip.style[this.stylePos] = positionPercentages[0] + '%';
                      if (this.options.orientation === 'vertical') {
                          this._css(this.tooltip, 'margin-top', -this.tooltip.offsetHeight / 2 + 'px');
                      } else {
                          this._css(this.tooltip, 'margin-left', -this.tooltip.offsetWidth / 2 + 'px');
                      }
                  }
  
                  if (this.options.orientation === 'vertical') {
                      this.trackLow.style.top = '0';
                      this.trackLow.style.height = Math.min(positionPercentages[0], positionPercentages[1]) + '%';
  
                      this.trackSelection.style.top = Math.min(positionPercentages[0], positionPercentages[1]) + '%';
                      this.trackSelection.style.height = Math.abs(positionPercentages[0] - positionPercentages[1]) + '%';
  
                      this.trackHigh.style.bottom = '0';
                      this.trackHigh.style.height = 100 - Math.min(positionPercentages[0], positionPercentages[1]) - Math.abs(positionPercentages[0] - positionPercentages[1]) + '%';
                  } else {
                      this.trackLow.style.left = '0';
                      this.trackLow.style.width = Math.min(positionPercentages[0], positionPercentages[1]) + '%';
  
                      this.trackSelection.style.left = Math.min(positionPercentages[0], positionPercentages[1]) + '%';
                      this.trackSelection.style.width = Math.abs(positionPercentages[0] - positionPercentages[1]) + '%';
  
                      this.trackHigh.style.right = '0';
                      this.trackHigh.style.width = 100 - Math.min(positionPercentages[0], positionPercentages[1]) - Math.abs(positionPercentages[0] - positionPercentages[1]) + '%';
  
                      var offset_min = this.tooltip_min.getBoundingClientRect();
                      var offset_max = this.tooltip_max.getBoundingClientRect();
  
                      if (this.options.tooltip_position === 'bottom') {
                          if (offset_min.right > offset_max.left) {
                              this._removeClass(this.tooltip_max, 'bottom');
                              this._addClass(this.tooltip_max, 'top');
                              this.tooltip_max.style.top = '';
                              this.tooltip_max.style.bottom = 22 + 'px';
                          } else {
                              this._removeClass(this.tooltip_max, 'top');
                              this._addClass(this.tooltip_max, 'bottom');
                              this.tooltip_max.style.top = this.tooltip_min.style.top;
                              this.tooltip_max.style.bottom = '';
                          }
                      } else {
                          if (offset_min.right > offset_max.left) {
                              this._removeClass(this.tooltip_max, 'top');
                              this._addClass(this.tooltip_max, 'bottom');
                              this.tooltip_max.style.top = 18 + 'px';
                          } else {
                              this._removeClass(this.tooltip_max, 'bottom');
                              this._addClass(this.tooltip_max, 'top');
                              this.tooltip_max.style.top = this.tooltip_min.style.top;
                          }
                      }
                  }
              },
              _createHighlightRange: function _createHighlightRange(start, end) {
                  if (this._isHighlightRange(start, end)) {
                      if (start > end) {
                          return { 'start': end, 'size': start - end };
                      }
                      return { 'start': start, 'size': end - start };
                  }
                  return null;
              },
              _isHighlightRange: function _isHighlightRange(start, end) {
                  if (0 <= start && start <= 100 && 0 <= end && end <= 100) {
                      return true;
                  } else {
                      return false;
                  }
              },
              _resize: function _resize(ev) {
                  /*jshint unused:false*/
                  this._state.offset = this._offset(this.sliderElem);
                  this._state.size = this.sliderElem[this.sizePos];
                  this._layout();
              },
              _removeProperty: function _removeProperty(element, prop) {
                  if (element.style.removeProperty) {
                      element.style.removeProperty(prop);
                  } else {
                      element.style.removeAttribute(prop);
                  }
              },
              _mousedown: function _mousedown(ev) {
                  if (!this._state.enabled) {
                      return false;
                  }
  
                  this._state.offset = this._offset(this.sliderElem);
                  this._state.size = this.sliderElem[this.sizePos];
  
                  var percentage = this._getPercentage(ev);
  
                  if (this.options.range) {
                      var diff1 = Math.abs(this._state.percentage[0] - percentage);
                      var diff2 = Math.abs(this._state.percentage[1] - percentage);
                      this._state.dragged = diff1 < diff2 ? 0 : 1;
                      this._adjustPercentageForRangeSliders(percentage);
                  } else {
                      this._state.dragged = 0;
                  }
  
                  this._state.percentage[this._state.dragged] = percentage;
                  this._layout();
  
                  if (this.touchCapable) {
                      document.removeEventListener("touchmove", this.mousemove, false);
                      document.removeEventListener("touchend", this.mouseup, false);
                  }
  
                  if (this.mousemove) {
                      document.removeEventListener("mousemove", this.mousemove, false);
                  }
                  if (this.mouseup) {
                      document.removeEventListener("mouseup", this.mouseup, false);
                  }
  
                  this.mousemove = this._mousemove.bind(this);
                  this.mouseup = this._mouseup.bind(this);
  
                  if (this.touchCapable) {
                      // Touch: Bind touch events:
                      document.addEventListener("touchmove", this.mousemove, false);
                      document.addEventListener("touchend", this.mouseup, false);
                  }
                  // Bind mouse events:
                  document.addEventListener("mousemove", this.mousemove, false);
                  document.addEventListener("mouseup", this.mouseup, false);
  
                  this._state.inDrag = true;
                  var newValue = this._calculateValue();
  
                  this._trigger('slideStart', newValue);
  
                  this._setDataVal(newValue);
                  this.setValue(newValue, false, true);
  
                  this._pauseEvent(ev);
  
                  if (this.options.focus) {
                      this._triggerFocusOnHandle(this._state.dragged);
                  }
  
                  return true;
              },
              _touchstart: function _touchstart(ev) {
                  if (ev.changedTouches === undefined) {
                      this._mousedown(ev);
                      return;
                  }
  
                  var touch = ev.changedTouches[0];
                  this.touchX = touch.pageX;
                  this.touchY = touch.pageY;
              },
              _triggerFocusOnHandle: function _triggerFocusOnHandle(handleIdx) {
                  if (handleIdx === 0) {
                      this.handle1.focus();
                  }
                  if (handleIdx === 1) {
                      this.handle2.focus();
                  }
              },
              _keydown: function _keydown(handleIdx, ev) {
                  if (!this._state.enabled) {
                      return false;
                  }
  
                  var dir;
                  switch (ev.keyCode) {
                      case 37: // left
                      case 40:
                          // down
                          dir = -1;
                          break;
                      case 39: // right
                      case 38:
                          // up
                          dir = 1;
                          break;
                  }
                  if (!dir) {
                      return;
                  }
  
                  // use natural arrow keys instead of from min to max
                  if (this.options.natural_arrow_keys) {
                      var ifVerticalAndNotReversed = this.options.orientation === 'vertical' && !this.options.reversed;
                      var ifHorizontalAndReversed = this.options.orientation === 'horizontal' && this.options.reversed;
  
                      if (ifVerticalAndNotReversed || ifHorizontalAndReversed) {
                          dir = -dir;
                      }
                  }
  
                  var val = this._state.value[handleIdx] + dir * this.options.step;
                  if (this.options.range) {
                      val = [!handleIdx ? val : this._state.value[0], handleIdx ? val : this._state.value[1]];
                  }
  
                  this._trigger('slideStart', val);
                  this._setDataVal(val);
                  this.setValue(val, true, true);
  
                  this._setDataVal(val);
                  this._trigger('slideStop', val);
                  this._layout();
  
                  this._pauseEvent(ev);
  
                  return false;
              },
              _pauseEvent: function _pauseEvent(ev) {
                  if (ev.stopPropagation) {
                      ev.stopPropagation();
                  }
                  if (ev.preventDefault) {
                      ev.preventDefault();
                  }
                  ev.cancelBubble = true;
                  ev.returnValue = false;
              },
              _mousemove: function _mousemove(ev) {
                  if (!this._state.enabled) {
                      return false;
                  }
  
                  var percentage = this._getPercentage(ev);
                  this._adjustPercentageForRangeSliders(percentage);
                  this._state.percentage[this._state.dragged] = percentage;
                  this._layout();
  
                  var val = this._calculateValue(true);
                  this.setValue(val, true, true);
  
                  return false;
              },
              _touchmove: function _touchmove(ev) {
                  if (ev.changedTouches === undefined) {
                      return;
                  }
  
                  var touch = ev.changedTouches[0];
  
                  var xDiff = touch.pageX - this.touchX;
                  var yDiff = touch.pageY - this.touchY;
  
                  if (!this._state.inDrag) {
                      // Vertical Slider
                      if (this.options.orientation === 'vertical' && xDiff <= 5 && xDiff >= -5 && (yDiff >= 15 || yDiff <= -15)) {
                          this._mousedown(ev);
                      }
                      // Horizontal slider.
                      else if (yDiff <= 5 && yDiff >= -5 && (xDiff >= 15 || xDiff <= -15)) {
                          this._mousedown(ev);
                      }
                  }
              },
              _adjustPercentageForRangeSliders: function _adjustPercentageForRangeSliders(percentage) {
                  if (this.options.range) {
                      var precision = this._getNumDigitsAfterDecimalPlace(percentage);
                      precision = precision ? precision - 1 : 0;
                      var percentageWithAdjustedPrecision = this._applyToFixedAndParseFloat(percentage, precision);
                      if (this._state.dragged === 0 && this._applyToFixedAndParseFloat(this._state.percentage[1], precision) < percentageWithAdjustedPrecision) {
                          this._state.percentage[0] = this._state.percentage[1];
                          this._state.dragged = 1;
                      } else if (this._state.dragged === 1 && this._applyToFixedAndParseFloat(this._state.percentage[0], precision) > percentageWithAdjustedPrecision) {
                          this._state.percentage[1] = this._state.percentage[0];
                          this._state.dragged = 0;
                      }
                  }
              },
              _mouseup: function _mouseup() {
                  if (!this._state.enabled) {
                      return false;
                  }
                  if (this.touchCapable) {
                      // Touch: Unbind touch event handlers:
                      document.removeEventListener("touchmove", this.mousemove, false);
                      document.removeEventListener("touchend", this.mouseup, false);
                  }
                  // Unbind mouse event handlers:
                  document.removeEventListener("mousemove", this.mousemove, false);
                  document.removeEventListener("mouseup", this.mouseup, false);
  
                  this._state.inDrag = false;
                  if (this._state.over === false) {
                      this._hideTooltip();
                  }
                  var val = this._calculateValue(true);
  
                  this._layout();
                  this._setDataVal(val);
                  this._trigger('slideStop', val);
  
                  return false;
              },
              _calculateValue: function _calculateValue(snapToClosestTick) {
                  var val;
                  if (this.options.range) {
                      val = [this.options.min, this.options.max];
                      if (this._state.percentage[0] !== 0) {
                          val[0] = this._toValue(this._state.percentage[0]);
                          val[0] = this._applyPrecision(val[0]);
                      }
                      if (this._state.percentage[1] !== 100) {
                          val[1] = this._toValue(this._state.percentage[1]);
                          val[1] = this._applyPrecision(val[1]);
                      }
                  } else {
                      val = this._toValue(this._state.percentage[0]);
                      val = parseFloat(val);
                      val = this._applyPrecision(val);
                  }
  
                  if (snapToClosestTick) {
                      var min = [val, Infinity];
                      for (var i = 0; i < this.options.ticks.length; i++) {
                          var diff = Math.abs(this.options.ticks[i] - val);
                          if (diff <= min[1]) {
                              min = [this.options.ticks[i], diff];
                          }
                      }
                      if (min[1] <= this.options.ticks_snap_bounds) {
                          return min[0];
                      }
                  }
  
                  return val;
              },
              _applyPrecision: function _applyPrecision(val) {
                  var precision = this.options.precision || this._getNumDigitsAfterDecimalPlace(this.options.step);
                  return this._applyToFixedAndParseFloat(val, precision);
              },
              _getNumDigitsAfterDecimalPlace: function _getNumDigitsAfterDecimalPlace(num) {
                  var match = ('' + num).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);
                  if (!match) {
                      return 0;
                  }
                  return Math.max(0, (match[1] ? match[1].length : 0) - (match[2] ? +match[2] : 0));
              },
              _applyToFixedAndParseFloat: function _applyToFixedAndParseFloat(num, toFixedInput) {
                  var truncatedNum = num.toFixed(toFixedInput);
                  return parseFloat(truncatedNum);
              },
              /*
               Credits to Mike Samuel for the following method!
               Source: http://stackoverflow.com/questions/10454518/javascript-how-to-retrieve-the-number-of-decimals-of-a-string-number
               */
              _getPercentage: function _getPercentage(ev) {
                  if (this.touchCapable && (ev.type === 'touchstart' || ev.type === 'touchmove')) {
                      ev = ev.touches[0];
                  }
  
                  var eventPosition = ev[this.mousePos];
                  var sliderOffset = this._state.offset[this.stylePos];
                  var distanceToSlide = eventPosition - sliderOffset;
                  // Calculate what percent of the length the slider handle has slid
                  var percentage = distanceToSlide / this._state.size * 100;
                  percentage = Math.round(percentage / this._state.percentage[2]) * this._state.percentage[2];
                  if (this.options.reversed) {
                      percentage = 100 - percentage;
                  }
  
                  // Make sure the percent is within the bounds of the slider.
                  // 0% corresponds to the 'min' value of the slide
                  // 100% corresponds to the 'max' value of the slide
                  return Math.max(0, Math.min(100, percentage));
              },
              _validateInputValue: function _validateInputValue(val) {
                  if (!isNaN(+val)) {
                      return +val;
                  } else if (Array.isArray(val)) {
                      this._validateArray(val);
                      return val;
                  } else {
                      throw new Error(ErrorMsgs.formatInvalidInputErrorMsg(val));
                  }
              },
              _validateArray: function _validateArray(val) {
                  for (var i = 0; i < val.length; i++) {
                      var input = val[i];
                      if (typeof input !== 'number') {
                          throw new Error(ErrorMsgs.formatInvalidInputErrorMsg(input));
                      }
                  }
              },
              _setDataVal: function _setDataVal(val) {
                  this.element.setAttribute('data-value', val);
                  this.element.setAttribute('value', val);
                  this.element.value = val;
              },
              _trigger: function _trigger(evt, val) {
                  val = val || val === 0 ? val : undefined;
  
                  var callbackFnArray = this.eventToCallbackMap[evt];
                  if (callbackFnArray && callbackFnArray.length) {
                      for (var i = 0; i < callbackFnArray.length; i++) {
                          var callbackFn = callbackFnArray[i];
                          callbackFn(val);
                      }
                  }
  
                  /* If JQuery exists, trigger JQuery events */
                  if ($) {
                      this._triggerJQueryEvent(evt, val);
                  }
              },
              _triggerJQueryEvent: function _triggerJQueryEvent(evt, val) {
                  var eventData = {
                      type: evt,
                      value: val
                  };
                  this.$element.trigger(eventData);
                  this.$sliderElem.trigger(eventData);
              },
              _unbindJQueryEventHandlers: function _unbindJQueryEventHandlers() {
                  this.$element.off();
                  this.$sliderElem.off();
              },
              _setText: function _setText(element, text) {
                  if (typeof element.textContent !== "undefined") {
                      element.textContent = text;
                  } else if (typeof element.innerText !== "undefined") {
                      element.innerText = text;
                  }
              },
              _removeClass: function _removeClass(element, classString) {
                  var classes = classString.split(" ");
                  var newClasses = element.className;
  
                  for (var i = 0; i < classes.length; i++) {
                      var classTag = classes[i];
                      var regex = new RegExp("(?:\\s|^)" + classTag + "(?:\\s|$)");
                      newClasses = newClasses.replace(regex, " ");
                  }
  
                  element.className = newClasses.trim();
              },
              _addClass: function _addClass(element, classString) {
                  var classes = classString.split(" ");
                  var newClasses = element.className;
  
                  for (var i = 0; i < classes.length; i++) {
                      var classTag = classes[i];
                      var regex = new RegExp("(?:\\s|^)" + classTag + "(?:\\s|$)");
                      var ifClassExists = regex.test(newClasses);
  
                      if (!ifClassExists) {
                          newClasses += " " + classTag;
                      }
                  }
  
                  element.className = newClasses.trim();
              },
              _offsetLeft: function _offsetLeft(obj) {
                  return obj.getBoundingClientRect().left;
              },
              _offsetTop: function _offsetTop(obj) {
                  var offsetTop = obj.offsetTop;
                  while ((obj = obj.offsetParent) && !isNaN(obj.offsetTop)) {
                      offsetTop += obj.offsetTop;
                      if (obj.tagName !== 'BODY') {
                          offsetTop -= obj.scrollTop;
                      }
                  }
                  return offsetTop;
              },
              _offset: function _offset(obj) {
                  return {
                      left: this._offsetLeft(obj),
                      top: this._offsetTop(obj)
                  };
              },
              _css: function _css(elementRef, styleName, value) {
                  if ($) {
                      $.style(elementRef, styleName, value);
                  } else {
                      var style = styleName.replace(/^-ms-/, "ms-").replace(/-([\da-z])/gi, function (all, letter) {
                          return letter.toUpperCase();
                      });
                      elementRef.style[style] = value;
                  }
              },
              _toValue: function _toValue(percentage) {
                  return this.options.scale.toValue.apply(this, [percentage]);
              },
              _toPercentage: function _toPercentage(value) {
                  return this.options.scale.toPercentage.apply(this, [value]);
              },
              _setTooltipPosition: function _setTooltipPosition() {
                  var tooltips = [this.tooltip, this.tooltip_min, this.tooltip_max];
                  if (this.options.orientation === 'vertical') {
                      var tooltipPos = this.options.tooltip_position || 'right';
                      var oppositeSide = tooltipPos === 'left' ? 'right' : 'left';
                      tooltips.forEach((function (tooltip) {
                          this._addClass(tooltip, tooltipPos);
                          tooltip.style[oppositeSide] = '100%';
                      }).bind(this));
                  } else if (this.options.tooltip_position === 'bottom') {
                      tooltips.forEach((function (tooltip) {
                          this._addClass(tooltip, 'bottom');
                          tooltip.style.top = 22 + 'px';
                      }).bind(this));
                  } else {
                      tooltips.forEach((function (tooltip) {
                          this._addClass(tooltip, 'top');
                          tooltip.style.top = -this.tooltip.outerHeight - 14 + 'px';
                      }).bind(this));
                  }
              }
          };
  
          /*********************************
           Attach to global namespace
           *********************************/
          if ($) {
              (function () {
                  var autoRegisterNamespace = undefined;
  
                  if (!$.fn.slider) {
                      $.bridget(NAMESPACE_MAIN, Slider);
                      autoRegisterNamespace = NAMESPACE_MAIN;
                  } else {
                      if (windowIsDefined) {
                          window.console.warn("bootstrap-slider.js - WARNING: $.fn.slider namespace is already bound. Use the $.fn.bootstrapSlider namespace instead.");
                      }
                      autoRegisterNamespace = NAMESPACE_ALTERNATE;
                  }
                  $.bridget(NAMESPACE_ALTERNATE, Slider);
  
                  // Auto-Register data-provide="slider" Elements
                  $(function () {
                      $("input[data-provide=slider]")[autoRegisterNamespace]();
                  });
              })();
          }
      })($);
  
      return Slider;
  });
  // 解决移动端click 300 毫秒延迟 (http://github.com/ftlabs/fastclick)
  $(function() {
      FastClick.attach(document.body);
  });
  
  // 图片lazy加载
  $('img.lazyload').lazyload();
  
  // tab
  $(".tab-item a").click(function (e) {
      e.preventDefault();
      $(this).tab('show');
  });
  
  // activate tabs for lazyload
  $(".tab-item a").on('shown.bs.tab', function () {
      $(window).trigger('scroll');
  });