text: /*!
    * Bootstrap v4.3.1 (https://getbootstrap.com/)
    * Copyright 2011-2019 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
    * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
    */
  (function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('jquery')) :
    typeof define === 'function' && define.amd ? define(['exports', 'jquery'], factory) :
    (global = global || self, factory(global.bootstrap = {}, global.jQuery));
  }(this, function (exports, $) { 'use strict';
  
    $ = $ && $.hasOwnProperty('default') ? $['default'] : $;
  
    function _defineProperties(target, props) {
      for (var i = 0; i < props.length; i++) {
        var descriptor = props[i];
        descriptor.enumerable = descriptor.enumerable || false;
        descriptor.configurable = true;
        if ("value" in descriptor) descriptor.writable = true;
        Object.defineProperty(target, descriptor.key, descriptor);
      }
    }
  
    function _createClass(Constructor, protoProps, staticProps) {
      if (protoProps) _defineProperties(Constructor.prototype, protoProps);
      if (staticProps) _defineProperties(Constructor, staticProps);
      return Constructor;
    }
  
    function _defineProperty(obj, key, value) {
      if (key in obj) {
        Object.defineProperty(obj, key, {
          value: value,
          enumerable: true,
          configurable: true,
          writable: true
        });
      } else {
        obj[key] = value;
      }
  
      return obj;
    }
  
    function _objectSpread(target) {
      for (var i = 1; i < arguments.length; i++) {
        var source = arguments[i] != null ? arguments[i] : {};
        var ownKeys = Object.keys(source);
  
        if (typeof Object.getOwnPropertySymbols === 'function') {
          ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) {
            return Object.getOwnPropertyDescriptor(source, sym).enumerable;
          }));
        }
  
        ownKeys.forEach(function (key) {
          _defineProperty(target, key, source[key]);
        });
      }
  
      return target;
    }
  
    function _inheritsLoose(subClass, superClass) {
      subClass.prototype = Object.create(superClass.prototype);
      subClass.prototype.constructor = subClass;
      subClass.__proto__ = superClass;
    }
  
    /**
     * --------------------------------------------------------------------------
     * Bootstrap (v4.3.1): util.js
     * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
     * --------------------------------------------------------------------------
     */
    /**
     * ------------------------------------------------------------------------
     * Private TransitionEnd Helpers
     * ------------------------------------------------------------------------
     */
  
    var TRANSITION_END = 'transitionend';
    var MAX_UID = 1000000;
    var MILLISECONDS_MULTIPLIER = 1000; // Shoutout AngusCroll (https://goo.gl/pxwQGp)
  
    function toType(obj) {
      return {}.toString.call(obj).match(/\s([a-z]+)/i)[1].toLowerCase();
    }
  
    function getSpecialTransitionEndEvent() {
      return {
        bindType: TRANSITION_END,
        delegateType: TRANSITION_END,
        handle: function handle(event) {
          if ($(event.target).is(this)) {
            return event.handleObj.handler.apply(this, arguments); // eslint-disable-line prefer-rest-params
          }
  
          return undefined; // eslint-disable-line no-undefined
        }
      };
    }
  
    function transitionEndEmulator(duration) {
      var _this = this;
  
      var called = false;
      $(this).one(Util.TRANSITION_END, function () {
        called = true;
      });
      setTimeout(function () {
        if (!called) {
          Util.triggerTransitionEnd(_this);
        }
      }, duration);
      return this;
    }
  
    function setTransitionEndSupport() {
      $.fn.emulateTransitionEnd = transitionEndEmulator;
      $.event.special[Util.TRANSITION_END] = getSpecialTransitionEndEvent();
    }
    /**
     * --------------------------------------------------------------------------
     * Public Util Api
     * --------------------------------------------------------------------------
     */
  
  
    var Util = {
      TRANSITION_END: 'bsTransitionEnd',
      getUID: function getUID(prefix) {
        do {
          // eslint-disable-next-line no-bitwise
          prefix += ~~(Math.random() * MAX_UID); // "~~" acts like a faster Math.floor() here
        } while (document.getElementById(prefix));
  
        return prefix;
      },
      getSelectorFromElement: function getSelectorFromElement(element) {
        var selector = element.getAttribute('data-target');
  
        if (!selector || selector === '#') {
          var hrefAttr = element.getAttribute('href');
          selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : '';
        }
  
        try {
          return document.querySelector(selector) ? selector : null;
        } catch (err) {
          return null;
        }
      },
      getTransitionDurationFromElement: function getTransitionDurationFromElement(element) {
        if (!element) {
          return 0;
        } // Get transition-duration of the element
  
  
        var transitionDuration = $(element).css('transition-duration');
        var transitionDelay = $(element).css('transition-delay');
        var floatTransitionDuration = parseFloat(transitionDuration);
        var floatTransitionDelay = parseFloat(transitionDelay); // Return 0 if element or transition duration is not found
  
        if (!floatTransitionDuration && !floatTransitionDelay) {
          return 0;
        } // If multiple durations are defined, take the first
  
  
        transitionDuration = transitionDuration.split(',')[0];
        transitionDelay = transitionDelay.split(',')[0];
        return (parseFloat(transitionDuration) + parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER;
      },
      reflow: function reflow(element) {
        return element.offsetHeight;
      },
      triggerTransitionEnd: function triggerTransitionEnd(element) {
        $(element).trigger(TRANSITION_END);
      },
      // TODO: Remove in v5
      supportsTransitionEnd: function supportsTransitionEnd() {
        return Boolean(TRANSITION_END);
      },
      isElement: function isElement(obj) {
        return (obj[0] || obj).nodeType;
      },
      typeCheckConfig: function typeCheckConfig(componentName, config, configTypes) {
        for (var property in configTypes) {
          if (Object.prototype.hasOwnProperty.call(configTypes, property)) {
            var expectedTypes = configTypes[property];
            var value = config[property];
            var valueType = value && Util.isElement(value) ? 'element' : toType(value);
  
            if (!new RegExp(expectedTypes).test(valueType)) {
              throw new Error(componentName.toUpperCase() + ": " + ("Option \"" + property + "\" provided type \"" + valueType + "\" ") + ("but expected type \"" + expectedTypes + "\"."));
            }
          }
        }
      },
      findShadowRoot: function findShadowRoot(element) {
        if (!document.documentElement.attachShadow) {
          return null;
        } // Can find the shadow root otherwise it'll return the document
  
  
        if (typeof element.getRootNode === 'function') {
          var root = element.getRootNode();
          return root instanceof ShadowRoot ? root : null;
        }
  
        if (element instanceof ShadowRoot) {
          return element;
        } // when we don't find a shadow root
  
  
        if (!element.parentNode) {
          return null;
        }
  
        return Util.findShadowRoot(element.parentNode);
      }
    };
    setTransitionEndSupport();
  
    /**
     * ------------------------------------------------------------------------
     * Constants
     * ------------------------------------------------------------------------
     */
  
    var NAME = 'alert';
    var VERSION = '4.3.1';
    var DATA_KEY = 'bs.alert';
    var EVENT_KEY = "." + DATA_KEY;
    var DATA_API_KEY = '.data-api';
    var JQUERY_NO_CONFLICT = $.fn[NAME];
    var Selector = {
      DISMISS: '[data-dismiss="alert"]'
    };
    var Event = {
      CLOSE: "close" + EVENT_KEY,
      CLOSED: "closed" + EVENT_KEY,
      CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY
    };
    var ClassName = {
      ALERT: 'alert',
      FADE: 'fade',
      SHOW: 'show'
      /**
       * ------------------------------------------------------------------------
       * Class Definition
       * ------------------------------------------------------------------------
       */
  
    };
  
    var Alert =
    /*#__PURE__*/
    function () {
      function Alert(element) {
        this._element = element;
      } // Getters
  
  
      var _proto = Alert.prototype;
  
      // Public
      _proto.close = function close(element) {
        var rootElement = this._element;
  
        if (element) {
          rootElement = this._getRootElement(element);
        }
  
        var customEvent = this._triggerCloseEvent(rootElement);
  
        if (customEvent.isDefaultPrevented()) {
          return;
        }
  
        this._removeElement(rootElement);
      };
  
      _proto.dispose = function dispose() {
        $.removeData(this._element, DATA_KEY);
        this._element = null;
      } // Private
      ;
  
      _proto._getRootElement = function _getRootElement(element) {
        var selector = Util.getSelectorFromElement(element);
        var parent = false;
  
        if (selector) {
          parent = document.querySelector(selector);
        }
  
        if (!parent) {
          parent = $(element).closest("." + ClassName.ALERT)[0];
        }
  
        return parent;
      };
  
      _proto._triggerCloseEvent = function _triggerCloseEvent(element) {
        var closeEvent = $.Event(Event.CLOSE);
        $(element).trigger(closeEvent);
        return closeEvent;
      };
  
      _proto._removeElement = function _removeElement(element) {
        var _this = this;
  
        $(element).removeClass(ClassName.SHOW);
  
        if (!$(element).hasClass(ClassName.FADE)) {
          this._destroyElement(element);
  
          return;
        }
  
        var transitionDuration = Util.getTransitionDurationFromElement(element);
        $(element).one(Util.TRANSITION_END, function (event) {
          return _this._destroyElement(element, event);
        }).emulateTransitionEnd(transitionDuration);
      };
  
      _proto._destroyElement = function _destroyElement(element) {
        $(element).detach().trigger(Event.CLOSED).remove();
      } // Static
      ;
  
      Alert._jQueryInterface = function _jQueryInterface(config) {
        return this.each(function () {
          var $element = $(this);
          var data = $element.data(DATA_KEY);
  
          if (!data) {
            data = new Alert(this);
            $element.data(DATA_KEY, data);
          }
  
          if (config === 'close') {
            data[config](this);
          }
        });
      };
  
      Alert._handleDismiss = function _handleDismiss(alertInstance) {
        return function (event) {
          if (event) {
            event.preventDefault();
          }
  
          alertInstance.close(this);
        };
      };
  
      _createClass(Alert, null, [{
        key: "VERSION",
        get: function get() {
          return VERSION;
        }
      }]);
  
      return Alert;
    }();
    /**
     * ------------------------------------------------------------------------
     * Data Api implementation
     * ------------------------------------------------------------------------
     */
  
  
    $(document).on(Event.CLICK_DATA_API, Selector.DISMISS, Alert._handleDismiss(new Alert()));
    /**
     * ------------------------------------------------------------------------
     * jQuery
     * ------------------------------------------------------------------------
     */
  
    $.fn[NAME] = Alert._jQueryInterface;
    $.fn[NAME].Constructor = Alert;
  
    $.fn[NAME].noConflict = function () {
      $.fn[NAME] = JQUERY_NO_CONFLICT;
      return Alert._jQueryInterface;
    };
  
    /**
     * ------------------------------------------------------------------------
     * Constants
     * ------------------------------------------------------------------------
     */
  
    var NAME$1 = 'button';
    var VERSION$1 = '4.3.1';
    var DATA_KEY$1 = 'bs.button';
    var EVENT_KEY$1 = "." + DATA_KEY$1;
    var DATA_API_KEY$1 = '.data-api';
    var JQUERY_NO_CONFLICT$1 = $.fn[NAME$1];
    var ClassName$1 = {
      ACTIVE: 'active',
      BUTTON: 'btn',
      FOCUS: 'focus'
    };
    var Selector$1 = {
      DATA_TOGGLE_CARROT: '[data-toggle^="button"]',
      DATA_TOGGLE: '[data-toggle="buttons"]',
      INPUT: 'input:not([type="hidden"])',
      ACTIVE: '.active',
      BUTTON: '.btn'
    };
    var Event$1 = {
      CLICK_DATA_API: "click" + EVENT_KEY$1 + DATA_API_KEY$1,
      FOCUS_BLUR_DATA_API: "focus" + EVENT_KEY$1 + DATA_API_KEY$1 + " " + ("blur" + EVENT_KEY$1 + DATA_API_KEY$1)
      /**
       * ------------------------------------------------------------------------
       * Class Definition
       * ------------------------------------------------------------------------
       */
  
    };
  
    var Button =
    /*#__PURE__*/
    function () {
      function Button(element) {
        this._element = element;
      } // Getters
  
  
      var _proto = Button.prototype;
  
      // Public
      _proto.toggle = function toggle() {
        var triggerChangeEvent = true;
        var addAriaPressed = true;
        var rootElement = $(this._element).closest(Selector$1.DATA_TOGGLE)[0];
  
        if (rootElement) {
          var input = this._element.querySelector(Selector$1.INPUT);
  
          if (input) {
            if (input.type === 'radio') {
              if (input.checked && this._element.classList.contains(ClassName$1.ACTIVE)) {
                triggerChangeEvent = false;
              } else {
                var activeElement = rootElement.querySelector(Selector$1.ACTIVE);
  
                if (activeElement) {
                  $(activeElement).removeClass(ClassName$1.ACTIVE);
                }
              }
            }
  
            if (triggerChangeEvent) {
              if (input.hasAttribute('disabled') || rootElement.hasAttribute('disabled') || input.classList.contains('disabled') || rootElement.classList.contains('disabled')) {
                return;
              }
  
              input.checked = !this._element.classList.contains(ClassName$1.ACTIVE);
              $(input).trigger('change');
            }
  
            input.focus();
            addAriaPressed = false;
          }
        }
  
        if (addAriaPressed) {
          this._element.setAttribute('aria-pressed', !this._element.classList.contains(ClassName$1.ACTIVE));
        }
  
        if (triggerChangeEvent) {
          $(this._element).toggleClass(ClassName$1.ACTIVE);
        }
      };
  
      _proto.dispose = function dispose() {
        $.removeData(this._element, DATA_KEY$1);
        this._element = null;
      } // Static
      ;
  
      Button._jQueryInterface = function _jQueryInterface(config) {
        return this.each(function () {
          var data = $(this).data(DATA_KEY$1);
  
          if (!data) {
            data = new Button(this);
            $(this).data(DATA_KEY$1, data);
          }
  
          if (config === 'toggle') {
            data[config]();
          }
        });
      };
  
      _createClass(Button, null, [{
        key: "VERSION",
        get: function get() {
          return VERSION$1;
        }
      }]);
  
      return Button;
    }();
    /**
     * ------------------------------------------------------------------------
     * Data Api implementation
     * ------------------------------------------------------------------------
     */
  
  
    $(document).on(Event$1.CLICK_DATA_API, Selector$1.DATA_TOGGLE_CARROT, function (event) {
      event.preventDefault();
      var button = event.target;
  
      if (!$(button).hasClass(ClassName$1.BUTTON)) {
        button = $(button).closest(Selector$1.BUTTON);
      }
  
      Button._jQueryInterface.call($(button), 'toggle');
    }).on(Event$1.FOCUS_BLUR_DATA_API, Selector$1.DATA_TOGGLE_CARROT, function (event) {
      var button = $(event.target).closest(Selector$1.BUTTON)[0];
      $(button).toggleClass(ClassName$1.FOCUS, /^focus(in)?$/.test(event.type));
    });
    /**
     * ------------------------------------------------------------------------
     * jQuery
     * ------------------------------------------------------------------------
     */
  
    $.fn[NAME$1] = Button._jQueryInterface;
    $.fn[NAME$1].Constructor = Button;
  
    $.fn[NAME$1].noConflict = function () {
      $.fn[NAME$1] = JQUERY_NO_CONFLICT$1;
      return Button._jQueryInterface;
    };
  
    /**
     * ------------------------------------------------------------------------
     * Constants
     * ------------------------------------------------------------------------
     */
  
    var NAME$2 = 'carousel';
    var VERSION$2 = '4.3.1';
    var DATA_KEY$2 = 'bs.carousel';
    var EVENT_KEY$2 = "." + DATA_KEY$2;
    var DATA_API_KEY$2 = '.data-api';
    var JQUERY_NO_CONFLICT$2 = $.fn[NAME$2];
    var ARROW_LEFT_KEYCODE = 37; // KeyboardEvent.which value for left arrow key
  
    var ARROW_RIGHT_KEYCODE = 39; // KeyboardEvent.which value for right arrow key
  
    var TOUCHEVENT_COMPAT_WAIT = 500; // Time for mouse compat events to fire after touch
  
    var SWIPE_THRESHOLD = 40;
    var Default = {
      interval: 5000,
      keyboard: true,
      slide: false,
      pause: 'hover',
      wrap: true,
      touch: true
    };
    var DefaultType = {
      interval: '(number|boolean)',
      keyboard: 'boolean',
      slide: '(boolean|string)',
      pause: '(string|boolean)',
      wrap: 'boolean',
      touch: 'boolean'
    };
    var Direction = {
      NEXT: 'next',
      PREV: 'prev',
      LEFT: 'left',
      RIGHT: 'right'
    };
    var Event$2 = {
      SLIDE: "slide" + EVENT_KEY$2,
      SLID: "slid" + EVENT_KEY$2,
      KEYDOWN: "keydown" + EVENT_KEY$2,
      MOUSEENTER: "mouseenter" + EVENT_KEY$2,
      MOUSELEAVE: "mouseleave" + EVENT_KEY$2,
      TOUCHSTART: "touchstart" + EVENT_KEY$2,
      TOUCHMOVE: "touchmove" + EVENT_KEY$2,
      TOUCHEND: "touchend" + EVENT_KEY$2,
      POINTERDOWN: "pointerdown" + EVENT_KEY$2,
      POINTERUP: "pointerup" + EVENT_KEY$2,
      DRAG_START: "dragstart" + EVENT_KEY$2,
      LOAD_DATA_API: "load" + EVENT_KEY$2 + DATA_API_KEY$2,
      CLICK_DATA_API: "click" + EVENT_KEY$2 + DATA_API_KEY$2
    };
    var ClassName$2 = {
      CAROUSEL: 'carousel',
      ACTIVE: 'active',
      SLIDE: 'slide',
      RIGHT: 'carousel-item-right',
      LEFT: 'carousel-item-left',
      NEXT: 'carousel-item-next',
      PREV: 'carousel-item-prev',
      ITEM: 'carousel-item',
      POINTER_EVENT: 'pointer-event'
    };
    var Selector$2 = {
      ACTIVE: '.active',
      ACTIVE_ITEM: '.active.carousel-item',
      ITEM: '.carousel-item',
      ITEM_IMG: '.carousel-item img',
      NEXT_PREV: '.carousel-item-next, .carousel-item-prev',
      INDICATORS: '.carousel-indicators',
      DATA_SLIDE: '[data-slide], [data-slide-to]',
      DATA_RIDE: '[data-ride="carousel"]'
    };
    var PointerType = {
      TOUCH: 'touch',
      PEN: 'pen'
      /**
       * ------------------------------------------------------------------------
       * Class Definition
       * ------------------------------------------------------------------------
       */
  
    };
  
    var Carousel =
    /*#__PURE__*/
    function () {
      function Carousel(element, config) {
        this._items = null;
        this._interval = null;
        this._activeElement = null;
        this._isPaused = false;
        this._isSliding = false;
        this.touchTimeout = null;
        this.touchStartX = 0;
        this.touchDeltaX = 0;
        this._config = this._getConfig(config);
        this._element = element;
        this._indicatorsElement = this._element.querySelector(Selector$2.INDICATORS);
        this._touchSupported = 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0;
        this._pointerEvent = Boolean(window.PointerEvent || window.MSPointerEvent);
  
        this._addEventListeners();
      } // Getters
  
  
      var _proto = Carousel.prototype;
  
      // Public
      _proto.next = function next() {
        if (!this._isSliding) {
          this._slide(Direction.NEXT);
        }
      };
  
      _proto.nextWhenVisible = function nextWhenVisible() {
        // Don't call next when the page isn't visible
        // or the carousel or its parent isn't visible
        if (!document.hidden && $(this._element).is(':visible') && $(this._element).css('visibility') !== 'hidden') {
          this.next();
        }
      };
  
      _proto.prev = function prev() {
        if (!this._isSliding) {
          this._slide(Direction.PREV);
        }
      };
  
      _proto.pause = function pause(event) {
        if (!event) {
          this._isPaused = true;
        }
  
        if (this._element.querySelector(Selector$2.NEXT_PREV)) {
          Util.triggerTransitionEnd(this._element);
          this.cycle(true);
        }
  
        clearInterval(this._interval);
        this._interval = null;
      };
  
      _proto.cycle = function cycle(event) {
        if (!event) {
          this._isPaused = false;
        }
  
        if (this._interval) {
          clearInterval(this._interval);
          this._interval = null;
        }
  
        if (this._config.interval && !this._isPaused) {
          this._interval = setInterval((document.visibilityState ? this.nextWhenVisible : this.next).bind(this), this._config.interval);
        }
      };
  
      _proto.to = function to(index) {
        var _this = this;
  
        this._activeElement = this._element.querySelector(Selector$2.ACTIVE_ITEM);
  
        var activeIndex = this._getItemIndex(this._activeElement);
  
        if (index > this._items.length - 1 || index < 0) {
          return;
        }
  
        if (this._isSliding) {
          $(this._element).one(Event$2.SLID, function () {
            return _this.to(index);
          });
          return;
        }
  
        if (activeIndex === index) {
          this.pause();
          this.cycle();
          return;
        }
  
        var direction = index > activeIndex ? Direction.NEXT : Direction.PREV;
  
        this._slide(direction, this._items[index]);
      };
  
      _proto.dispose = function dispose() {
        $(this._element).off(EVENT_KEY$2);
        $.removeData(this._element, DATA_KEY$2);
        this._items = null;
        this._config = null;
        this._element = null;
        this._interval = null;
        this._isPaused = null;
        this._isSliding = null;
        this._activeElement = null;
        this._indicatorsElement = null;
      } // Private
      ;
  
      _proto._getConfig = function _getConfig(config) {
        config = _objectSpread({}, Default, config);
        Util.typeCheckConfig(NAME$2, config, DefaultType);
        return config;
      };
  
      _proto._handleSwipe = function _handleSwipe() {
        var absDeltax = Math.abs(this.touchDeltaX);
  
        if (absDeltax <= SWIPE_THRESHOLD) {
          return;
        }
  
        var direction = absDeltax / this.touchDeltaX; // swipe left
  
        if (direction > 0) {
          this.prev();
        } // swipe right
  
  
        if (direction < 0) {
          this.next();
        }
      };
  
      _proto._addEventListeners = function _addEventListeners() {
        var _this2 = this;
  
        if (this._config.keyboard) {
          $(this._element).on(Event$2.KEYDOWN, function (event) {
            return _this2._keydown(event);
          });
        }
  
        if (this._config.pause === 'hover') {
          $(this._element).on(Event$2.MOUSEENTER, function (event) {
            return _this2.pause(event);
          }).on(Event$2.MOUSELEAVE, function (event) {
            return _this2.cycle(event);
          });
        }
  
        if (this._config.touch) {
          this._addTouchEventListeners();
        }
      };
  
      _proto._addTouchEventListeners = function _addTouchEventListeners() {
        var _this3 = this;
  
        if (!this._touchSupported) {
          return;
        }
  
        var start = function start(event) {
          if (_this3._pointerEvent && PointerType[event.originalEvent.pointerType.toUpperCase()]) {
            _this3.touchStartX = event.originalEvent.clientX;
          } else if (!_this3._pointerEvent) {
            _this3.touchStartX = event.originalEvent.touches[0].clientX;
          }
        };
  
        var move = function move(event) {
          // ensure swiping with one touch and not pinching
          if (event.originalEvent.touches && event.originalEvent.touches.length > 1) {
            _this3.touchDeltaX = 0;
          } else {
            _this3.touchDeltaX = event.originalEvent.touches[0].clientX - _this3.touchStartX;
          }
        };
  
        var end = function end(event) {
          if (_this3._pointerEvent && PointerType[event.originalEvent.pointerType.toUpperCase()]) {
            _this3.touchDeltaX = event.originalEvent.clientX - _this3.touchStartX;
          }
  
          _this3._handleSwipe();
  
          if (_this3._config.pause === 'hover') {
            // If it's a touch-enabled device, mouseenter/leave are fired as
            // part of the mouse compatibility events on first tap - the carousel
            // would stop cycling until user tapped out of it;
            // here, we listen for touchend, explicitly pause the carousel
            // (as if it's the second time we tap on it, mouseenter compat event
            // is NOT fired) and after a timeout (to allow for mouse compatibility
            // events to fire) we explicitly restart cycling
            _this3.pause();
  
            if (_this3.touchTimeout) {
              clearTimeout(_this3.touchTimeout);
            }
  
            _this3.touchTimeout = setTimeout(function (event) {
              return _this3.cycle(event);
            }, TOUCHEVENT_COMPAT_WAIT + _this3._config.interval);
          }
        };
  
        $(this._element.querySelectorAll(Selector$2.ITEM_IMG)).on(Event$2.DRAG_START, function (e) {
          return e.preventDefault();
        });
  
        if (this._pointerEvent) {
          $(this._element).on(Event$2.POINTERDOWN, function (event) {
            return start(event);
          });
          $(this._element).on(Event$2.POINTERUP, function (event) {
            return end(event);
          });
  
          this._element.classList.add(ClassName$2.POINTER_EVENT);
        } else {
          $(this._element).on(Event$2.TOUCHSTART, function (event) {
            return start(event);
          });
          $(this._element).on(Event$2.TOUCHMOVE, function (event) {
            return move(event);
          });
          $(this._element).on(Event$2.TOUCHEND, function (event) {
            return end(event);
          });
        }
      };
  
      _proto._keydown = function _keydown(event) {
        if (/input|textarea/i.test(event.target.tagName)) {
          return;
        }
  
        switch (event.which) {
          case ARROW_LEFT_KEYCODE:
            event.preventDefault();
            this.prev();
            break;
  
          case ARROW_RIGHT_KEYCODE:
            event.preventDefault();
            this.next();
            break;
  
          default:
        }
      };
  
      _proto._getItemIndex = function _getItemIndex(element) {
        this._items = element && element.parentNode ? [].slice.call(element.parentNode.querySelectorAll(Selector$2.ITEM)) : [];
        return this._items.indexOf(element);
      };
  
      _proto._getItemByDirection = function _getItemByDirection(direction, activeElement) {
        var isNextDirection = direction === Direction.NEXT;
        var isPrevDirection = direction === Direction.PREV;
  
        var activeIndex = this._getItemIndex(activeElement);
  
        var lastItemIndex = this._items.length - 1;
        var isGoingToWrap = isPrevDirection && activeIndex === 0 || isNextDirection && activeIndex === lastItemIndex;
  
        if (isGoingToWrap && !this._config.wrap) {
          return activeElement;
        }
  
        var delta = direction === Direction.PREV ? -1 : 1;
        var itemIndex = (activeIndex + delta) % this._items.length;
        return itemIndex === -1 ? this._items[this._items.length - 1] : this._items[itemIndex];
      };
  
      _proto._triggerSlideEvent = function _triggerSlideEvent(relatedTarget, eventDirectionName) {
        var targetIndex = this._getItemIndex(relatedTarget);
  
        var fromIndex = this._getItemIndex(this._element.querySelector(Selector$2.ACTIVE_ITEM));
  
        var slideEvent = $.Event(Event$2.SLIDE, {
          relatedTarget: relatedTarget,
          direction: eventDirectionName,
          from: fromIndex,
          to: targetIndex
        });
        $(this._element).trigger(slideEvent);
        return slideEvent;
      };
  
      _proto._setActiveIndicatorElement = function _setActiveIndicatorElement(element) {
        if (this._indicatorsElement) {
          var indicators = [].slice.call(this._indicatorsElement.querySelectorAll(Selector$2.ACTIVE));
          $(indicators).removeClass(ClassName$2.ACTIVE);
  
          var nextIndicator = this._indicatorsElement.children[this._getItemIndex(element)];
  
          if (nextIndicator) {
            $(nextIndicator).addClass(ClassName$2.ACTIVE);
          }
        }
      };
  
      _proto._slide = function _slide(direction, element) {
        var _this4 = this;
  
        var activeElement = this._element.querySelector(Selector$2.ACTIVE_ITEM);
  
        var activeElementIndex = this._getItemIndex(activeElement);
  
        var nextElement = element || activeElement && this._getItemByDirection(direction, activeElement);
  
        var nextElementIndex = this._getItemIndex(nextElement);
  
        var isCycling = Boolean(this._interval);
        var directionalClassName;
        var orderClassName;
        var eventDirectionName;
  
        if (direction === Direction.NEXT) {
          directionalClassName = ClassName$2.LEFT;
          orderClassName = ClassName$2.NEXT;
          eventDirectionName = Direction.LEFT;
        } else {
          directionalClassName = ClassName$2.RIGHT;
          orderClassName = ClassName$2.PREV;
          eventDirectionName = Direction.RIGHT;
        }
  
        if (nextElement && $(nextElement).hasClass(ClassName$2.ACTIVE)) {
          this._isSliding = false;
          return;
        }
  
        var slideEvent = this._triggerSlideEvent(nextElement, eventDirectionName);
  
        if (slideEvent.isDefaultPrevented()) {
          return;
        }
  
        if (!activeElement || !nextElement) {
          // Some weirdness is happening, so we bail
          return;
        }
  
        this._isSliding = true;
  
        if (isCycling) {
          this.pause();
        }
  
        this._setActiveIndicatorElement(nextElement);
  
        var slidEvent = $.Event(Event$2.SLID, {
          relatedTarget: nextElement,
          direction: eventDirectionName,
          from: activeElementIndex,
          to: nextElementIndex
        });
  
        if ($(this._element).hasClass(ClassName$2.SLIDE)) {
          $(nextElement).addClass(orderClassName);
          Util.reflow(nextElement);
          $(activeElement).addClass(directionalClassName);
          $(nextElement).addClass(directionalClassName);
          var nextElementInterval = parseInt(nextElement.getAttribute('data-interval'), 10);
  
          if (nextElementInterval) {
            this._config.defaultInterval = this._config.defaultInterval || this._config.interval;
            this._config.interval = nextElementInterval;
          } else {
            this._config.interval = this._config.defaultInterval || this._config.interval;
          }
  
          var transitionDuration = Util.getTransitionDurationFromElement(activeElement);
          $(activeElement).one(Util.TRANSITION_END, function () {
            $(nextElement).removeClass(directionalClassName + " " + orderClassName).addClass(ClassName$2.ACTIVE);
            $(activeElement).removeClass(ClassName$2.ACTIVE + " " + orderClassName + " " + directionalClassName);
            _this4._isSliding = false;
            setTimeout(function () {
              return $(_this4._element).trigger(slidEvent);
            }, 0);
          }).emulateTransitionEnd(transitionDuration);
        } else {
          $(activeElement).removeClass(ClassName$2.ACTIVE);
          $(nextElement).addClass(ClassName$2.ACTIVE);
          this._isSliding = false;
          $(this._element).trigger(slidEvent);
        }
  
        if (isCycling) {
          this.cycle();
        }
      } // Static
      ;
  
      Carousel._jQueryInterface = function _jQueryInterface(config) {
        return this.each(function () {
          var data = $(this).data(DATA_KEY$2);
  
          var _config = _objectSpread({}, Default, $(this).data());
  
          if (typeof config === 'object') {
            _config = _objectSpread({}, _config, config);
          }
  
          var action = typeof config === 'string' ? config : _config.slide;
  
          if (!data) {
            data = new Carousel(this, _config);
            $(this).data(DATA_KEY$2, data);
          }
  
          if (typeof config === 'number') {
            data.to(config);
          } else if (typeof action === 'string') {
            if (typeof data[action] === 'undefined') {
              throw new TypeError("No method named \"" + action + "\"");
            }
  
            data[action]();
          } else if (_config.interval && _config.ride) {
            data.pause();
            data.cycle();
          }
        });
      };
  
      Carousel._dataApiClickHandler = function _dataApiClickHandler(event) {
        var selector = Util.getSelectorFromElement(this);
  
        if (!selector) {
          return;
        }
  
        var target = $(selector)[0];
  
        if (!target || !$(target).hasClass(ClassName$2.CAROUSEL)) {
          return;
        }
  
        var config = _objectSpread({}, $(target).data(), $(this).data());
  
        var slideIndex = this.getAttribute('data-slide-to');
  
        if (slideIndex) {
          config.interval = false;
        }
  
        Carousel._jQueryInterface.call($(target), config);
  
        if (slideIndex) {
          $(target).data(DATA_KEY$2).to(slideIndex);
        }
  
        event.preventDefault();
      };
  
      _createClass(Carousel, null, [{
        key: "VERSION",
        get: function get() {
          return VERSION$2;
        }
      }, {
        key: "Default",
        get: function get() {
          return Default;
        }
      }]);
  
      return Carousel;
    }();
    /**
     * ------------------------------------------------------------------------
     * Data Api implementation
     * ------------------------------------------------------------------------
     */
  
  
    $(document).on(Event$2.CLICK_DATA_API, Selector$2.DATA_SLIDE, Carousel._dataApiClickHandler);
    $(window).on(Event$2.LOAD_DATA_API, function () {
      var carousels = [].slice.call(document.querySelectorAll(Selector$2.DATA_RIDE));
  
      for (var i = 0, len = carousels.length; i < len; i++) {
        var $carousel = $(carousels[i]);
  
        Carousel._jQueryInterface.call($carousel, $carousel.data());
      }
    });
    /**
     * ------------------------------------------------------------------------
     * jQuery
     * ------------------------------------------------------------------------
     */
  
    $.fn[NAME$2] = Carousel._jQueryInterface;
    $.fn[NAME$2].Constructor = Carousel;
  
    $.fn[NAME$2].noConflict = function () {
      $.fn[NAME$2] = JQUERY_NO_CONFLICT$2;
      return Carousel._jQueryInterface;
    };
  
    /**
     * ------------------------------------------------------------------------
     * Constants
     * ------------------------------------------------------------------------
     */
  
    var NAME$3 = 'collapse';
    var VERSION$3 = '4.3.1';
    var DATA_KEY$3 = 'bs.collapse';
    var EVENT_KEY$3 = "." + DATA_KEY$3;
    var DATA_API_KEY$3 = '.data-api';
    var JQUERY_NO_CONFLICT$3 = $.fn[NAME$3];
    var Default$1 = {
      toggle: true,
      parent: ''
    };
    var DefaultType$1 = {
      toggle: 'boolean',
      parent: '(string|element)'
    };
    var Event$3 = {
      SHOW: "show" + EVENT_KEY$3,
      SHOWN: "shown" + EVENT_KEY$3,
      HIDE: "hide" + EVENT_KEY$3,
      HIDDEN: "hidden" + EVENT_KEY$3,
      CLICK_DATA_API: "click" + EVENT_KEY$3 + DATA_API_KEY$3
    };
    var ClassName$3 = {
      SHOW: 'show',
      COLLAPSE: 'collapse',
      COLLAPSING: 'collapsing',
      COLLAPSED: 'collapsed'
    };
    var Dimension = {
      WIDTH: 'width',
      HEIGHT: 'height'
    };
    var Selector$3 = {
      ACTIVES: '.show, .collapsing',
      DATA_TOGGLE: '[data-toggle="collapse"]'
      /**
       * ------------------------------------------------------------------------
       * Class Definition
       * ------------------------------------------------------------------------
       */
  
    };
  
    var Collapse =
    /*#__PURE__*/
    function () {
      function Collapse(element, config) {
        this._isTransitioning = false;
        this._element = element;
        this._config = this._getConfig(config);
        this._triggerArray = [].slice.call(document.querySelectorAll("[data-toggle=\"collapse\"][href=\"#" + element.id + "\"]," + ("[data-toggle=\"collapse\"][data-target=\"#" + element.id + "\"]")));
        var toggleList = [].slice.call(document.querySelectorAll(Selector$3.DATA_TOGGLE));
  
        for (var i = 0, len = toggleList.length; i < len; i++) {
          var elem = toggleList[i];
          var selector = Util.getSelectorFromElement(elem);
          var filterElement = [].slice.call(document.querySelectorAll(selector)).filter(function (foundElem) {
            return foundElem === element;
          });
  
          if (selector !== null && filterElement.length > 0) {
            this._selector = selector;
  
            this._triggerArray.push(elem);
          }
        }
  
        this._parent = this._config.parent ? this._getParent() : null;
  
        if (!this._config.parent) {
          this._addAriaAndCollapsedClass(this._element, this._triggerArray);
        }
  
        if (this._config.toggle) {
          this.toggle();
        }
      } // Getters
  
  
      var _proto = Collapse.prototype;
  
      // Public
      _proto.toggle = function toggle() {
        if ($(this._element).hasClass(ClassName$3.SHOW)) {
          this.hide();
        } else {
          this.show();
        }
      };
  
      _proto.show = function show() {
        var _this = this;
  
        if (this._isTransitioning || $(this._element).hasClass(ClassName$3.SHOW)) {
          return;
        }
  
        var actives;
        var activesData;
  
        if (this._parent) {
          actives = [].slice.call(this._parent.querySelectorAll(Selector$3.ACTIVES)).filter(function (elem) {
            if (typeof _this._config.parent === 'string') {
              return elem.getAttribute('data-parent') === _this._config.parent;
            }
  
            return elem.classList.contains(ClassName$3.COLLAPSE);
          });
  
          if (actives.length === 0) {
            actives = null;
          }
        }
  
        if (actives) {
          activesData = $(actives).not(this._selector).data(DATA_KEY$3);
  
          if (activesData && activesData._isTransitioning) {
            return;
          }
        }
  
        var startEvent = $.Event(Event$3.SHOW);
        $(this._element).trigger(startEvent);
  
        if (startEvent.isDefaultPrevented()) {
          return;
        }
  
        if (actives) {
          Collapse._jQueryInterface.call($(actives).not(this._selector), 'hide');
  
          if (!activesData) {
            $(actives).data(DATA_KEY$3, null);
          }
        }
  
        var dimension = this._getDimension();
  
        $(this._element).removeClass(ClassName$3.COLLAPSE).addClass(ClassName$3.COLLAPSING);
        this._element.style[dimension] = 0;
  
        if (this._triggerArray.length) {
          $(this._triggerArray).removeClass(ClassName$3.COLLAPSED).attr('aria-expanded', true);
        }
  
        this.setTransitioning(true);
  
        var complete = function complete() {
          $(_this._element).removeClass(ClassName$3.COLLAPSING).addClass(ClassName$3.COLLAPSE).addClass(ClassName$3.SHOW);
          _this._element.style[dimension] = '';
  
          _this.setTransitioning(false);
  
          $(_this._element).trigger(Event$3.SHOWN);
        };
  
        var capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1);
        var scrollSize = "scroll" + capitalizedDimension;
        var transitionDuration = Util.getTransitionDurationFromElement(this._element);
        $(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);
        this._element.style[dimension] = this._element[scrollSize] + "px";
      };
  
      _proto.hide = function hide() {
        var _this2 = this;
  
        if (this._isTransitioning || !$(this._element).hasClass(ClassName$3.SHOW)) {
          return;
        }
  
        var startEvent = $.Event(Event$3.HIDE);
        $(this._element).trigger(startEvent);
  
        if (startEvent.isDefaultPrevented()) {
          return;
        }
  
        var dimension = this._getDimension();
  
        this._element.style[dimension] = this._element.getBoundingClientRect()[dimension] + "px";
        Util.reflow(this._element);
        $(this._element).addClass(ClassName$3.COLLAPSING).removeClass(ClassName$3.COLLAPSE).removeClass(ClassName$3.SHOW);
        var triggerArrayLength = this._triggerArray.length;
  
        if (triggerArrayLength > 0) {
          for (var i = 0; i < triggerArrayLength; i++) {
            var trigger = this._triggerArray[i];
            var selector = Util.getSelectorFromElement(trigger);
  
            if (selector !== null) {
              var $elem = $([].slice.call(document.querySelectorAll(selector)));
  
              if (!$elem.hasClass(ClassName$3.SHOW)) {
                $(trigger).addClass(ClassName$3.COLLAPSED).attr('aria-expanded', false);
              }
            }
          }
        }
  
        this.setTransitioning(true);
  
        var complete = function complete() {
          _this2.setTransitioning(false);
  
          $(_this2._element).removeClass(ClassName$3.COLLAPSING).addClass(ClassName$3.COLLAPSE).trigger(Event$3.HIDDEN);
        };
  
        this._element.style[dimension] = '';
        var transitionDuration = Util.getTransitionDurationFromElement(this._element);
        $(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);
      };
  
      _proto.setTransitioning = function setTransitioning(isTransitioning) {
        this._isTransitioning = isTransitioning;
      };
  
      _proto.dispose = function dispose() {
        $.removeData(this._element, DATA_KEY$3);
        this._config = null;
        this._parent = null;
        this._element = null;
        this._triggerArray = null;
        this._isTransitioning = null;
      } // Private
      ;
  
      _proto._getConfig = function _getConfig(config) {
        config = _objectSpread({}, Default$1, config);
        config.toggle = Boolean(config.toggle); // Coerce string values
  
        Util.typeCheckConfig(NAME$3, config, DefaultType$1);
        return config;
      };
  
      _proto._getDimension = function _getDimension() {
        var hasWidth = $(this._element).hasClass(Dimension.WIDTH);
        return hasWidth ? Dimension.WIDTH : Dimension.HEIGHT;
      };
  
      _proto._getParent = function _getParent() {
        var _this3 = this;
  
        var parent;
  
        if (Util.isElement(this._config.parent)) {
          parent = this._config.parent; // It's a jQuery object
  
          if (typeof this._config.parent.jquery !== 'undefined') {
            parent = this._config.parent[0];
          }
        } else {
          parent = document.querySelector(this._config.parent);
        }
  
        var selector = "[data-toggle=\"collapse\"][data-parent=\"" + this._config.parent + "\"]";
        var children = [].slice.call(parent.querySelectorAll(selector));
        $(children).each(function (i, element) {
          _this3._addAriaAndCollapsedClass(Collapse._getTargetFromElement(element), [element]);
        });
        return parent;
      };
  
      _proto._addAriaAndCollapsedClass = function _addAriaAndCollapsedClass(element, triggerArray) {
        var isOpen = $(element).hasClass(ClassName$3.SHOW);
  
        if (triggerArray.length) {
          $(triggerArray).toggleClass(ClassName$3.COLLAPSED, !isOpen).attr('aria-expanded', isOpen);
        }
      } // Static
      ;
  
      Collapse._getTargetFromElement = function _getTargetFromElement(element) {
        var selector = Util.getSelectorFromElement(element);
        return selector ? document.querySelector(selector) : null;
      };
  
      Collapse._jQueryInterface = function _jQueryInterface(config) {
        return this.each(function () {
          var $this = $(this);
          var data = $this.data(DATA_KEY$3);
  
          var _config = _objectSpread({}, Default$1, $this.data(), typeof config === 'object' && config ? config : {});
  
          if (!data && _config.toggle && /show|hide/.test(config)) {
            _config.toggle = false;
          }
  
          if (!data) {
            data = new Collapse(this, _config);
            $this.data(DATA_KEY$3, data);
          }
  
          if (typeof config === 'string') {
            if (typeof data[config] === 'undefined') {
              throw new TypeError("No method named \"" + config + "\"");
            }
  
            data[config]();
          }
        });
      };
  
      _createClass(Collapse, null, [{
        key: "VERSION",
        get: function get() {
          return VERSION$3;
        }
      }, {
        key: "Default",
        get: function get() {
          return Default$1;
        }
      }]);
  
      return Collapse;
    }();
    /**
     * ------------------------------------------------------------------------
     * Data Api implementation
     * ------------------------------------------------------------------------
     */
  
  
    $(document).on(Event$3.CLICK_DATA_API, Selector$3.DATA_TOGGLE, function (event) {
      // preventDefault only for <a> elements (which change the URL) not inside the collapsible element
      if (event.currentTarget.tagName === 'A') {
        event.preventDefault();
      }
  
      var $trigger = $(this);
      var selector = Util.getSelectorFromElement(this);
      var selectors = [].slice.call(document.querySelectorAll(selector));
      $(selectors).each(function () {
        var $target = $(this);
        var data = $target.data(DATA_KEY$3);
        var config = data ? 'toggle' : $trigger.data();
  
        Collapse._jQueryInterface.call($target, config);
      });
    });
    /**
     * ------------------------------------------------------------------------
     * jQuery
     * ------------------------------------------------------------------------
     */
  
    $.fn[NAME$3] = Collapse._jQueryInterface;
    $.fn[NAME$3].Constructor = Collapse;
  
    $.fn[NAME$3].noConflict = function () {
      $.fn[NAME$3] = JQUERY_NO_CONFLICT$3;
      return Collapse._jQueryInterface;
    };
  
    /**!
     * @fileOverview Kickass library to create and place poppers near their reference elements.
     * @version 1.14.7
     * @license
     * Copyright (c) 2016 Federico Zivolo 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.
     */
    var isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined';
  
    var longerTimeoutBrowsers = ['Edge', 'Trident', 'Firefox'];
    var timeoutDuration = 0;
    for (var i = 0; i < longerTimeoutBrowsers.length; i += 1) {
      if (isBrowser && navigator.userAgent.indexOf(longerTimeoutBrowsers[i]) >= 0) {
        timeoutDuration = 1;
        break;
      }
    }
  
    function microtaskDebounce(fn) {
      var called = false;
      return function () {
        if (called) {
          return;
        }
        called = true;
        window.Promise.resolve().then(function () {
          called = false;
          fn();
        });
      };
    }
  
    function taskDebounce(fn) {
      var scheduled = false;
      return function () {
        if (!scheduled) {
          scheduled = true;
          setTimeout(function () {
            scheduled = false;
            fn();
          }, timeoutDuration);
        }
      };
    }
  
    var supportsMicroTasks = isBrowser && window.Promise;
  
    /**
    * Create a debounced version of a method, that's asynchronously deferred
    * but called in the minimum time possible.
    *
    * @method
    * @memberof Popper.Utils
    * @argument {Function} fn
    * @returns {Function}
    */
    var debounce = supportsMicroTasks ? microtaskDebounce : taskDebounce;
  
    /**
     * Check if the given variable is a function
     * @method
     * @memberof Popper.Utils
     * @argument {Any} functionToCheck - variable to check
     * @returns {Boolean} answer to: is a function?
     */
    function isFunction(functionToCheck) {
      var getType = {};
      return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
    }
  
    /**
     * Get CSS computed property of the given element
     * @method
     * @memberof Popper.Utils
     * @argument {Eement} element
     * @argument {String} property
     */
    function getStyleComputedProperty(element, property) {
      if (element.nodeType !== 1) {
        return [];
      }
      // NOTE: 1 DOM access here
      var window = element.ownerDocument.defaultView;
      var css = window.getComputedStyle(element, null);
      return property ? css[property] : css;
    }
  
    /**
     * Returns the parentNode or the host of the element
     * @method
     * @memberof Popper.Utils
     * @argument {Element} element
     * @returns {Element} parent
     */
    function getParentNode(element) {
      if (element.nodeName === 'HTML') {
        return element;
      }
      return element.parentNode || element.host;
    }
  
    /**
     * Returns the scrolling parent of the given element
     * @method
     * @memberof Popper.Utils
     * @argument {Element} element
     * @returns {Element} scroll parent
     */
    function getScrollParent(element) {
      // Return body, `getScroll` will take care to get the correct `scrollTop` from it
      if (!element) {
        return document.body;
      }
  
      switch (element.nodeName) {
        case 'HTML':
        case 'BODY':
          return element.ownerDocument.body;
        case '#document':
          return element.body;
      }
  
      // Firefox want us to check `-x` and `-y` variations as well
  
      var _getStyleComputedProp = getStyleComputedProperty(element),
          overflow = _getStyleComputedProp.overflow,
          overflowX = _getStyleComputedProp.overflowX,
          overflowY = _getStyleComputedProp.overflowY;
  
      if (/(auto|scroll|overlay)/.test(overflow + overflowY + overflowX)) {
        return element;
      }
  
      return getScrollParent(getParentNode(element));
    }
  
    var isIE11 = isBrowser && !!(window.MSInputMethodContext && document.documentMode);
    var isIE10 = isBrowser && /MSIE 10/.test(navigator.userAgent);
  
    /**
     * Determines if the browser is Internet Explorer
     * @method
     * @memberof Popper.Utils
     * @param {Number} version to check
     * @returns {Boolean} isIE
     */
    function isIE(version) {
      if (version === 11) {
        return isIE11;
      }
      if (version === 10) {
        return isIE10;
      }
      return isIE11 || isIE10;
    }
  
    /**
     * Returns the offset parent of the given element
     * @method
     * @memberof Popper.Utils
     * @argument {Element} element
     * @returns {Element} offset parent
     */
    function getOffsetParent(element) {
      if (!element) {
        return document.documentElement;
      }
  
      var noOffsetParent = isIE(10) ? document.body : null;
  
      // NOTE: 1 DOM access here
      var offsetParent = element.offsetParent || null;
      // Skip hidden elements which don't have an offsetParent
      while (offsetParent === noOffsetParent && element.nextElementSibling) {
        offsetParent = (element = element.nextElementSibling).offsetParent;
      }
  
      var nodeName = offsetParent && offsetParent.nodeName;
  
      if (!nodeName || nodeName === 'BODY' || nodeName === 'HTML') {
        return element ? element.ownerDocument.documentElement : document.documentElement;
      }
  
      // .offsetParent will return the closest TH, TD or TABLE in case
      // no offsetParent is present, I hate this job...
      if (['TH', 'TD', 'TABLE'].indexOf(offsetParent.nodeName) !== -1 && getStyleComputedProperty(offsetParent, 'position') === 'static') {
        return getOffsetParent(offsetParent);
      }
  
      return offsetParent;
    }
  
    function isOffsetContainer(element) {
      var nodeName = element.nodeName;
  
      if (nodeName === 'BODY') {
        return false;
      }
      return nodeName === 'HTML' || getOffsetParent(element.firstElementChild) === element;
    }
  
    /**
     * Finds the root node (document, shadowDOM root) of the given element
     * @method
     * @memberof Popper.Utils
     * @argument {Element} node
     * @returns {Element} root node
     */
    function getRoot(node) {
      if (node.parentNode !== null) {
        return getRoot(node.parentNode);
      }
  
      return node;
    }
  
    /**
     * Finds the offset parent common to the two provided nodes
     * @method
     * @memberof Popper.Utils
     * @argument {Element} element1
     * @argument {Element} element2
     * @returns {Element} common offset parent
     */
    function findCommonOffsetParent(element1, element2) {
      // This check is needed to avoid errors in case one of the elements isn't defined for any reason
      if (!element1 || !element1.nodeType || !element2 || !element2.nodeType) {
        return document.documentElement;
      }
  
      // Here we make sure to give as "start" the element that comes first in the DOM
      var order = element1.compareDocumentPosition(element2) & Node.DOCUMENT_POSITION_FOLLOWING;
      var start = order ? element1 : element2;
      var end = order ? element2 : element1;
  
      // Get common ancestor container
      var range = document.createRange();
      range.setStart(start, 0);
      range.setEnd(end, 0);
      var commonAncestorContainer = range.commonAncestorContainer;
  
      // Both nodes are inside #document
  
      if (element1 !== commonAncestorContainer && element2 !== commonAncestorContainer || start.contains(end)) {
        if (isOffsetContainer(commonAncestorContainer)) {
          return commonAncestorContainer;
        }
  
        return getOffsetParent(commonAncestorContainer);
      }
  
      // one of the nodes is inside shadowDOM, find which one
      var element1root = getRoot(element1);
      if (element1root.host) {
        return findCommonOffsetParent(element1root.host, element2);
      } else {
        return findCommonOffsetParent(element1, getRoot(element2).host);
      }
    }
  
    /**
     * Gets the scroll value of the given element in the given side (top and left)
     * @method
     * @memberof Popper.Utils
     * @argument {Element} element
     * @argument {String} side `top` or `left`
     * @returns {number} amount of scrolled pixels
     */
    function getScroll(element) {
      var side = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'top';
  
      var upperSide = side === 'top' ? 'scrollTop' : 'scrollLeft';
      var nodeName = element.nodeName;
  
      if (nodeName === 'BODY' || nodeName === 'HTML') {
        var html = element.ownerDocument.documentElement;
        var scrollingElement = element.ownerDocument.scrollingElement || html;
        return scrollingElement[upperSide];
      }
  
      return element[upperSide];
    }
  
    /*
     * Sum or subtract the element scroll values (left and top) from a given rect object
     * @method
     * @memberof Popper.Utils
     * @param {Object} rect - Rect object you want to change
     * @param {HTMLElement} element - The element from the function reads the scroll values
     * @param {Boolean} subtract - set to true if you want to subtract the scroll values
     * @return {Object} rect - The modifier rect object
     */
    function includeScroll(rect, element) {
      var subtract = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
  
      var scrollTop = getScroll(element, 'top');
      var scrollLeft = getScroll(element, 'left');
      var modifier = subtract ? -1 : 1;
      rect.top += scrollTop * modifier;
      rect.bottom += scrollTop * modifier;
      rect.left += scrollLeft * modifier;
      rect.right += scrollLeft * modifier;
      return rect;
    }
  
    /*
     * Helper to detect borders of a given element
     * @method
     * @memberof Popper.Utils
     * @param {CSSStyleDeclaration} styles
     * Result of `getStyleComputedProperty` on the given element
     * @param {String} axis - `x` or `y`
     * @return {number} borders - The borders size of the given axis
     */
  
    function getBordersSize(styles, axis) {
      var sideA = axis === 'x' ? 'Left' : 'Top';
      var sideB = sideA === 'Left' ? 'Right' : 'Bottom';
  
      return parseFloat(styles['border' + sideA + 'Width'], 10) + parseFloat(styles['border' + sideB + 'Width'], 10);
    }
  
    function getSize(axis, body, html, computedStyle) {
      return Math.max(body['offset' + axis], body['scroll' + axis], html['client' + axis], html['offset' + axis], html['scroll' + axis], isIE(10) ? parseInt(html['offset' + axis]) + parseInt(computedStyle['margin' + (axis === 'Height' ? 'Top' : 'Left')]) + parseInt(computedStyle['margin' + (axis === 'Height' ? 'Bottom' : 'Right')]) : 0);
    }
  
    function getWindowSizes(document) {
      var body = document.body;
      var html = document.documentElement;
      var computedStyle = isIE(10) && getComputedStyle(html);
  
      return {
        height: getSize('Height', body, html, computedStyle),
        width: getSize('Width', body, html, computedStyle)
      };
    }
  
    var classCallCheck = function (instance, Constructor) {
      if (!(instance instanceof Constructor)) {
        throw new TypeError("Cannot call a class as a function");
      }
    };
  
    var createClass = function () {
      function defineProperties(target, props) {
        for (var i = 0; i < props.length; i++) {
          var descriptor = props[i];
          descriptor.enumerable = descriptor.enumerable || false;
          descriptor.configurable = true;
          if ("value" in descriptor) descriptor.writable = true;
          Object.defineProperty(target, descriptor.key, descriptor);
        }
      }
  
      return function (Constructor, protoProps, staticProps) {
        if (protoProps) defineProperties(Constructor.prototype, protoProps);
        if (staticProps) defineProperties(Constructor, staticProps);
        return Constructor;
      };
    }();
  
  
  
  
  
    var defineProperty = function (obj, key, value) {
      if (key in obj) {
        Object.defineProperty(obj, key, {
          value: value,
          enumerable: true,
          configurable: true,
          writable: true
        });
      } else {
        obj[key] = value;
      }
  
      return obj;
    };
  
    var _extends = Object.assign || function (target) {
      for (var i = 1; i < arguments.length; i++) {
        var source = arguments[i];
  
        for (var key in source) {
          if (Object.prototype.hasOwnProperty.call(source, key)) {
            target[key] = source[key];
          }
        }
      }
  
      return target;
    };
  
    /**
     * Given element offsets, generate an output similar to getBoundingClientRect
     * @method
     * @memberof Popper.Utils
     * @argument {Object} offsets
     * @returns {Object} ClientRect like output
     */
    function getClientRect(offsets) {
      return _extends({}, offsets, {
        right: offsets.left + offsets.width,
        bottom: offsets.top + offsets.height
      });
    }
  
    /**
     * Get bounding client rect of given element
     * @method
     * @memberof Popper.Utils
     * @param {HTMLElement} element
     * @return {Object} client rect
     */
    function getBoundingClientRect(element) {
      var rect = {};
  
      // IE10 10 FIX: Please, don't ask, the element isn't
      // considered in DOM in some circumstances...
      // This isn't reproducible in IE10 compatibility mode of IE11
      try {
        if (isIE(10)) {
          rect = element.getBoundingClientRect();
          var scrollTop = getScroll(element, 'top');
          var scrollLeft = getScroll(element, 'left');
          rect.top += scrollTop;
          rect.left += scrollLeft;
          rect.bottom += scrollTop;
          rect.right += scrollLeft;
        } else {
          rect = element.getBoundingClientRect();
        }
      } catch (e) {}
  
      var result = {
        left: rect.left,
        top: rect.top,
        width: rect.right - rect.left,
        height: rect.bottom - rect.top
      };
  
      // subtract scrollbar size from sizes
      var sizes = element.nodeName === 'HTML' ? getWindowSizes(element.ownerDocument) : {};
      var width = sizes.width || element.clientWidth || result.right - result.left;
      var height = sizes.height || element.clientHeight || result.bottom - result.top;
  
      var horizScrollbar = element.offsetWidth - width;
      var vertScrollbar = element.offsetHeight - height;
  
      // if an hypothetical scrollbar is detected, we must be sure it's not a `border`
      // we make this check conditional for performance reasons
      if (horizScrollbar || vertScrollbar) {
        var styles = getStyleComputedProperty(element);
        horizScrollbar -= getBordersSize(styles, 'x');
        vertScrollbar -= getBordersSize(styles, 'y');
  
        result.width -= horizScrollbar;
        result.height -= vertScrollbar;
      }
  
      return getClientRect(result);
    }
  
    function getOffsetRectRelativeToArbitraryNode(children, parent) {
      var fixedPosition = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
  
      var isIE10 = isIE(10);
      var isHTML = parent.nodeName === 'HTML';
      var childrenRect = getBoundingClientRect(children);
      var parentRect = getBoundingClientRect(parent);
      var scrollParent = getScrollParent(children);
  
      var styles = getStyleComputedProperty(parent);
      var borderTopWidth = parseFloat(styles.borderTopWidth, 10);
      var borderLeftWidth = parseFloat(styles.borderLeftWidth, 10);
  
      // In cases where the parent is fixed, we must ignore negative scroll in offset calc
      if (fixedPosition && isHTML) {
        parentRect.top = Math.max(parentRect.top, 0);
        parentRect.left = Math.max(parentRect.left, 0);
      }
      var offsets = getClientRect({
        top: childrenRect.top - parentRect.top - borderTopWidth,
        left: childrenRect.left - parentRect.left - borderLeftWidth,
        width: childrenRect.width,
        height: childrenRect.height
      });
      offsets.marginTop = 0;
      offsets.marginLeft = 0;
  
      // Subtract margins of documentElement in case it's being used as parent
      // we do this only on HTML because it's the only element that behaves
      // differently when margins are applied to it. The margins are included in
      // the box of the documentElement, in the other cases not.
      if (!isIE10 && isHTML) {
        var marginTop = parseFloat(styles.marginTop, 10);
        var marginLeft = parseFloat(styles.marginLeft, 10);
  
        offsets.top -= borderTopWidth - marginTop;
        offsets.bottom -= borderTopWidth - marginTop;
        offsets.left -= borderLeftWidth - marginLeft;
        offsets.right -= borderLeftWidth - marginLeft;
  
        // Attach marginTop and marginLeft because in some circumstances we may need them
        offsets.marginTop = marginTop;
        offsets.marginLeft = marginLeft;
      }
  
      if (isIE10 && !fixedPosition ? parent.contains(scrollParent) : parent === scrollParent && scrollParent.nodeName !== 'BODY') {
        offsets = includeScroll(offsets, parent);
      }
  
      return offsets;
    }
  
    function getViewportOffsetRectRelativeToArtbitraryNode(element) {
      var excludeScroll = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
  
      var html = element.ownerDocument.documentElement;
      var relativeOffset = getOffsetRectRelativeToArbitraryNode(element, html);
      var width = Math.max(html.clientWidth, window.innerWidth || 0);
      var height = Math.max(html.clientHeight, window.innerHeight || 0);
  
      var scrollTop = !excludeScroll ? getScroll(html) : 0;
      var scrollLeft = !excludeScroll ? getScroll(html, 'left') : 0;
  
      var offset = {
        top: scrollTop - relativeOffset.top + relativeOffset.marginTop,
        left: scrollLeft - relativeOffset.left + relativeOffset.marginLeft,
        width: width,
        height: height
      };
  
      return getClientRect(offset);
    }
  
    /**
     * Check if the given element is fixed or is inside a fixed parent
     * @method
     * @memberof Popper.Utils
     * @argument {Element} element
     * @argument {Element} customContainer
     * @returns {Boolean} answer to "isFixed?"
     */
    function isFixed(element) {
      var nodeName = element.nodeName;
      if (nodeName === 'BODY' || nodeName === 'HTML') {
        return false;
      }
      if (getStyleComputedProperty(element, 'position') === 'fixed') {
        return true;
      }
      var parentNode = getParentNode(element);
      if (!parentNode) {
        return false;
      }
      return isFixed(parentNode);
    }
  
    /**
     * Finds the first parent of an element that has a transformed property defined
     * @method
     * @memberof Popper.Utils
     * @argument {Element} element
     * @returns {Element} first transformed parent or documentElement
     */
  
    function getFixedPositionOffsetParent(element) {
      // This check is needed to avoid errors in case one of the elements isn't defined for any reason
      if (!element || !element.parentElement || isIE()) {
        return document.documentElement;
      }
      var el = element.parentElement;
      while (el && getStyleComputedProperty(el, 'transform') === 'none') {
        el = el.parentElement;
      }
      return el || document.documentElement;
    }
  
    /**
     * Computed the boundaries limits and return them
     * @method
     * @memberof Popper.Utils
     * @param {HTMLElement} popper
     * @param {HTMLElement} reference
     * @param {number} padding
     * @param {HTMLElement} boundariesElement - Element used to define the boundaries
     * @param {Boolean} fixedPosition - Is in fixed position mode
     * @returns {Object} Coordinates of the boundaries
     */
    function getBoundaries(popper, reference, padding, boundariesElement) {
      var fixedPosition = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
  
      // NOTE: 1 DOM access here
  
      var boundaries = { top: 0, left: 0 };
      var offsetParent = fixedPosition ? getFixedPositionOffsetParent(popper) : findCommonOffsetParent(popper, reference);
  
      // Handle viewport case
      if (boundariesElement === 'viewport') {
        boundaries = getViewportOffsetRectRelativeToArtbitraryNode(offsetParent, fixedPosition);
      } else {
        // Handle other cases based on DOM element used as boundaries
        var boundariesNode = void 0;
        if (boundariesElement === 'scrollParent') {
          boundariesNode = getScrollParent(getParentNode(reference));
          if (boundariesNode.nodeName === 'BODY') {
            boundariesNode = popper.ownerDocument.documentElement;
          }
        } else if (boundariesElement === 'window') {
          boundariesNode = popper.ownerDocument.documentElement;
        } else {
          boundariesNode = boundariesElement;
        }
  
        var offsets = getOffsetRectRelativeToArbitraryNode(boundariesNode, offsetParent, fixedPosition);
  
        // In case of HTML, we need a different computation
        if (boundariesNode.nodeName === 'HTML' && !isFixed(offsetParent)) {
          var _getWindowSizes = getWindowSizes(popper.ownerDocument),
              height = _getWindowSizes.height,
              width = _getWindowSizes.width;
  
          boundaries.top += offsets.top - offsets.marginTop;
          boundaries.bottom = height + offsets.top;
          boundaries.left += offsets.left - offsets.marginLeft;
          boundaries.right = width + offsets.left;
        } else {
          // for all the other DOM elements, this one is good
          boundaries = offsets;
        }
      }
  
      // Add paddings
      padding = padding || 0;
      var isPaddingNumber = typeof padding === 'number';
      boundaries.left += isPaddingNumber ? padding : padding.left || 0;
      boundaries.top += isPaddingNumber ? padding : padding.top || 0;
      boundaries.right -= isPaddingNumber ? padding : padding.right || 0;
      boundaries.bottom -= isPaddingNumber ? padding : padding.bottom || 0;
  
      return boundaries;
    }
  
    function getArea(_ref) {
      var width = _ref.width,
          height = _ref.height;
  
      return width * height;
    }
  
    /**
     * Utility used to transform the `auto` placement to the placement with more
     * available space.
     * @method
     * @memberof Popper.Utils
     * @argument {Object} data - The data object generated by update method
     * @argument {Object} options - Modifiers configuration and options
     * @returns {Object} The data object, properly modified
     */
    function computeAutoPlacement(placement, refRect, popper, reference, boundariesElement) {
      var padding = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 0;
  
      if (placement.indexOf('auto') === -1) {
        return placement;
      }
  
      var boundaries = getBoundaries(popper, reference, padding, boundariesElement);
  
      var rects = {
        top: {
          width: boundaries.width,
          height: refRect.top - boundaries.top
        },
        right: {
          width: boundaries.right - refRect.right,
          height: boundaries.height
        },
        bottom: {
          width: boundaries.width,
          height: boundaries.bottom - refRect.bottom
        },
        left: {
          width: refRect.left - boundaries.left,
          height: boundaries.height
        }
      };
  
      var sortedAreas = Object.keys(rects).map(function (key) {
        return _extends({
          key: key
        }, rects[key], {
          area: getArea(rects[key])
        });
      }).sort(function (a, b) {
        return b.area - a.area;
      });
  
      var filteredAreas = sortedAreas.filter(function (_ref2) {
        var width = _ref2.width,
            height = _ref2.height;
        return width >= popper.clientWidth && height >= popper.clientHeight;
      });
  
      var computedPlacement = filteredAreas.length > 0 ? filteredAreas[0].key : sortedAreas[0].key;
  
      var variation = placement.split('-')[1];
  
      return computedPlacement + (variation ? '-' + variation : '');
    }
  
    /**
     * Get offsets to the reference element
     * @method
     * @memberof Popper.Utils
     * @param {Object} state
     * @param {Element} popper - the popper element
     * @param {Element} reference - the reference element (the popper will be relative to this)
     * @param {Element} fixedPosition - is in fixed position mode
     * @returns {Object} An object containing the offsets which will be applied to the popper
     */
    function getReferenceOffsets(state, popper, reference) {
      var fixedPosition = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
  
      var commonOffsetParent = fixedPosition ? getFixedPositionOffsetParent(popper) : findCommonOffsetParent(popper, reference);
      return getOffsetRectRelativeToArbitraryNode(reference, commonOffsetParent, fixedPosition);
    }
  
    /**
     * Get the outer sizes of the given element (offset size + margins)
     * @method
     * @memberof Popper.Utils
     * @argument {Element} element
     * @returns {Object} object containing width and height properties
     */
    function getOuterSizes(element) {
      var window = element.ownerDocument.defaultView;
      var styles = window.getComputedStyle(element);
      var x = parseFloat(styles.marginTop || 0) + parseFloat(styles.marginBottom || 0);
      var y = parseFloat(styles.marginLeft || 0) + parseFloat(styles.marginRight || 0);
      var result = {
        width: element.offsetWidth + y,
        height: element.offsetHeight + x
      };
      return result;
    }
  
    /**
     * Get the opposite placement of the given one
     * @method
     * @memberof Popper.Utils
     * @argument {String} placement
     * @returns {String} flipped placement
     */
    function getOppositePlacement(placement) {
      var hash = { left: 'right', right: 'left', bottom: 'top', top: 'bottom' };
      return placement.replace(/left|right|bottom|top/g, function (matched) {
        return hash[matched];
      });
    }
  
    /**
     * Get offsets to the popper
     * @method
     * @memberof Popper.Utils
     * @param {Object} position - CSS position the Popper will get applied
     * @param {HTMLElement} popper - the popper element
     * @param {Object} referenceOffsets - the reference offsets (the popper will be relative to this)
     * @param {String} placement - one of the valid placement options
     * @returns {Object} popperOffsets - An object containing the offsets which will be applied to the popper
     */
    function getPopperOffsets(popper, referenceOffsets, placement) {
      placement = placement.split('-')[0];
  
      // Get popper node sizes
      var popperRect = getOuterSizes(popper);
  
      // Add position, width and height to our offsets object
      var popperOffsets = {
        width: popperRect.width,
        height: popperRect.height
      };
  
      // depending by the popper placement we have to compute its offsets slightly differently
      var isHoriz = ['right', 'left'].indexOf(placement) !== -1;
      var mainSide = isHoriz ? 'top' : 'left';
      var secondarySide = isHoriz ? 'left' : 'top';
      var measurement = isHoriz ? 'height' : 'width';
      var secondaryMeasurement = !isHoriz ? 'height' : 'width';
  
      popperOffsets[mainSide] = referenceOffsets[mainSide] + referenceOffsets[measurement] / 2 - popperRect[measurement] / 2;
      if (placement === secondarySide) {
        popperOffsets[secondarySide] = referenceOffsets[secondarySide] - popperRect[secondaryMeasurement];
      } else {
        popperOffsets[secondarySide] = referenceOffsets[getOppositePlacement(secondarySide)];
      }
  
      return popperOffsets;
    }
  
    /**
     * Mimics the `find` method of Array
     * @method
     * @memberof Popper.Utils
     * @argument {Array} arr
     * @argument prop
     * @argument value
     * @returns index or -1
     */
    function find(arr, check) {
      // use native find if supported
      if (Array.prototype.find) {
        return arr.find(check);
      }
  
      // use `filter` to obtain the same behavior of `find`
      return arr.filter(check)[0];
    }
  
    /**
     * Return the index of the matching object
     * @method
     * @memberof Popper.Utils
     * @argument {Array} arr
     * @argument prop
     * @argument value
     * @returns index or -1
     */
    function findIndex(arr, prop, value) {
      // use native findIndex if supported
      if (Array.prototype.findIndex) {
        return arr.findIndex(function (cur) {
          return cur[prop] === value;
        });
      }
  
      // use `find` + `indexOf` if `findIndex` isn't supported
      var match = find(arr, function (obj) {
        return obj[prop] === value;
      });
      return arr.indexOf(match);
    }
  
    /**
     * Loop trough the list of modifiers and run them in order,
     * each of them will then edit the data object.
     * @method
     * @memberof Popper.Utils
     * @param {dataObject} data
     * @param {Array} modifiers
     * @param {String} ends - Optional modifier name used as stopper
     * @returns {dataObject}
     */
    function runModifiers(modifiers, data, ends) {
      var modifiersToRun = ends === undefined ? modifiers : modifiers.slice(0, findIndex(modifiers, 'name', ends));
  
      modifiersToRun.forEach(function (modifier) {
        if (modifier['function']) {
          // eslint-disable-line dot-notation
          console.warn('`modifier.function` is deprecated, use `modifier.fn`!');
        }
        var fn = modifier['function'] || modifier.fn; // eslint-disable-line dot-notation
        if (modifier.enabled && isFunction(fn)) {
          // Add properties to offsets to make them a complete clientRect object
          // we do this before each modifier to make sure the previous one doesn't
          // mess with these values
          data.offsets.popper = getClientRect(data.offsets.popper);
          data.offsets.reference = getClientRect(data.offsets.reference);
  
          data = fn(data, modifier);
        }
      });
  
      return data;
    }
  
    /**
     * Updates the position of the popper, computing the new offsets and applying
     * the new style.<br />
     * Prefer `scheduleUpdate` over `update` because of performance reasons.
     * @method
     * @memberof Popper
     */
    function update() {
      // if popper is destroyed, don't perform any further update
      if (this.state.isDestroyed) {
        return;
      }
  
      var data = {
        instance: this,
        styles: {},
        arrowStyles: {},
        attributes: {},
        flipped: false,
        offsets: {}
      };
  
      // compute reference element offsets
      data.offsets.reference = getReferenceOffsets(this.state, this.popper, this.reference, this.options.positionFixed);
  
      // compute auto placement, store placement inside the data object,
      // modifiers will be able to edit `placement` if needed
      // and refer to originalPlacement to know the original value
      data.placement = computeAutoPlacement(this.options.placement, data.offsets.reference, this.popper, this.reference, this.options.modifiers.flip.boundariesElement, this.options.modifiers.flip.padding);
  
      // store the computed placement inside `originalPlacement`
      data.originalPlacement = data.placement;
  
      data.positionFixed = this.options.positionFixed;
  
      // compute the popper offsets
      data.offsets.popper = getPopperOffsets(this.popper, data.offsets.reference, data.placement);
  
      data.offsets.popper.position = this.options.positionFixed ? 'fixed' : 'absolute';
  
      // run the modifiers
      data = runModifiers(this.modifiers, data);
  
      // the first `update` will call `onCreate` callback
      // the other ones will call `onUpdate` callback
      if (!this.state.isCreated) {
        this.state.isCreated = true;
        this.options.onCreate(data);
      } else {
        this.options.onUpdate(data);
      }
    }
  
    /**
     * Helper used to know if the given modifier is enabled.
     * @method
     * @memberof Popper.Utils
     * @returns {Boolean}
     */
    function isModifierEnabled(modifiers, modifierName) {
      return modifiers.some(function (_ref) {
        var name = _ref.name,
            enabled = _ref.enabled;
        return enabled && name === modifierName;
      });
    }
  
    /**
     * Get the prefixed supported property name
     * @method
     * @memberof Popper.Utils
     * @argument {String} property (camelCase)
     * @returns {String} prefixed property (camelCase or PascalCase, depending on the vendor prefix)
     */
    function getSupportedPropertyName(property) {
      var prefixes = [false, 'ms', 'Webkit', 'Moz', 'O'];
      var upperProp = property.charAt(0).toUpperCase() + property.slice(1);
  
      for (var i = 0; i < prefixes.length; i++) {
        var prefix = prefixes[i];
        var toCheck = prefix ? '' + prefix + upperProp : property;
        if (typeof document.body.style[toCheck] !== 'undefined') {
          return toCheck;
        }
      }
      return null;
    }
  
    /**
     * Destroys the popper.
     * @method
     * @memberof Popper
     */
    function destroy() {
      this.state.isDestroyed = true;
  
      // touch DOM only if `applyStyle` modifier is enabled
      if (isModifierEnabled(this.modifiers, 'applyStyle')) {
        this.popper.removeAttribute('x-placement');
        this.popper.style.position = '';
        this.popper.style.top = '';
        this.popper.style.left = '';
        this.popper.style.right = '';
        this.popper.style.bottom = '';
        this.popper.style.willChange = '';
        this.popper.style[getSupportedPropertyName('transform')] = '';
      }
  
      this.disableEventListeners();
  
      // remove the popper if user explicity asked for the deletion on destroy
      // do not use `remove` because IE11 doesn't support it
      if (this.options.removeOnDestroy) {
        this.popper.parentNode.removeChild(this.popper);
      }
      return this;
    }
  
    /**
     * Get the window associated with the element
     * @argument {Element} element
     * @returns {Window}
     */
    function getWindow(element) {
      var ownerDocument = element.ownerDocument;
      return ownerDocument ? ownerDocument.defaultView : window;
    }
  
    function attachToScrollParents(scrollParent, event, callback, scrollParents) {
      var isBody = scrollParent.nodeName === 'BODY';
      var target = isBody ? scrollParent.ownerDocument.defaultView : scrollParent;
      target.addEventListener(event, callback, { passive: true });
  
      if (!isBody) {
        attachToScrollParents(getScrollParent(target.parentNode), event, callback, scrollParents);
      }
      scrollParents.push(target);
    }
  
    /**
     * Setup needed event listeners used to update the popper position
     * @method
     * @memberof Popper.Utils
     * @private
     */
    function setupEventListeners(reference, options, state, updateBound) {
      // Resize event listener on window
      state.updateBound = updateBound;
      getWindow(reference).addEventListener('resize', state.updateBound, { passive: true });
  
      // Scroll event listener on scroll parents
      var scrollElement = getScrollParent(reference);
      attachToScrollParents(scrollElement, 'scroll', state.updateBound, state.scrollParents);
      state.scrollElement = scrollElement;
      state.eventsEnabled = true;
  
      return state;
    }
  
    /**
     * It will add resize/scroll events and start recalculating
     * position of the popper element when they are triggered.
     * @method
     * @memberof Popper
     */
    function enableEventListeners() {
      if (!this.state.eventsEnabled) {
        this.state = setupEventListeners(this.reference, this.options, this.state, this.scheduleUpdate);
      }
    }
  
    /**
     * Remove event listeners used to update the popper position
     * @method
     * @memberof Popper.Utils
     * @private
     */
    function removeEventListeners(reference, state) {
      // Remove resize event listener on window
      getWindow(reference).removeEventListener('resize', state.updateBound);
  
      // Remove scroll event listener on scroll parents
      state.scrollParents.forEach(function (target) {
        target.removeEventListener('scroll', state.updateBound);
      });
  
      // Reset state
      state.updateBound = null;
      state.scrollParents = [];
      state.scrollElement = null;
      state.eventsEnabled = false;
      return state;
    }
  
    /**
     * It will remove resize/scroll events and won't recalculate popper position
     * when they are triggered. It also won't trigger `onUpdate` callback anymore,
     * unless you call `update` method manually.
     * @method
     * @memberof Popper
     */
    function disableEventListeners() {
      if (this.state.eventsEnabled) {
        cancelAnimationFrame(this.scheduleUpdate);
        this.state = removeEventListeners(this.reference, this.state);
      }
    }
  
    /**
     * Tells if a given input is a number
     * @method
     * @memberof Popper.Utils
     * @param {*} input to check
     * @return {Boolean}
     */
    function isNumeric(n) {
      return n !== '' && !isNaN(parseFloat(n)) && isFinite(n);
    }
  
    /**
     * Set the style to the given popper
     * @method
     * @memberof Popper.Utils
     * @argument {Element} element - Element to apply the style to
     * @argument {Object} styles
     * Object with a list of properties and values which will be applied to the element
     */
    function setStyles(element, styles) {
      Object.keys(styles).forEach(function (prop) {
        var unit = '';
        // add unit if the value is numeric and is one of the following
        if (['width', 'height', 'top', 'right', 'bottom', 'left'].indexOf(prop) !== -1 && isNumeric(styles[prop])) {
          unit = 'px';
        }
        element.style[prop] = styles[prop] + unit;
      });
    }
  
    /**
     * Set the attributes to the given popper
     * @method
     * @memberof Popper.Utils
     * @argument {Element} element - Element to apply the attributes to
     * @argument {Object} styles
     * Object with a list of properties and values which will be applied to the element
     */
    function setAttributes(element, attributes) {
      Object.keys(attributes).forEach(function (prop) {
        var value = attributes[prop];
        if (value !== false) {
          element.setAttribute(prop, attributes[prop]);
        } else {
          element.removeAttribute(prop);
        }
      });
    }
  
    /**
     * @function
     * @memberof Modifiers
     * @argument {Object} data - The data object generated by `update` method
     * @argument {Object} data.styles - List of style properties - values to apply to popper element
     * @argument {Object} data.attributes - List of attribute properties - values to apply to popper element
     * @argument {Object} options - Modifiers configuration and options
     * @returns {Object} The same data object
     */
    function applyStyle(data) {
      // any property present in `data.styles` will be applied to the popper,
      // in this way we can make the 3rd party modifiers add custom styles to it
      // Be aware, modifiers could override the properties defined in the previous
      // lines of this modifier!
      setStyles(data.instance.popper, data.styles);
  
      // any property present in `data.attributes` will be applied to the popper,
      // they will be set as HTML attributes of the element
      setAttributes(data.instance.popper, data.attributes);
  
      // if arrowElement is defined and arrowStyles has some properties
      if (data.arrowElement && Object.keys(data.arrowStyles).length) {
        setStyles(data.arrowElement, data.arrowStyles);
      }
  
      return data;
    }
  
    /**
     * Set the x-placement attribute before everything else because it could be used
     * to add margins to the popper margins needs to be calculated to get the
     * correct popper offsets.
     * @method
     * @memberof Popper.modifiers
     * @param {HTMLElement} reference - The reference element used to position the popper
     * @param {HTMLElement} popper - The HTML element used as popper
     * @param {Object} options - Popper.js options
     */
    function applyStyleOnLoad(reference, popper, options, modifierOptions, state) {
      // compute reference element offsets
      var referenceOffsets = getReferenceOffsets(state, popper, reference, options.positionFixed);
  
      // compute auto placement, store placement inside the data object,
      // modifiers will be able to edit `placement` if needed
      // and refer to originalPlacement to know the original value
      var placement = computeAutoPlacement(options.placement, referenceOffsets, popper, reference, options.modifiers.flip.boundariesElement, options.modifiers.flip.padding);
  
      popper.setAttribute('x-placement', placement);
  
      // Apply `position` to popper before anything else because
      // without the position applied we can't guarantee correct computations
      setStyles(popper, { position: options.positionFixed ? 'fixed' : 'absolute' });
  
      return options;
    }
  
    /**
     * @function
     * @memberof Popper.Utils
     * @argument {Object} data - The data object generated by `update` method
     * @argument {Boolean} shouldRound - If the offsets should be rounded at all
     * @returns {Object} The popper's position offsets rounded
     *
     * The tale of pixel-perfect positioning. It's still not 100% perfect, but as
     * good as it can be within reason.
     * Discussion here: https://github.com/FezVrasta/popper.js/pull/715
     *
     * Low DPI screens cause a popper to be blurry if not using full pixels (Safari
     * as well on High DPI screens).
     *
     * Firefox prefers no rounding for positioning and does not have blurriness on
     * high DPI screens.
     *
     * Only horizontal placement and left/right values need to be considered.
     */
    function getRoundedOffsets(data, shouldRound) {
      var _data$offsets = data.offsets,
          popper = _data$offsets.popper,
          reference = _data$offsets.reference;
      var round = Math.round,
          floor = Math.floor;
  
      var noRound = function noRound(v) {
        return v;
      };
  
      var referenceWidth = round(reference.width);
      var popperWidth = round(popper.width);
  
      var isVertical = ['left', 'right'].indexOf(data.placement) !== -1;
      var isVariation = data.placement.indexOf('-') !== -1;
      var sameWidthParity = referenceWidth % 2 === popperWidth % 2;
      var bothOddWidth = referenceWidth % 2 === 1 && popperWidth % 2 === 1;
  
      var horizontalToInteger = !shouldRound ? noRound : isVertical || isVariation || sameWidthParity ? round : floor;
      var verticalToInteger = !shouldRound ? noRound : round;
  
      return {
        left: horizontalToInteger(bothOddWidth && !isVariation && shouldRound ? popper.left - 1 : popper.left),
        top: verticalToInteger(popper.top),
        bottom: verticalToInteger(popper.bottom),
        right: horizontalToInteger(popper.right)
      };
    }
  
    var isFirefox = isBrowser && /Firefox/i.test(navigator.userAgent);
  
    /**
     * @function
     * @memberof Modifiers
     * @argument {Object} data - The data object generated by `update` method
     * @argument {Object} options - Modifiers configuration and options
     * @returns {Object} The data object, properly modified
     */
    function computeStyle(data, options) {
      var x = options.x,
          y = options.y;
      var popper = data.offsets.popper;
  
      // Remove this legacy support in Popper.js v2
  
      var legacyGpuAccelerationOption = find(data.instance.modifiers, function (modifier) {
        return modifier.name === 'applyStyle';
      }).gpuAcceleration;
      if (legacyGpuAccelerationOption !== undefined) {
        console.warn('WARNING: `gpuAcceleration` option moved to `computeStyle` modifier and will not be supported in future versions of Popper.js!');
      }
      var gpuAcceleration = legacyGpuAccelerationOption !== undefined ? legacyGpuAccelerationOption : options.gpuAcceleration;
  
      var offsetParent = getOffsetParent(data.instance.popper);
      var offsetParentRect = getBoundingClientRect(offsetParent);
  
      // Styles
      var styles = {
        position: popper.position
      };
  
      var offsets = getRoundedOffsets(data, window.devicePixelRatio < 2 || !isFirefox);
  
      var sideA = x === 'bottom' ? 'top' : 'bottom';
      var sideB = y === 'right' ? 'left' : 'right';
  
      // if gpuAcceleration is set to `true` and transform is supported,
      //  we use `translate3d` to apply the position to the popper we
      // automatically use the supported prefixed version if needed
      var prefixedProperty = getSupportedPropertyName('transform');
  
      // now, let's make a step back and look at this code closely (wtf?)
      // If the content of the popper grows once it's been positioned, it
      // may happen that the popper gets misplaced because of the new content
      // overflowing its reference element
      // To avoid this problem, we provide two options (x and y), which allow
      // the consumer to define the offset origin.
      // If we position a popper on top of a reference element, we can set
      // `x` to `top` to make the popper grow towards its top instead of
      // its bottom.
      var left = void 0,
          top = void 0;
      if (sideA === 'bottom') {
        // when offsetParent is <html> the positioning is relative to the bottom of the screen (excluding the scrollbar)
        // and not the bottom of the html element
        if (offsetParent.nodeName === 'HTML') {
          top = -offsetParent.clientHeight + offsets.bottom;
        } else {
          top = -offsetParentRect.height + offsets.bottom;
        }
      } else {
        top = offsets.top;
      }
      if (sideB === 'right') {
        if (offsetParent.nodeName === 'HTML') {
          left = -offsetParent.clientWidth + offsets.right;
        } else {
          left = -offsetParentRect.width + offsets.right;
        }
      } else {
        left = offsets.left;
      }
      if (gpuAcceleration && prefixedProperty) {
        styles[prefixedProperty] = 'translate3d(' + left + 'px, ' + top + 'px, 0)';
        styles[sideA] = 0;
        styles[sideB] = 0;
        styles.willChange = 'transform';
      } else {
        // othwerise, we use the standard `top`, `left`, `bottom` and `right` properties
        var invertTop = sideA === 'bottom' ? -1 : 1;
        var invertLeft = sideB === 'right' ? -1 : 1;
        styles[sideA] = top * invertTop;
        styles[sideB] = left * invertLeft;
        styles.willChange = sideA + ', ' + sideB;
      }
  
      // Attributes
      var attributes = {
        'x-placement': data.placement
      };
  
      // Update `data` attributes, styles and arrowStyles
      data.attributes = _extends({}, attributes, data.attributes);
      data.styles = _extends({}, styles, data.styles);
      data.arrowStyles = _extends({}, data.offsets.arrow, data.arrowStyles);
  
      return data;
    }
  
    /**
     * Helper used to know if the given modifier depends from another one.<br />
     * It checks if the needed modifier is listed and enabled.
     * @method
     * @memberof Popper.Utils
     * @param {Array} modifiers - list of modifiers
     * @param {String} requestingName - name of requesting modifier
     * @param {String} requestedName - name of requested modifier
     * @returns {Boolean}
     */
    function isModifierRequired(modifiers, requestingName, requestedName) {
      var requesting = find(modifiers, function (_ref) {
        var name = _ref.name;
        return name === requestingName;
      });
  
      var isRequired = !!requesting && modifiers.some(function (modifier) {
        return modifier.name === requestedName && modifier.enabled && modifier.order < requesting.order;
      });
  
      if (!isRequired) {
        var _requesting = '`' + requestingName + '`';
        var requested = '`' + requestedName + '`';
        console.warn(requested + ' modifier is required by ' + _requesting + ' modifier in order to work, be sure to include it before ' + _requesting + '!');
      }
      return isRequired;
    }
  
    /**
     * @function
     * @memberof Modifiers
     * @argument {Object} data - The data object generated by update method
     * @argument {Object} options - Modifiers configuration and options
     * @returns {Object} The data object, properly modified
     */
    function arrow(data, options) {
      var _data$offsets$arrow;
  
      // arrow depends on keepTogether in order to work
      if (!isModifierRequired(data.instance.modifiers, 'arrow', 'keepTogether')) {
        return data;
      }
  
      var arrowElement = options.element;
  
      // if arrowElement is a string, suppose it's a CSS selector
      if (typeof arrowElement === 'string') {
        arrowElement = data.instance.popper.querySelector(arrowElement);
  
        // if arrowElement is not found, don't run the modifier
        if (!arrowElement) {
          return data;
        }
      } else {
        // if the arrowElement isn't a query selector we must check that the
        // provided DOM node is child of its popper node
        if (!data.instance.popper.contains(arrowElement)) {
          console.warn('WARNING: `arrow.element` must be child of its popper element!');
          return data;
        }
      }
  
      var placement = data.placement.split('-')[0];
      var _data$offsets = data.offsets,
          popper = _data$offsets.popper,
          reference = _data$offsets.reference;
  
      var isVertical = ['left', 'right'].indexOf(placement) !== -1;
  
      var len = isVertical ? 'height' : 'width';
      var sideCapitalized = isVertical ? 'Top' : 'Left';
      var side = sideCapitalized.toLowerCase();
      var altSide = isVertical ? 'left' : 'top';
      var opSide = isVertical ? 'bottom' : 'right';
      var arrowElementSize = getOuterSizes(arrowElement)[len];
  
      //
      // extends keepTogether behavior making sure the popper and its
      // reference have enough pixels in conjunction
      //
  
      // top/left side
      if (reference[opSide] - arrowElementSize < popper[side]) {
        data.offsets.popper[side] -= popper[side] - (reference[opSide] - arrowElementSize);
      }
      // bottom/right side
      if (reference[side] + arrowElementSize > popper[opSide]) {
        data.offsets.popper[side] += reference[side] + arrowElementSize - popper[opSide];
      }
      data.offsets.popper = getClientRect(data.offsets.popper);
  
      // compute center of the popper
      var center = reference[side] + reference[len] / 2 - arrowElementSize / 2;
  
      // Compute the sideValue using the updated popper offsets
      // take popper margin in account because we don't have this info available
      var css = getStyleComputedProperty(data.instance.popper);
      var popperMarginSide = parseFloat(css['margin' + sideCapitalized], 10);
      var popperBorderSide = parseFloat(css['border' + sideCapitalized + 'Width'], 10);
      var sideValue = center - data.offsets.popper[side] - popperMarginSide - popperBorderSide;
  
      // prevent arrowElement from being placed not contiguously to its popper
      sideValue = Math.max(Math.min(popper[len] - arrowElementSize, sideValue), 0);
  
      data.arrowElement = arrowElement;
      data.offsets.arrow = (_data$offsets$arrow = {}, defineProperty(_data$offsets$arrow, side, Math.round(sideValue)), defineProperty(_data$offsets$arrow, altSide, ''), _data$offsets$arrow);
  
      return data;
    }
  
    /**
     * Get the opposite placement variation of the given one
     * @method
     * @memberof Popper.Utils
     * @argument {String} placement variation
     * @returns {String} flipped placement variation
     */
    function getOppositeVariation(variation) {
      if (variation === 'end') {
        return 'start';
      } else if (variation === 'start') {
        return 'end';
      }
      return variation;
    }
  
    /**
     * List of accepted placements to use as values of the `placement` option.<br />
     * Valid placements are:
     * - `auto`
     * - `top`
     * - `right`
     * - `bottom`
     * - `left`
     *
     * Each placement can have a variation from this list:
     * - `-start`
     * - `-end`
     *
     * Variations are interpreted easily if you think of them as the left to right
     * written languages. Horizontally (`top` and `bottom`), `start` is left and `end`
     * is right.<br />
     * Vertically (`left` and `right`), `start` is top and `end` is bottom.
     *
     * Some valid examples are:
     * - `top-end` (on top of reference, right aligned)
     * - `right-start` (on right of reference, top aligned)
     * - `bottom` (on bottom, centered)
     * - `auto-end` (on the side with more space available, alignment depends by placement)
     *
     * @static
     * @type {Array}
     * @enum {String}
     * @readonly
     * @method placements
     * @memberof Popper
     */
    var placements = ['auto-start', 'auto', 'auto-end', 'top-start', 'top', 'top-end', 'right-start', 'right', 'right-end', 'bottom-end', 'bottom', 'bottom-start', 'left-end', 'left', 'left-start'];
  
    // Get rid of `auto` `auto-start` and `auto-end`
    var validPlacements = placements.slice(3);
  
    /**
     * Given an initial placement, returns all the subsequent placements
     * clockwise (or counter-clockwise).
     *
     * @method
     * @memberof Popper.Utils
     * @argument {String} placement - A valid placement (it accepts variations)
     * @argument {Boolean} counter - Set to true to walk the placements counterclockwise
     * @returns {Array} placements including their variations
     */
    function clockwise(placement) {
      var counter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
  
      var index = validPlacements.indexOf(placement);
      var arr = validPlacements.slice(index + 1).concat(validPlacements.slice(0, index));
      return counter ? arr.reverse() : arr;
    }
  
    var BEHAVIORS = {
      FLIP: 'flip',
      CLOCKWISE: 'clockwise',
      COUNTERCLOCKWISE: 'counterclockwise'
    };
  
    /**
     * @function
     * @memberof Modifiers
     * @argument {Object} data - The data object generated by update method
     * @argument {Object} options - Modifiers configuration and options
     * @returns {Object} The data object, properly modified
     */
    function flip(data, options) {
      // if `inner` modifier is enabled, we can't use the `flip` modifier
      if (isModifierEnabled(data.instance.modifiers, 'inner')) {
        return data;
      }
  
      if (data.flipped && data.placement === data.originalPlacement) {
        // seems like flip is trying to loop, probably there's not enough space on any of the flippable sides
        return data;
      }
  
      var boundaries = getBoundaries(data.instance.popper, data.instance.reference, options.padding, options.boundariesElement, data.positionFixed);
  
      var placement = data.placement.split('-')[0];
      var placementOpposite = getOppositePlacement(placement);
      var variation = data.placement.split('-')[1] || '';
  
      var flipOrder = [];
  
      switch (options.behavior) {
        case BEHAVIORS.FLIP:
          flipOrder = [placement, placementOpposite];
          break;
        case BEHAVIORS.CLOCKWISE:
          flipOrder = clockwise(placement);
          break;
        case BEHAVIORS.COUNTERCLOCKWISE:
          flipOrder = clockwise(placement, true);
          break;
        default:
          flipOrder = options.behavior;
      }
  
      flipOrder.forEach(function (step, index) {
        if (placement !== step || flipOrder.length === index + 1) {
          return data;
        }
  
        placement = data.placement.split('-')[0];
        placementOpposite = getOppositePlacement(placement);
  
        var popperOffsets = data.offsets.popper;
        var refOffsets = data.offsets.reference;
  
        // using floor because the reference offsets may contain decimals we are not going to consider here
        var floor = Math.floor;
        var overlapsRef = placement === 'left' && floor(popperOffsets.right) > floor(refOffsets.left) || placement === 'right' && floor(popperOffsets.left) < floor(refOffsets.right) || placement === 'top' && floor(popperOffsets.bottom) > floor(refOffsets.top) || placement === 'bottom' && floor(popperOffsets.top) < floor(refOffsets.bottom);
  
        var overflowsLeft = floor(popperOffsets.left) < floor(boundaries.left);
        var overflowsRight = floor(popperOffsets.right) > floor(boundaries.right);
        var overflowsTop = floor(popperOffsets.top) < floor(boundaries.top);
        var overflowsBottom = floor(popperOffsets.bottom) > floor(boundaries.bottom);
  
        var overflowsBoundaries = placement === 'left' && overflowsLeft || placement === 'right' && overflowsRight || placement === 'top' && overflowsTop || placement === 'bottom' && overflowsBottom;
  
        // flip the variation if required
        var isVertical = ['top', 'bottom'].indexOf(placement) !== -1;
        var flippedVariation = !!options.flipVariations && (isVertical && variation === 'start' && overflowsLeft || isVertical && variation === 'end' && overflowsRight || !isVertical && variation === 'start' && overflowsTop || !isVertical && variation === 'end' && overflowsBottom);
  
        if (overlapsRef || overflowsBoundaries || flippedVariation) {
          // this boolean to detect any flip loop
          data.flipped = true;
  
          if (overlapsRef || overflowsBoundaries) {
            placement = flipOrder[index + 1];
          }
  
          if (flippedVariation) {
            variation = getOppositeVariation(variation);
          }
  
          data.placement = placement + (variation ? '-' + variation : '');
  
          // this object contains `position`, we want to preserve it along with
          // any additional property we may add in the future
          data.offsets.popper = _extends({}, data.offsets.popper, getPopperOffsets(data.instance.popper, data.offsets.reference, data.placement));
  
          data = runModifiers(data.instance.modifiers, data, 'flip');
        }
      });
      return data;
    }
  
    /**
     * @function
     * @memberof Modifiers
     * @argument {Object} data - The data object generated by update method
     * @argument {Object} options - Modifiers configuration and options
     * @returns {Object} The data object, properly modified
     */
    function keepTogether(data) {
      var _data$offsets = data.offsets,
          popper = _data$offsets.popper,
          reference = _data$offsets.reference;
  
      var placement = data.placement.split('-')[0];
      var floor = Math.floor;
      var isVertical = ['top', 'bottom'].indexOf(placement) !== -1;
      var side = isVertical ? 'right' : 'bottom';
      var opSide = isVertical ? 'left' : 'top';
      var measurement = isVertical ? 'width' : 'height';
  
      if (popper[side] < floor(reference[opSide])) {
        data.offsets.popper[opSide] = floor(reference[opSide]) - popper[measurement];
      }
      if (popper[opSide] > floor(reference[side])) {
        data.offsets.popper[opSide] = floor(reference[side]);
      }
  
      return data;
    }
  
    /**
     * Converts a string containing value + unit into a px value number
     * @function
     * @memberof {modifiers~offset}
     * @private
     * @argument {String} str - Value + unit string
     * @argument {String} measurement - `height` or `width`
     * @argument {Object} popperOffsets
     * @argument {Object} referenceOffsets
     * @returns {Number|String}
     * Value in pixels, or original string if no values were extracted
     */
    function toValue(str, measurement, popperOffsets, referenceOffsets) {
      // separate value from unit
      var split = str.match(/((?:\-|\+)?\d*\.?\d*)(.*)/);
      var value = +split[1];
      var unit = split[2];
  
      // If it's not a number it's an operator, I guess
      if (!value) {
        return str;
      }
  
      if (unit.indexOf('%') === 0) {
        var element = void 0;
        switch (unit) {
          case '%p':
            element = popperOffsets;
            break;
          case '%':
          case '%r':
          default:
            element = referenceOffsets;
        }
  
        var rect = getClientRect(element);
        return rect[measurement] / 100 * value;
      } else if (unit === 'vh' || unit === 'vw') {
        // if is a vh or vw, we calculate the size based on the viewport
        var size = void 0;
        if (unit === 'vh') {
          size = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
        } else {
          size = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
        }
        return size / 100 * value;
      } else {
        // if is an explicit pixel unit, we get rid of the unit and keep the value
        // if is an implicit unit, it's px, and we return just the value
        return value;
      }
    }
  
    /**
     * Parse an `offset` string to extrapolate `x` and `y` numeric offsets.
     * @function
     * @memberof {modifiers~offset}
     * @private
     * @argument {String} offset
     * @argument {Object} popperOffsets
     * @argument {Object} referenceOffsets
     * @argument {String} basePlacement
     * @returns {Array} a two cells array with x and y offsets in numbers
     */
    function parseOffset(offset, popperOffsets, referenceOffsets, basePlacement) {
      var offsets = [0, 0];
  
      // Use height if placement is left or right and index is 0 otherwise use width
      // in this way the first offset will use an axis and the second one
      // will use the other one
      var useHeight = ['right', 'left'].indexOf(basePlacement) !== -1;
  
      // Split the offset string to obtain a list of values and operands
      // The regex addresses values with the plus or minus sign in front (+10, -20, etc)
      var fragments = offset.split(/(\+|\-)/).map(function (frag) {
        return frag.trim();
      });
  
      // Detect if the offset string contains a pair of values or a single one
      // they could be separated by comma or space
      var divider = fragments.indexOf(find(fragments, function (frag) {
        return frag.search(/,|\s/) !== -1;
      }));
  
      if (fragments[divider] && fragments[divider].indexOf(',') === -1) {
        console.warn('Offsets separated by white space(s) are deprecated, use a comma (,) instead.');
      }
  
      // If divider is found, we divide the list of values and operands to divide
      // them by ofset X and Y.
      var splitRegex = /\s*,\s*|\s+/;
      var ops = divider !== -1 ? [fragments.slice(0, divider).concat([fragments[divider].split(splitRegex)[0]]), [fragments[divider].split(splitRegex)[1]].concat(fragments.slice(divider + 1))] : [fragments];
  
      // Convert the values with units to absolute pixels to allow our computations
      ops = ops.map(function (op, index) {
        // Most of the units rely on the orientation of the popper
        var measurement = (index === 1 ? !useHeight : useHeight) ? 'height' : 'width';
        var mergeWithPrevious = false;
        return op
        // This aggregates any `+` or `-` sign that aren't considered operators
        // e.g.: 10 + +5 => [10, +, +5]
        .reduce(function (a, b) {
          if (a[a.length - 1] === '' && ['+', '-'].indexOf(b) !== -1) {
            a[a.length - 1] = b;
            mergeWithPrevious = true;
            return a;
          } else if (mergeWithPrevious) {
            a[a.length - 1] += b;
            mergeWithPrevious = false;
            return a;
          } else {
            return a.concat(b);
          }
        }, [])
        // Here we convert the string values into number values (in px)
        .map(function (str) {
          return toValue(str, measurement, popperOffsets, referenceOffsets);
        });
      });
  
      // Loop trough the offsets arrays and execute the operations
      ops.forEach(function (op, index) {
        op.forEach(function (frag, index2) {
          if (isNumeric(frag)) {
            offsets[index] += frag * (op[index2 - 1] === '-' ? -1 : 1);
          }
        });
      });
      return offsets;
    }
  
    /**
     * @function
     * @memberof Modifiers
     * @argument {Object} data - The data object generated by update method
     * @argument {Object} options - Modifiers configuration and options
     * @argument {Number|String} options.offset=0
     * The offset value as described in the modifier description
     * @returns {Object} The data object, properly modified
     */
    function offset(data, _ref) {
      var offset = _ref.offset;
      var placement = data.placement,
          _data$offsets = data.offsets,
          popper = _data$offsets.popper,
          reference = _data$offsets.reference;
  
      var basePlacement = placement.split('-')[0];
  
      var offsets = void 0;
      if (isNumeric(+offset)) {
        offsets = [+offset, 0];
      } else {
        offsets = parseOffset(offset, popper, reference, basePlacement);
      }
  
      if (basePlacement === 'left') {
        popper.top += offsets[0];
        popper.left -= offsets[1];
      } else if (basePlacement === 'right') {
        popper.top += offsets[0];
        popper.left += offsets[1];
      } else if (basePlacement === 'top') {
        popper.left += offsets[0];
        popper.top -= offsets[1];
      } else if (basePlacement === 'bottom') {
        popper.left += offsets[0];
        popper.top += offsets[1];
      }
  
      data.popper = popper;
      return data;
    }
  
    /**
     * @function
     * @memberof Modifiers
     * @argument {Object} data - The data object generated by `update` method
     * @argument {Object} options - Modifiers configuration and options
     * @returns {Object} The data object, properly modified
     */
    function preventOverflow(data, options) {
      var boundariesElement = options.boundariesElement || getOffsetParent(data.instance.popper);
  
      // If offsetParent is the reference element, we really want to
      // go one step up and use the next offsetParent as reference to
      // avoid to make this modifier completely useless and look like broken
      if (data.instance.reference === boundariesElement) {
        boundariesElement = getOffsetParent(boundariesElement);
      }
  
      // NOTE: DOM access here
      // resets the popper's position so that the document size can be calculated excluding
      // the size of the popper element itself
      var transformProp = getSupportedPropertyName('transform');
      var popperStyles = data.instance.popper.style; // assignment to help minification
      var top = popperStyles.top,
          left = popperStyles.left,
          transform = popperStyles[transformProp];
  
      popperStyles.top = '';
      popperStyles.left = '';
      popperStyles[transformProp] = '';
  
      var boundaries = getBoundaries(data.instance.popper, data.instance.reference, options.padding, boundariesElement, data.positionFixed);
  
      // NOTE: DOM access here
      // restores the original style properties after the offsets have been computed
      popperStyles.top = top;
      popperStyles.left = left;
      popperStyles[transformProp] = transform;
  
      options.boundaries = boundaries;
  
      var order = options.priority;
      var popper = data.offsets.popper;
  
      var check = {
        primary: function primary(placement) {
          var value = popper[placement];
          if (popper[placement] < boundaries[placement] && !options.escapeWithReference) {
            value = Math.max(popper[placement], boundaries[placement]);
          }
          return defineProperty({}, placement, value);
        },
        secondary: function secondary(placement) {
          var mainSide = placement === 'right' ? 'left' : 'top';
          var value = popper[mainSide];
          if (popper[placement] > boundaries[placement] && !options.escapeWithReference) {
            value = Math.min(popper[mainSide], boundaries[placement] - (placement === 'right' ? popper.width : popper.height));
          }
          return defineProperty({}, mainSide, value);
        }
      };
  
      order.forEach(function (placement) {
        var side = ['left', 'top'].indexOf(placement) !== -1 ? 'primary' : 'secondary';
        popper = _extends({}, popper, check[side](placement));
      });
  
      data.offsets.popper = popper;
  
      return data;
    }
  
    /**
     * @function
     * @memberof Modifiers
     * @argument {Object} data - The data object generated by `update` method
     * @argument {Object} options - Modifiers configuration and options
     * @returns {Object} The data object, properly modified
     */
    function shift(data) {
      var placement = data.placement;
      var basePlacement = placement.split('-')[0];
      var shiftvariation = placement.split('-')[1];
  
      // if shift shiftvariation is specified, run the modifier
      if (shiftvariation) {
        var _data$offsets = data.offsets,
            reference = _data$offsets.reference,
            popper = _data$offsets.popper;
  
        var isVertical = ['bottom', 'top'].indexOf(basePlacement) !== -1;
        var side = isVertical ? 'left' : 'top';
        var measurement = isVertical ? 'width' : 'height';
  
        var shiftOffsets = {
          start: defineProperty({}, side, reference[side]),
          end: defineProperty({}, side, reference[side] + reference[measurement] - popper[measurement])
        };
  
        data.offsets.popper = _extends({}, popper, shiftOffsets[shiftvariation]);
      }
  
      return data;
    }
  
    /**
     * @function
     * @memberof Modifiers
     * @argument {Object} data - The data object generated by update method
     * @argument {Object} options - Modifiers configuration and options
     * @returns {Object} The data object, properly modified
     */
    function hide(data) {
      if (!isModifierRequired(data.instance.modifiers, 'hide', 'preventOverflow')) {
        return data;
      }
  
      var refRect = data.offsets.reference;
      var bound = find(data.instance.modifiers, function (modifier) {
        return modifier.name === 'preventOverflow';
      }).boundaries;
  
      if (refRect.bottom < bound.top || refRect.left > bound.right || refRect.top > bound.bottom || refRect.right < bound.left) {
        // Avoid unnecessary DOM access if visibility hasn't changed
        if (data.hide === true) {
          return data;
        }
  
        data.hide = true;
        data.attributes['x-out-of-boundaries'] = '';
      } else {
        // Avoid unnecessary DOM access if visibility hasn't changed
        if (data.hide === false) {
          return data;
        }
  
        data.hide = false;
        data.attributes['x-out-of-boundaries'] = false;
      }
  
      return data;
    }
  
    /**
     * @function
     * @memberof Modifiers
     * @argument {Object} data - The data object generated by `update` method
     * @argument {Object} options - Modifiers configuration and options
     * @returns {Object} The data object, properly modified
     */
    function inner(data) {
      var placement = data.placement;
      var basePlacement = placement.split('-')[0];
      var _data$offsets = data.offsets,
          popper = _data$offsets.popper,
          reference = _data$offsets.reference;
  
      var isHoriz = ['left', 'right'].indexOf(basePlacement) !== -1;
  
      var subtractLength = ['top', 'left'].indexOf(basePlacement) === -1;
  
      popper[isHoriz ? 'left' : 'top'] = reference[basePlacement] - (subtractLength ? popper[isHoriz ? 'width' : 'height'] : 0);
  
      data.placement = getOppositePlacement(placement);
      data.offsets.popper = getClientRect(popper);
  
      return data;
    }
  
    /**
     * Modifier function, each modifier can have a function of this type assigned
     * to its `fn` property.<br />
     * These functions will be called on each update, this means that you must
     * make sure they are performant enough to avoid performance bottlenecks.
     *
     * @function ModifierFn
     * @argument {dataObject} data - The data object generated by `update` method
     * @argument {Object} options - Modifiers configuration and options
     * @returns {dataObject} The data object, properly modified
     */
  
    /**
     * Modifiers are plugins used to alter the behavior of your poppers.<br />
     * Popper.js uses a set of 9 modifiers to provide all the basic functionalities
     * needed by the library.
     *
     * Usually you don't want to override the `order`, `fn` and `onLoad` props.
     * All the other properties are configurations that could be tweaked.
     * @namespace modifiers
     */
    var modifiers = {
      /**
       * Modifier used to shift the popper on the start or end of its reference
       * element.<br />
       * It will read the variation of the `placement` property.<br />
       * It can be one either `-end` or `-start`.
       * @memberof modifiers
       * @inner
       */
      shift: {
        /** @prop {number} order=100 - Index used to define the order of execution */
        order: 100,
        /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
        enabled: true,
        /** @prop {ModifierFn} */
        fn: shift
      },
  
      /**
       * The `offset` modifier can shift your popper on both its axis.
       *
       * It accepts the following units:
       * - `px` or unit-less, interpreted as pixels
       * - `%` or `%r`, percentage relative to the length of the reference element
       * - `%p`, percentage relative to the length of the popper element
       * - `vw`, CSS viewport width unit
       * - `vh`, CSS viewport height unit
       *
       * For length is intended the main axis relative to the placement of the popper.<br />
       * This means that if the placement is `top` or `bottom`, the length will be the
       * `width`. In case of `left` or `right`, it will be the `height`.
       *
       * You can provide a single value (as `Number` or `String`), or a pair of values
       * as `String` divided by a comma or one (or more) white spaces.<br />
       * The latter is a deprecated method because it leads to confusion and will be
       * removed in v2.<br />
       * Additionally, it accepts additions and subtractions between different units.
       * Note that multiplications and divisions aren't supported.
       *
       * Valid examples are:
       * ```
       * 10
       * '10%'
       * '10, 10'
       * '10%, 10'
       * '10 + 10%'
       * '10 - 5vh + 3%'
       * '-10px + 5vh, 5px - 6%'
       * ```
       * > **NB**: If you desire to apply offsets to your poppers in a way that may make them overlap
       * > with their reference element, unfortunately, you will have to disable the `flip` modifier.
       * > You can read more on this at this [issue](https://github.com/FezVrasta/popper.js/issues/373).
       *
       * @memberof modifiers
       * @inner
       */
      offset: {
        /** @prop {number} order=200 - Index used to define the order of execution */
        order: 200,
        /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
        enabled: true,
        /** @prop {ModifierFn} */
        fn: offset,
        /** @prop {Number|String} offset=0
         * The offset value as described in the modifier description
         */
        offset: 0
      },
  
      /**
       * Modifier used to prevent the popper from being positioned outside the boundary.
       *
       * A scenario exists where the reference itself is not within the boundaries.<br />
       * We can say it has "escaped the boundaries" — or just "escaped".<br />
       * In this case we need to decide whether the popper should either:
       *
       * - detach from the reference and remain "trapped" in the boundaries, or
       * - if it should ignore the boundary and "escape with its reference"
       *
       * When `escapeWithReference` is set to`true` and reference is completely
       * outside its boundaries, the popper will overflow (or completely leave)
       * the boundaries in order to remain attached to the edge of the reference.
       *
       * @memberof modifiers
       * @inner
       */
      preventOverflow: {
        /** @prop {number} order=300 - Index used to define the order of execution */
        order: 300,
        /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
        enabled: true,
        /** @prop {ModifierFn} */
        fn: preventOverflow,
        /**
         * @prop {Array} [priority=['left','right','top','bottom']]
         * Popper will try to prevent overflow following these priorities by default,
         * then, it could overflow on the left and on top of the `boundariesElement`
         */
        priority: ['left', 'right', 'top', 'bottom'],
        /**
         * @prop {number} padding=5
         * Amount of pixel used to define a minimum distance between the boundaries
         * and the popper. This makes sure the popper always has a little padding
         * between the edges of its container
         */
        padding: 5,
        /**
         * @prop {String|HTMLElement} boundariesElement='scrollParent'
         * Boundaries used by the modifier. Can be `scrollParent`, `window`,
         * `viewport` or any DOM element.
         */
        boundariesElement: 'scrollParent'
      },
  
      /**
       * Modifier used to make sure the reference and its popper stay near each other
       * without leaving any gap between the two. Especially useful when the arrow is
       * enabled and you want to ensure that it points to its reference element.
       * It cares only about the first axis. You can still have poppers with margin
       * between the popper and its reference element.
       * @memberof modifiers
       * @inner
       */
      keepTogether: {
        /** @prop {number} order=400 - Index used to define the order of execution */
        order: 400,
        /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
        enabled: true,
        /** @prop {ModifierFn} */
        fn: keepTogether
      },
  
      /**
       * This modifier is used to move the `arrowElement` of the popper to make
       * sure it is positioned between the reference element and its popper element.
       * It will read the outer size of the `arrowElement` node to detect how many
       * pixels of conjunction are needed.
       *
       * It has no effect if no `arrowElement` is provided.
       * @memberof modifiers
       * @inner
       */
      arrow: {
        /** @prop {number} order=500 - Index used to define the order of execution */
        order: 500,
        /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
        enabled: true,
        /** @prop {ModifierFn} */
        fn: arrow,
        /** @prop {String|HTMLElement} element='[x-arrow]' - Selector or node used as arrow */
        element: '[x-arrow]'
      },
  
      /**
       * Modifier used to flip the popper's placement when it starts to overlap its
       * reference element.
       *
       * Requires the `preventOverflow` modifier before it in order to work.
       *
       * **NOTE:** this modifier will interrupt the current update cycle and will
       * restart it if it detects the need to flip the placement.
       * @memberof modifiers
       * @inner
       */
      flip: {
        /** @prop {number} order=600 - Index used to define the order of execution */
        order: 600,
        /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
        enabled: true,
        /** @prop {ModifierFn} */
        fn: flip,
        /**
         * @prop {String|Array} behavior='flip'
         * The behavior used to change the popper's placement. It can be one of
         * `flip`, `clockwise`, `counterclockwise` or an array with a list of valid
         * placements (with optional variations)
         */
        behavior: 'flip',
        /**
         * @prop {number} padding=5
         * The popper will flip if it hits the edges of the `boundariesElement`
         */
        padding: 5,
        /**
         * @prop {String|HTMLElement} boundariesElement='viewport'
         * The element which will define the boundaries of the popper position.
         * The popper will never be placed outside of the defined boundaries
         * (except if `keepTogether` is enabled)
         */
        boundariesElement: 'viewport'
      },
  
      /**
       * Modifier used to make the popper flow toward the inner of the reference element.
       * By default, when this modifier is disabled, the popper will be placed outside
       * the reference element.
       * @memberof modifiers
       * @inner
       */
      inner: {
        /** @prop {number} order=700 - Index used to define the order of execution */
        order: 700,
        /** @prop {Boolean} enabled=false - Whether the modifier is enabled or not */
        enabled: false,
        /** @prop {ModifierFn} */
        fn: inner
      },
  
      /**
       * Modifier used to hide the popper when its reference element is outside of the
       * popper boundaries. It will set a `x-out-of-boundaries` attribute which can
       * be used to hide with a CSS selector the popper when its reference is
       * out of boundaries.
       *
       * Requires the `preventOverflow` modifier before it in order to work.
       * @memberof modifiers
       * @inner
       */
      hide: {
        /** @prop {number} order=800 - Index used to define the order of execution */
        order: 800,
        /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
        enabled: true,
        /** @prop {ModifierFn} */
        fn: hide
      },
  
      /**
       * Computes the style that will be applied to the popper element to gets
       * properly positioned.
       *
       * Note that this modifier will not touch the DOM, it just prepares the styles
       * so that `applyStyle` modifier can apply it. This separation is useful
       * in case you need to replace `applyStyle` with a custom implementation.
       *
       * This modifier has `850` as `order` value to maintain backward compatibility
       * with previous versions of Popper.js. Expect the modifiers ordering method
       * to change in future major versions of the library.
       *
       * @memberof modifiers
       * @inner
       */
      computeStyle: {
        /** @prop {number} order=850 - Index used to define the order of execution */
        order: 850,
        /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
        enabled: true,
        /** @prop {ModifierFn} */
        fn: computeStyle,
        /**
         * @prop {Boolean} gpuAcceleration=true
         * If true, it uses the CSS 3D transformation to position the popper.
         * Otherwise, it will use the `top` and `left` properties
         */
        gpuAcceleration: true,
        /**
         * @prop {string} [x='bottom']
         * Where to anchor the X axis (`bottom` or `top`). AKA X offset origin.
         * Change this if your popper should grow in a direction different from `bottom`
         */
        x: 'bottom',
        /**
         * @prop {string} [x='left']
         * Where to anchor the Y axis (`left` or `right`). AKA Y offset origin.
         * Change this if your popper should grow in a direction different from `right`
         */
        y: 'right'
      },
  
      /**
       * Applies the computed styles to the popper element.
       *
       * All the DOM manipulations are limited to this modifier. This is useful in case
       * you want to integrate Popper.js inside a framework or view library and you
       * want to delegate all the DOM manipulations to it.
       *
       * Note that if you disable this modifier, you must make sure the popper element
       * has its position set to `absolute` before Popper.js can do its work!
       *
       * Just disable this modifier and define your own to achieve the desired effect.
       *
       * @memberof modifiers
       * @inner
       */
      applyStyle: {
        /** @prop {number} order=900 - Index used to define the order of execution */
        order: 900,
        /** @prop {Boolean} enabled=true - Whether the modifier is enabled or not */
        enabled: true,
        /** @prop {ModifierFn} */
        fn: applyStyle,
        /** @prop {Function} */
        onLoad: applyStyleOnLoad,
        /**
         * @deprecated since version 1.10.0, the property moved to `computeStyle` modifier
         * @prop {Boolean} gpuAcceleration=true
         * If true, it uses the CSS 3D transformation to position the popper.
         * Otherwise, it will use the `top` and `left` properties
         */
        gpuAcceleration: undefined
      }
    };
  
    /**
     * The `dataObject` is an object containing all the information used by Popper.js.
     * This object is passed to modifiers and to the `onCreate` and `onUpdate` callbacks.
     * @name dataObject
     * @property {Object} data.instance The Popper.js instance
     * @property {String} data.placement Placement applied to popper
     * @property {String} data.originalPlacement Placement originally defined on init
     * @property {Boolean} data.flipped True if popper has been flipped by flip modifier
     * @property {Boolean} data.hide True if the reference element is out of boundaries, useful to know when to hide the popper
     * @property {HTMLElement} data.arrowElement Node used as arrow by arrow modifier
     * @property {Object} data.styles Any CSS property defined here will be applied to the popper. It expects the JavaScript nomenclature (eg. `marginBottom`)
     * @property {Object} data.arrowStyles Any CSS property defined here will be applied to the popper arrow. It expects the JavaScript nomenclature (eg. `marginBottom`)
     * @property {Object} data.boundaries Offsets of the popper boundaries
     * @property {Object} data.offsets The measurements of popper, reference and arrow elements
     * @property {Object} data.offsets.popper `top`, `left`, `width`, `height` values
     * @property {Object} data.offsets.reference `top`, `left`, `width`, `height` values
     * @property {Object} data.offsets.arrow] `top` and `left` offsets, only one of them will be different from 0
     */
  
    /**
     * Default options provided to Popper.js constructor.<br />
     * These can be overridden using the `options` argument of Popper.js.<br />
     * To override an option, simply pass an object with the same
     * structure of the `options` object, as the 3rd argument. For example:
     * ```
     * new Popper(ref, pop, {
     *   modifiers: {
     *     preventOverflow: { enabled: false }
     *   }
     * })
     * ```
     * @type {Object}
     * @static
     * @memberof Popper
     */
    var Defaults = {
      /**
       * Popper's placement.
       * @prop {Popper.placements} placement='bottom'
       */
      placement: 'bottom',
  
      /**
       * Set this to true if you want popper to position it self in 'fixed' mode
       * @prop {Boolean} positionFixed=false
       */
      positionFixed: false,
  
      /**
       * Whether events (resize, scroll) are initially enabled.
       * @prop {Boolean} eventsEnabled=true
       */
      eventsEnabled: true,
  
      /**
       * Set to true if you want to automatically remove the popper when
       * you call the `destroy` method.
       * @prop {Boolean} removeOnDestroy=false
       */
      removeOnDestroy: false,
  
      /**
       * Callback called when the popper is created.<br />
       * By default, it is set to no-op.<br />
       * Access Popper.js instance with `data.instance`.
       * @prop {onCreate}
       */
      onCreate: function onCreate() {},
  
      /**
       * Callback called when the popper is updated. This callback is not called
       * on the initialization/creation of the popper, but only on subsequent
       * updates.<br />
       * By default, it is set to no-op.<br />
       * Access Popper.js instance with `data.instance`.
       * @prop {onUpdate}
       */
      onUpdate: function onUpdate() {},
  
      /**
       * List of modifiers used to modify the offsets before they are applied to the popper.
       * They provide most of the functionalities of Popper.js.
       * @prop {modifiers}
       */
      modifiers: modifiers
    };
  
    /**
     * @callback onCreate
     * @param {dataObject} data
     */
  
    /**
     * @callback onUpdate
     * @param {dataObject} data
     */
  
    // Utils
    // Methods
    var Popper = function () {
      /**
       * Creates a new Popper.js instance.
       * @class Popper
       * @param {HTMLElement|referenceObject} reference - The reference element used to position the popper
       * @param {HTMLElement} popper - The HTML element used as the popper
       * @param {Object} options - Your custom options to override the ones defined in [Defaults](#defaults)
       * @return {Object} instance - The generated Popper.js instance
       */
      function Popper(reference, popper) {
        var _this = this;
  
        var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
        classCallCheck(this, Popper);
  
        this.scheduleUpdate = function () {
          return requestAnimationFrame(_this.update);
        };
  
        // make update() debounced, so that it only runs at most once-per-tick
        this.update = debounce(this.update.bind(this));
  
        // with {} we create a new object with the options inside it
        this.options = _extends({}, Popper.Defaults, options);
  
        // init state
        this.state = {
          isDestroyed: false,
          isCreated: false,
          scrollParents: []
        };
  
        // get reference and popper elements (allow jQuery wrappers)
        this.reference = reference && reference.jquery ? reference[0] : reference;
        this.popper = popper && popper.jquery ? popper[0] : popper;
  
        // Deep merge modifiers options
        this.options.modifiers = {};
        Object.keys(_extends({}, Popper.Defaults.modifiers, options.modifiers)).forEach(function (name) {
          _this.options.modifiers[name] = _extends({}, Popper.Defaults.modifiers[name] || {}, options.modifiers ? options.modifiers[name] : {});
        });
  
        // Refactoring modifiers' list (Object => Array)
        this.modifiers = Object.keys(this.options.modifiers).map(function (name) {
          return _extends({
            name: name
          }, _this.options.modifiers[name]);
        })
        // sort the modifiers by order
        .sort(function (a, b) {
          return a.order - b.order;
        });
  
        // modifiers have the ability to execute arbitrary code when Popper.js get inited
        // such code is executed in the same order of its modifier
        // they could add new properties to their options configuration
        // BE AWARE: don't add options to `options.modifiers.name` but to `modifierOptions`!
        this.modifiers.forEach(function (modifierOptions) {
          if (modifierOptions.enabled && isFunction(modifierOptions.onLoad)) {
            modifierOptions.onLoad(_this.reference, _this.popper, _this.options, modifierOptions, _this.state);
          }
        });
  
        // fire the first update to position the popper in the right place
        this.update();
  
        var eventsEnabled = this.options.eventsEnabled;
        if (eventsEnabled) {
          // setup event listeners, they will take care of update the position in specific situations
          this.enableEventListeners();
        }
  
        this.state.eventsEnabled = eventsEnabled;
      }
  
      // We can't use class properties because they don't get listed in the
      // class prototype and break stuff like Sinon stubs
  
  
      createClass(Popper, [{
        key: 'update',
        value: function update$$1() {
          return update.call(this);
        }
      }, {
        key: 'destroy',
        value: function destroy$$1() {
          return destroy.call(this);
        }
      }, {
        key: 'enableEventListeners',
        value: function enableEventListeners$$1() {
          return enableEventListeners.call(this);
        }
      }, {
        key: 'disableEventListeners',
        value: function disableEventListeners$$1() {
          return disableEventListeners.call(this);
        }
  
        /**
         * Schedules an update. It will run on the next UI update available.
         * @method scheduleUpdate
         * @memberof Popper
         */
  
  
        /**
         * Collection of utilities useful when writing custom modifiers.
         * Starting from version 1.7, this method is available only if you
         * include `popper-utils.js` before `popper.js`.
         *
         * **DEPRECATION**: This way to access PopperUtils is deprecated
         * and will be removed in v2! Use the PopperUtils module directly instead.
         * Due to the high instability of the methods contained in Utils, we can't
         * guarantee them to follow semver. Use them at your own risk!
         * @static
         * @private
         * @type {Object}
         * @deprecated since version 1.8
         * @member Utils
         * @memberof Popper
         */
  
      }]);
      return Popper;
    }();
  
    /**
     * The `referenceObject` is an object that provides an interface compatible with Popper.js
     * and lets you use it as replacement of a real DOM node.<br />
     * You can use this method to position a popper relatively to a set of coordinates
     * in case you don't have a DOM node to use as reference.
     *
     * ```
     * new Popper(referenceObject, popperNode);
     * ```
     *
     * NB: This feature isn't supported in Internet Explorer 10.
     * @name referenceObject
     * @property {Function} data.getBoundingClientRect
     * A function that returns a set of coordinates compatible with the native `getBoundingClientRect` method.
     * @property {number} data.clientWidth
     * An ES6 getter that will return the width of the virtual reference element.
     * @property {number} data.clientHeight
     * An ES6 getter that will return the height of the virtual reference element.
     */
  
  
    Popper.Utils = (typeof window !== 'undefined' ? window : global).PopperUtils;
    Popper.placements = placements;
    Popper.Defaults = Defaults;
  
    /**
     * ------------------------------------------------------------------------
     * Constants
     * ------------------------------------------------------------------------
     */
  
    var NAME$4 = 'dropdown';
    var VERSION$4 = '4.3.1';
    var DATA_KEY$4 = 'bs.dropdown';
    var EVENT_KEY$4 = "." + DATA_KEY$4;
    var DATA_API_KEY$4 = '.data-api';
    var JQUERY_NO_CONFLICT$4 = $.fn[NAME$4];
    var ESCAPE_KEYCODE = 27; // KeyboardEvent.which value for Escape (Esc) key
  
    var SPACE_KEYCODE = 32; // KeyboardEvent.which value for space key
  
    var TAB_KEYCODE = 9; // KeyboardEvent.which value for tab key
  
    var ARROW_UP_KEYCODE = 38; // KeyboardEvent.which value for up arrow key
  
    var ARROW_DOWN_KEYCODE = 40; // KeyboardEvent.which value for down arrow key
  
    var RIGHT_MOUSE_BUTTON_WHICH = 3; // MouseEvent.which value for the right button (assuming a right-handed mouse)
  
    var REGEXP_KEYDOWN = new RegExp(ARROW_UP_KEYCODE + "|" + ARROW_DOWN_KEYCODE + "|" + ESCAPE_KEYCODE);
    var Event$4 = {
      HIDE: "hide" + EVENT_KEY$4,
      HIDDEN: "hidden" + EVENT_KEY$4,
      SHOW: "show" + EVENT_KEY$4,
      SHOWN: "shown" + EVENT_KEY$4,
      CLICK: "click" + EVENT_KEY$4,
      CLICK_DATA_API: "click" + EVENT_KEY$4 + DATA_API_KEY$4,
      KEYDOWN_DATA_API: "keydown" + EVENT_KEY$4 + DATA_API_KEY$4,
      KEYUP_DATA_API: "keyup" + EVENT_KEY$4 + DATA_API_KEY$4
    };
    var ClassName$4 = {
      DISABLED: 'disabled',
      SHOW: 'show',
      DROPUP: 'dropup',
      DROPRIGHT: 'dropright',
      DROPLEFT: 'dropleft',
      MENURIGHT: 'dropdown-menu-right',
      MENULEFT: 'dropdown-menu-left',
      POSITION_STATIC: 'position-static'
    };
    var Selector$4 = {
      DATA_TOGGLE: '[data-toggle="dropdown"]',
      FORM_CHILD: '.dropdown form',
      MENU: '.dropdown-menu',
      NAVBAR_NAV: '.navbar-nav',
      VISIBLE_ITEMS: '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)'
    };
    var AttachmentMap = {
      TOP: 'top-start',
      TOPEND: 'top-end',
      BOTTOM: 'bottom-start',
      BOTTOMEND: 'bottom-end',
      RIGHT: 'right-start',
      RIGHTEND: 'right-end',
      LEFT: 'left-start',
      LEFTEND: 'left-end'
    };
    var Default$2 = {
      offset: 0,
      flip: true,
      boundary: 'scrollParent',
      reference: 'toggle',
      display: 'dynamic'
    };
    var DefaultType$2 = {
      offset: '(number|string|function)',
      flip: 'boolean',
      boundary: '(string|element)',
      reference: '(string|element)',
      display: 'string'
      /**
       * ------------------------------------------------------------------------
       * Class Definition
       * ------------------------------------------------------------------------
       */
  
    };
  
    var Dropdown =
    /*#__PURE__*/
    function () {
      function Dropdown(element, config) {
        this._element = element;
        this._popper = null;
        this._config = this._getConfig(config);
        this._menu = this._getMenuElement();
        this._inNavbar = this._detectNavbar();
  
        this._addEventListeners();
      } // Getters
  
  
      var _proto = Dropdown.prototype;
  
      // Public
      _proto.toggle = function toggle() {
        if (this._element.disabled || $(this._element).hasClass(ClassName$4.DISABLED)) {
          return;
        }
  
        var parent = Dropdown._getParentFromElement(this._element);
  
        var isActive = $(this._menu).hasClass(ClassName$4.SHOW);
  
        Dropdown._clearMenus();
  
        if (isActive) {
          return;
        }
  
        var relatedTarget = {
          relatedTarget: this._element
        };
        var showEvent = $.Event(Event$4.SHOW, relatedTarget);
        $(parent).trigger(showEvent);
  
        if (showEvent.isDefaultPrevented()) {
          return;
        } // Disable totally Popper.js for Dropdown in Navbar
  
  
        if (!this._inNavbar) {
          /**
           * Check for Popper dependency
           * Popper - https://popper.js.org
           */
          if (typeof Popper === 'undefined') {
            throw new TypeError('Bootstrap\'s dropdowns require Popper.js (https://popper.js.org/)');
          }
  
          var referenceElement = this._element;
  
          if (this._config.reference === 'parent') {
            referenceElement = parent;
          } else if (Util.isElement(this._config.reference)) {
            referenceElement = this._config.reference; // Check if it's jQuery element
  
            if (typeof this._config.reference.jquery !== 'undefined') {
              referenceElement = this._config.reference[0];
            }
          } // If boundary is not `scrollParent`, then set position to `static`
          // to allow the menu to "escape" the scroll parent's boundaries
          // https://github.com/twbs/bootstrap/issues/24251
  
  
          if (this._config.boundary !== 'scrollParent') {
            $(parent).addClass(ClassName$4.POSITION_STATIC);
          }
  
          this._popper = new Popper(referenceElement, this._menu, this._getPopperConfig());
        } // If this is a touch-enabled device we add extra
        // empty mouseover listeners to the body's immediate children;
        // only needed because of broken event delegation on iOS
        // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
  
  
        if ('ontouchstart' in document.documentElement && $(parent).closest(Selector$4.NAVBAR_NAV).length === 0) {
          $(document.body).children().on('mouseover', null, $.noop);
        }
  
        this._element.focus();
  
        this._element.setAttribute('aria-expanded', true);
  
        $(this._menu).toggleClass(ClassName$4.SHOW);
        $(parent).toggleClass(ClassName$4.SHOW).trigger($.Event(Event$4.SHOWN, relatedTarget));
      };
  
      _proto.show = function show() {
        if (this._element.disabled || $(this._element).hasClass(ClassName$4.DISABLED) || $(this._menu).hasClass(ClassName$4.SHOW)) {
          return;
        }
  
        var relatedTarget = {
          relatedTarget: this._element
        };
        var showEvent = $.Event(Event$4.SHOW, relatedTarget);
  
        var parent = Dropdown._getParentFromElement(this._element);
  
        $(parent).trigger(showEvent);
  
        if (showEvent.isDefaultPrevented()) {
          return;
        }
  
        $(this._menu).toggleClass(ClassName$4.SHOW);
        $(parent).toggleClass(ClassName$4.SHOW).trigger($.Event(Event$4.SHOWN, relatedTarget));
      };
  
      _proto.hide = function hide() {
        if (this._element.disabled || $(this._element).hasClass(ClassName$4.DISABLED) || !$(this._menu).hasClass(ClassName$4.SHOW)) {
          return;
        }
  
        var relatedTarget = {
          relatedTarget: this._element
        };
        var hideEvent = $.Event(Event$4.HIDE, relatedTarget);
  
        var parent = Dropdown._getParentFromElement(this._element);
  
        $(parent).trigger(hideEvent);
  
        if (hideEvent.isDefaultPrevented()) {
          return;
        }
  
        $(this._menu).toggleClass(ClassName$4.SHOW);
        $(parent).toggleClass(ClassName$4.SHOW).trigger($.Event(Event$4.HIDDEN, relatedTarget));
      };
  
      _proto.dispose = function dispose() {
        $.removeData(this._element, DATA_KEY$4);
        $(this._element).off(EVENT_KEY$4);
        this._element = null;
        this._menu = null;
  
        if (this._popper !== null) {
          this._popper.destroy();
  
          this._popper = null;
        }
      };
  
      _proto.update = function update() {
        this._inNavbar = this._detectNavbar();
  
        if (this._popper !== null) {
          this._popper.scheduleUpdate();
        }
      } // Private
      ;
  
      _proto._addEventListeners = function _addEventListeners() {
        var _this = this;
  
        $(this._element).on(Event$4.CLICK, function (event) {
          event.preventDefault();
          event.stopPropagation();
  
          _this.toggle();
        });
      };
  
      _proto._getConfig = function _getConfig(config) {
        config = _objectSpread({}, this.constructor.Default, $(this._element).data(), config);
        Util.typeCheckConfig(NAME$4, config, this.constructor.DefaultType);
        return config;
      };
  
      _proto._getMenuElement = function _getMenuElement() {
        if (!this._menu) {
          var parent = Dropdown._getParentFromElement(this._element);
  
          if (parent) {
            this._menu = parent.querySelector(Selector$4.MENU);
          }
        }
  
        return this._menu;
      };
  
      _proto._getPlacement = function _getPlacement() {
        var $parentDropdown = $(this._element.parentNode);
        var placement = AttachmentMap.BOTTOM; // Handle dropup
  
        if ($parentDropdown.hasClass(ClassName$4.DROPUP)) {
          placement = AttachmentMap.TOP;
  
          if ($(this._menu).hasClass(ClassName$4.MENURIGHT)) {
            placement = AttachmentMap.TOPEND;
          }
        } else if ($parentDropdown.hasClass(ClassName$4.DROPRIGHT)) {
          placement = AttachmentMap.RIGHT;
        } else if ($parentDropdown.hasClass(ClassName$4.DROPLEFT)) {
          placement = AttachmentMap.LEFT;
        } else if ($(this._menu).hasClass(ClassName$4.MENURIGHT)) {
          placement = AttachmentMap.BOTTOMEND;
        }
  
        return placement;
      };
  
      _proto._detectNavbar = function _detectNavbar() {
        return $(this._element).closest('.navbar').length > 0;
      };
  
      _proto._getOffset = function _getOffset() {
        var _this2 = this;
  
        var offset = {};
  
        if (typeof this._config.offset === 'function') {
          offset.fn = function (data) {
            data.offsets = _objectSpread({}, data.offsets, _this2._config.offset(data.offsets, _this2._element) || {});
            return data;
          };
        } else {
          offset.offset = this._config.offset;
        }
  
        return offset;
      };
  
      _proto._getPopperConfig = function _getPopperConfig() {
        var popperConfig = {
          placement: this._getPlacement(),
          modifiers: {
            offset: this._getOffset(),
            flip: {
              enabled: this._config.flip
            },
            preventOverflow: {
              boundariesElement: this._config.boundary
            }
          } // Disable Popper.js if we have a static display
  
        };
  
        if (this._config.display === 'static') {
          popperConfig.modifiers.applyStyle = {
            enabled: false
          };
        }
  
        return popperConfig;
      } // Static
      ;
  
      Dropdown._jQueryInterface = function _jQueryInterface(config) {
        return this.each(function () {
          var data = $(this).data(DATA_KEY$4);
  
          var _config = typeof config === 'object' ? config : null;
  
          if (!data) {
            data = new Dropdown(this, _config);
            $(this).data(DATA_KEY$4, data);
          }
  
          if (typeof config === 'string') {
            if (typeof data[config] === 'undefined') {
              throw new TypeError("No method named \"" + config + "\"");
            }
  
            data[config]();
          }
        });
      };
  
      Dropdown._clearMenus = function _clearMenus(event) {
        if (event && (event.which === RIGHT_MOUSE_BUTTON_WHICH || event.type === 'keyup' && event.which !== TAB_KEYCODE)) {
          return;
        }
  
        var toggles = [].slice.call(document.querySelectorAll(Selector$4.DATA_TOGGLE));
  
        for (var i = 0, len = toggles.length; i < len; i++) {
          var parent = Dropdown._getParentFromElement(toggles[i]);
  
          var context = $(toggles[i]).data(DATA_KEY$4);
          var relatedTarget = {
            relatedTarget: toggles[i]
          };
  
          if (event && event.type === 'click') {
            relatedTarget.clickEvent = event;
          }
  
          if (!context) {
            continue;
          }
  
          var dropdownMenu = context._menu;
  
          if (!$(parent).hasClass(ClassName$4.SHOW)) {
            continue;
          }
  
          if (event && (event.type === 'click' && /input|textarea/i.test(event.target.tagName) || event.type === 'keyup' && event.which === TAB_KEYCODE) && $.contains(parent, event.target)) {
            continue;
          }
  
          var hideEvent = $.Event(Event$4.HIDE, relatedTarget);
          $(parent).trigger(hideEvent);
  
          if (hideEvent.isDefaultPrevented()) {
            continue;
          } // If this is a touch-enabled device we remove the extra
          // empty mouseover listeners we added for iOS support
  
  
          if ('ontouchstart' in document.documentElement) {
            $(document.body).children().off('mouseover', null, $.noop);
          }
  
          toggles[i].setAttribute('aria-expanded', 'false');
          $(dropdownMenu).removeClass(ClassName$4.SHOW);
          $(parent).removeClass(ClassName$4.SHOW).trigger($.Event(Event$4.HIDDEN, relatedTarget));
        }
      };
  
      Dropdown._getParentFromElement = function _getParentFromElement(element) {
        var parent;
        var selector = Util.getSelectorFromElement(element);
  
        if (selector) {
          parent = document.querySelector(selector);
        }
  
        return parent || element.parentNode;
      } // eslint-disable-next-line complexity
      ;
  
      Dropdown._dataApiKeydownHandler = function _dataApiKeydownHandler(event) {
        // If not input/textarea:
        //  - And not a key in REGEXP_KEYDOWN => not a dropdown command
        // If input/textarea:
        //  - If space key => not a dropdown command
        //  - If key is other than escape
        //    - If key is not up or down => not a dropdown command
        //    - If trigger inside the menu => not a dropdown command
        if (/input|textarea/i.test(event.target.tagName) ? event.which === SPACE_KEYCODE || event.which !== ESCAPE_KEYCODE && (event.which !== ARROW_DOWN_KEYCODE && event.which !== ARROW_UP_KEYCODE || $(event.target).closest(Selector$4.MENU).length) : !REGEXP_KEYDOWN.test(event.which)) {
          return;
        }
  
        event.preventDefault();
        event.stopPropagation();
  
        if (this.disabled || $(this).hasClass(ClassName$4.DISABLED)) {
          return;
        }
  
        var parent = Dropdown._getParentFromElement(this);
  
        var isActive = $(parent).hasClass(ClassName$4.SHOW);
  
        if (!isActive || isActive && (event.which === ESCAPE_KEYCODE || event.which === SPACE_KEYCODE)) {
          if (event.which === ESCAPE_KEYCODE) {
            var toggle = parent.querySelector(Selector$4.DATA_TOGGLE);
            $(toggle).trigger('focus');
          }
  
          $(this).trigger('click');
          return;
        }
  
        var items = [].slice.call(parent.querySelectorAll(Selector$4.VISIBLE_ITEMS));
  
        if (items.length === 0) {
          return;
        }
  
        var index = items.indexOf(event.target);
  
        if (event.which === ARROW_UP_KEYCODE && index > 0) {
          // Up
          index--;
        }
  
        if (event.which === ARROW_DOWN_KEYCODE && index < items.length - 1) {
          // Down
          index++;
        }
  
        if (index < 0) {
          index = 0;
        }
  
        items[index].focus();
      };
  
      _createClass(Dropdown, null, [{
        key: "VERSION",
        get: function get() {
          return VERSION$4;
        }
      }, {
        key: "Default",
        get: function get() {
          return Default$2;
        }
      }, {
        key: "DefaultType",
        get: function get() {
          return DefaultType$2;
        }
      }]);
  
      return Dropdown;
    }();
    /**
     * ------------------------------------------------------------------------
     * Data Api implementation
     * ------------------------------------------------------------------------
     */
  
  
    $(document).on(Event$4.KEYDOWN_DATA_API, Selector$4.DATA_TOGGLE, Dropdown._dataApiKeydownHandler).on(Event$4.KEYDOWN_DATA_API, Selector$4.MENU, Dropdown._dataApiKeydownHandler).on(Event$4.CLICK_DATA_API + " " + Event$4.KEYUP_DATA_API, Dropdown._clearMenus).on(Event$4.CLICK_DATA_API, Selector$4.DATA_TOGGLE, function (event) {
      event.preventDefault();
      event.stopPropagation();
  
      Dropdown._jQueryInterface.call($(this), 'toggle');
    }).on(Event$4.CLICK_DATA_API, Selector$4.FORM_CHILD, function (e) {
      e.stopPropagation();
    });
    /**
     * ------------------------------------------------------------------------
     * jQuery
     * ------------------------------------------------------------------------
     */
  
    $.fn[NAME$4] = Dropdown._jQueryInterface;
    $.fn[NAME$4].Constructor = Dropdown;
  
    $.fn[NAME$4].noConflict = function () {
      $.fn[NAME$4] = JQUERY_NO_CONFLICT$4;
      return Dropdown._jQueryInterface;
    };
  
    /**
     * ------------------------------------------------------------------------
     * Constants
     * ------------------------------------------------------------------------
     */
  
    var NAME$5 = 'modal';
    var VERSION$5 = '4.3.1';
    var DATA_KEY$5 = 'bs.modal';
    var EVENT_KEY$5 = "." + DATA_KEY$5;
    var DATA_API_KEY$5 = '.data-api';
    var JQUERY_NO_CONFLICT$5 = $.fn[NAME$5];
    var ESCAPE_KEYCODE$1 = 27; // KeyboardEvent.which value for Escape (Esc) key
  
    var Default$3 = {
      backdrop: true,
      keyboard: true,
      focus: true,
      show: true
    };
    var DefaultType$3 = {
      backdrop: '(boolean|string)',
      keyboard: 'boolean',
      focus: 'boolean',
      show: 'boolean'
    };
    var Event$5 = {
      HIDE: "hide" + EVENT_KEY$5,
      HIDDEN: "hidden" + EVENT_KEY$5,
      SHOW: "show" + EVENT_KEY$5,
      SHOWN: "shown" + EVENT_KEY$5,
      FOCUSIN: "focusin" + EVENT_KEY$5,
      RESIZE: "resize" + EVENT_KEY$5,
      CLICK_DISMISS: "click.dismiss" + EVENT_KEY$5,
      KEYDOWN_DISMISS: "keydown.dismiss" + EVENT_KEY$5,
      MOUSEUP_DISMISS: "mouseup.dismiss" + EVENT_KEY$5,
      MOUSEDOWN_DISMISS: "mousedown.dismiss" + EVENT_KEY$5,
      CLICK_DATA_API: "click" + EVENT_KEY$5 + DATA_API_KEY$5
    };
    var ClassName$5 = {
      SCROLLABLE: 'modal-dialog-scrollable',
      SCROLLBAR_MEASURER: 'modal-scrollbar-measure',
      BACKDROP: 'modal-backdrop',
      OPEN: 'modal-open',
      FADE: 'fade',
      SHOW: 'show'
    };
    var Selector$5 = {
      DIALOG: '.modal-dialog',
      MODAL_BODY: '.modal-body',
      DATA_TOGGLE: '[data-toggle="modal"]',
      DATA_DISMISS: '[data-dismiss="modal"]',
      FIXED_CONTENT: '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top',
      STICKY_CONTENT: '.sticky-top'
      /**
       * ------------------------------------------------------------------------
       * Class Definition
       * ------------------------------------------------------------------------
       */
  
    };
  
    var Modal =
    /*#__PURE__*/
    function () {
      function Modal(element, config) {
        this._config = this._getConfig(config);
        this._element = element;
        this._dialog = element.querySelector(Selector$5.DIALOG);
        this._backdrop = null;
        this._isShown = false;
        this._isBodyOverflowing = false;
        this._ignoreBackdropClick = false;
        this._isTransitioning = false;
        this._scrollbarWidth = 0;
      } // Getters
  
  
      var _proto = Modal.prototype;
  
      // Public
      _proto.toggle = function toggle(relatedTarget) {
        return this._isShown ? this.hide() : this.show(relatedTarget);
      };
  
      _proto.show = function show(relatedTarget) {
        var _this = this;
  
        if (this._isShown || this._isTransitioning) {
          return;
        }
  
        if ($(this._element).hasClass(ClassName$5.FADE)) {
          this._isTransitioning = true;
        }
  
        var showEvent = $.Event(Event$5.SHOW, {
          relatedTarget: relatedTarget
        });
        $(this._element).trigger(showEvent);
  
        if (this._isShown || showEvent.isDefaultPrevented()) {
          return;
        }
  
        this._isShown = true;
  
        this._checkScrollbar();
  
        this._setScrollbar();
  
        this._adjustDialog();
  
        this._setEscapeEvent();
  
        this._setResizeEvent();
  
        $(this._element).on(Event$5.CLICK_DISMISS, Selector$5.DATA_DISMISS, function (event) {
          return _this.hide(event);
        });
        $(this._dialog).on(Event$5.MOUSEDOWN_DISMISS, function () {
          $(_this._element).one(Event$5.MOUSEUP_DISMISS, function (event) {
            if ($(event.target).is(_this._element)) {
              _this._ignoreBackdropClick = true;
            }
          });
        });
  
        this._showBackdrop(function () {
          return _this._showElement(relatedTarget);
        });
      };
  
      _proto.hide = function hide(event) {
        var _this2 = this;
  
        if (event) {
          event.preventDefault();
        }
  
        if (!this._isShown || this._isTransitioning) {
          return;
        }
  
        var hideEvent = $.Event(Event$5.HIDE);
        $(this._element).trigger(hideEvent);
  
        if (!this._isShown || hideEvent.isDefaultPrevented()) {
          return;
        }
  
        this._isShown = false;
        var transition = $(this._element).hasClass(ClassName$5.FADE);
  
        if (transition) {
          this._isTransitioning = true;
        }
  
        this._setEscapeEvent();
  
        this._setResizeEvent();
  
        $(document).off(Event$5.FOCUSIN);
        $(this._element).removeClass(ClassName$5.SHOW);
        $(this._element).off(Event$5.CLICK_DISMISS);
        $(this._dialog).off(Event$5.MOUSEDOWN_DISMISS);
  
        if (transition) {
          var transitionDuration = Util.getTransitionDurationFromElement(this._element);
          $(this._element).one(Util.TRANSITION_END, function (event) {
            return _this2._hideModal(event);
          }).emulateTransitionEnd(transitionDuration);
        } else {
          this._hideModal();
        }
      };
  
      _proto.dispose = function dispose() {
        [window, this._element, this._dialog].forEach(function (htmlElement) {
          return $(htmlElement).off(EVENT_KEY$5);
        });
        /**
         * `document` has 2 events `Event.FOCUSIN` and `Event.CLICK_DATA_API`
         * Do not move `document` in `htmlElements` array
         * It will remove `Event.CLICK_DATA_API` event that should remain
         */
  
        $(document).off(Event$5.FOCUSIN);
        $.removeData(this._element, DATA_KEY$5);
        this._config = null;
        this._element = null;
        this._dialog = null;
        this._backdrop = null;
        this._isShown = null;
        this._isBodyOverflowing = null;
        this._ignoreBackdropClick = null;
        this._isTransitioning = null;
        this._scrollbarWidth = null;
      };
  
      _proto.handleUpdate = function handleUpdate() {
        this._adjustDialog();
      } // Private
      ;
  
      _proto._getConfig = function _getConfig(config) {
        config = _objectSpread({}, Default$3, config);
        Util.typeCheckConfig(NAME$5, config, DefaultType$3);
        return config;
      };
  
      _proto._showElement = function _showElement(relatedTarget) {
        var _this3 = this;
  
        var transition = $(this._element).hasClass(ClassName$5.FADE);
  
        if (!this._element.parentNode || this._element.parentNode.nodeType !== Node.ELEMENT_NODE) {
          // Don't move modal's DOM position
          document.body.appendChild(this._element);
        }
  
        this._element.style.display = 'block';
  
        this._element.removeAttribute('aria-hidden');
  
        this._element.setAttribute('aria-modal', true);
  
        if ($(this._dialog).hasClass(ClassName$5.SCROLLABLE)) {
          this._dialog.querySelector(Selector$5.MODAL_BODY).scrollTop = 0;
        } else {
          this._element.scrollTop = 0;
        }
  
        if (transition) {
          Util.reflow(this._element);
        }
  
        $(this._element).addClass(ClassName$5.SHOW);
  
        if (this._config.focus) {
          this._enforceFocus();
        }
  
        var shownEvent = $.Event(Event$5.SHOWN, {
          relatedTarget: relatedTarget
        });
  
        var transitionComplete = function transitionComplete() {
          if (_this3._config.focus) {
            _this3._element.focus();
          }
  
          _this3._isTransitioning = false;
          $(_this3._element).trigger(shownEvent);
        };
  
        if (transition) {
          var transitionDuration = Util.getTransitionDurationFromElement(this._dialog);
          $(this._dialog).one(Util.TRANSITION_END, transitionComplete).emulateTransitionEnd(transitionDuration);
        } else {
          transitionComplete();
        }
      };
  
      _proto._enforceFocus = function _enforceFocus() {
        var _this4 = this;
  
        $(document).off(Event$5.FOCUSIN) // Guard against infinite focus loop
        .on(Event$5.FOCUSIN, function (event) {
          if (document !== event.target && _this4._element !== event.target && $(_this4._element).has(event.target).length === 0) {
            _this4._element.focus();
          }
        });
      };
  
      _proto._setEscapeEvent = function _setEscapeEvent() {
        var _this5 = this;
  
        if (this._isShown && this._config.keyboard) {
          $(this._element).on(Event$5.KEYDOWN_DISMISS, function (event) {
            if (event.which === ESCAPE_KEYCODE$1) {
              event.preventDefault();
  
              _this5.hide();
            }
          });
        } else if (!this._isShown) {
          $(this._element).off(Event$5.KEYDOWN_DISMISS);
        }
      };
  
      _proto._setResizeEvent = function _setResizeEvent() {
        var _this6 = this;
  
        if (this._isShown) {
          $(window).on(Event$5.RESIZE, function (event) {
            return _this6.handleUpdate(event);
          });
        } else {
          $(window).off(Event$5.RESIZE);
        }
      };
  
      _proto._hideModal = function _hideModal() {
        var _this7 = this;
  
        this._element.style.display = 'none';
  
        this._element.setAttribute('aria-hidden', true);
  
        this._element.removeAttribute('aria-modal');
  
        this._isTransitioning = false;
  
        this._showBackdrop(function () {
          $(document.body).removeClass(ClassName$5.OPEN);
  
          _this7._resetAdjustments();
  
          _this7._resetScrollbar();
  
          $(_this7._element).trigger(Event$5.HIDDEN);
        });
      };
  
      _proto._removeBackdrop = function _removeBackdrop() {
        if (this._backdrop) {
          $(this._backdrop).remove();
          this._backdrop = null;
        }
      };
  
      _proto._showBackdrop = function _showBackdrop(callback) {
        var _this8 = this;
  
        var animate = $(this._element).hasClass(ClassName$5.FADE) ? ClassName$5.FADE : '';
  
        if (this._isShown && this._config.backdrop) {
          this._backdrop = document.createElement('div');
          this._backdrop.className = ClassName$5.BACKDROP;
  
          if (animate) {
            this._backdrop.classList.add(animate);
          }
  
          $(this._backdrop).appendTo(document.body);
          $(this._element).on(Event$5.CLICK_DISMISS, function (event) {
            if (_this8._ignoreBackdropClick) {
              _this8._ignoreBackdropClick = false;
              return;
            }
  
            if (event.target !== event.currentTarget) {
              return;
            }
  
            if (_this8._config.backdrop === 'static') {
              _this8._element.focus();
            } else {
              _this8.hide();
            }
          });
  
          if (animate) {
            Util.reflow(this._backdrop);
          }
  
          $(this._backdrop).addClass(ClassName$5.SHOW);
  
          if (!callback) {
            return;
          }
  
          if (!animate) {
            callback();
            return;
          }
  
          var backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop);
          $(this._backdrop).one(Util.TRANSITION_END, callback).emulateTransitionEnd(backdropTransitionDuration);
        } else if (!this._isShown && this._backdrop) {
          $(this._backdrop).removeClass(ClassName$5.SHOW);
  
          var callbackRemove = function callbackRemove() {
            _this8._removeBackdrop();
  
            if (callback) {
              callback();
            }
          };
  
          if ($(this._element).hasClass(ClassName$5.FADE)) {
            var _backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop);
  
            $(this._backdrop).one(Util.TRANSITION_END, callbackRemove).emulateTransitionEnd(_backdropTransitionDuration);
          } else {
            callbackRemove();
          }
        } else if (callback) {
          callback();
        }
      } // ----------------------------------------------------------------------
      // the following methods are used to handle overflowing modals
      // todo (fat): these should probably be refactored out of modal.js
      // ----------------------------------------------------------------------
      ;
  
      _proto._adjustDialog = function _adjustDialog() {
        var isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight;
  
        if (!this._isBodyOverflowing && isModalOverflowing) {
          this._element.style.paddingLeft = this._scrollbarWidth + "px";
        }
  
        if (this._isBodyOverflowing && !isModalOverflowing) {
          this._element.style.paddingRight = this._scrollbarWidth + "px";
        }
      };
  
      _proto._resetAdjustments = function _resetAdjustments() {
        this._element.style.paddingLeft = '';
        this._element.style.paddingRight = '';
      };
  
      _proto._checkScrollbar = function _checkScrollbar() {
        var rect = document.body.getBoundingClientRect();
        this._isBodyOverflowing = rect.left + rect.right < window.innerWidth;
        this._scrollbarWidth = this._getScrollbarWidth();
      };
  
      _proto._setScrollbar = function _setScrollbar() {
        var _this9 = this;
  
        if (this._isBodyOverflowing) {
          // Note: DOMNode.style.paddingRight returns the actual value or '' if not set
          //   while $(DOMNode).css('padding-right') returns the calculated value or 0 if not set
          var fixedContent = [].slice.call(document.querySelectorAll(Selector$5.FIXED_CONTENT));
          var stickyContent = [].slice.call(document.querySelectorAll(Selector$5.STICKY_CONTENT)); // Adjust fixed content padding
  
          $(fixedContent).each(function (index, element) {
            var actualPadding = element.style.paddingRight;
            var calculatedPadding = $(element).css('padding-right');
            $(element).data('padding-right', actualPadding).css('padding-right', parseFloat(calculatedPadding) + _this9._scrollbarWidth + "px");
          }); // Adjust sticky content margin
  
          $(stickyContent).each(function (index, element) {
            var actualMargin = element.style.marginRight;
            var calculatedMargin = $(element).css('margin-right');
            $(element).data('margin-right', actualMargin).css('margin-right', parseFloat(calculatedMargin) - _this9._scrollbarWidth + "px");
          }); // Adjust body padding
  
          var actualPadding = document.body.style.paddingRight;
          var calculatedPadding = $(document.body).css('padding-right');
          $(document.body).data('padding-right', actualPadding).css('padding-right', parseFloat(calculatedPadding) + this._scrollbarWidth + "px");
        }
  
        $(document.body).addClass(ClassName$5.OPEN);
      };
  
      _proto._resetScrollbar = function _resetScrollbar() {
        // Restore fixed content padding
        var fixedContent = [].slice.call(document.querySelectorAll(Selector$5.FIXED_CONTENT));
        $(fixedContent).each(function (index, element) {
          var padding = $(element).data('padding-right');
          $(element).removeData('padding-right');
          element.style.paddingRight = padding ? padding : '';
        }); // Restore sticky content
  
        var elements = [].slice.call(document.querySelectorAll("" + Selector$5.STICKY_CONTENT));
        $(elements).each(function (index, element) {
          var margin = $(element).data('margin-right');
  
          if (typeof margin !== 'undefined') {
            $(element).css('margin-right', margin).removeData('margin-right');
          }
        }); // Restore body padding
  
        var padding = $(document.body).data('padding-right');
        $(document.body).removeData('padding-right');
        document.body.style.paddingRight = padding ? padding : '';
      };
  
      _proto._getScrollbarWidth = function _getScrollbarWidth() {
        // thx d.walsh
        var scrollDiv = document.createElement('div');
        scrollDiv.className = ClassName$5.SCROLLBAR_MEASURER;
        document.body.appendChild(scrollDiv);
        var scrollbarWidth = scrollDiv.getBoundingClientRect().width - scrollDiv.clientWidth;
        document.body.removeChild(scrollDiv);
        return scrollbarWidth;
      } // Static
      ;
  
      Modal._jQueryInterface = function _jQueryInterface(config, relatedTarget) {
        return this.each(function () {
          var data = $(this).data(DATA_KEY$5);
  
          var _config = _objectSpread({}, Default$3, $(this).data(), typeof config === 'object' && config ? config : {});
  
          if (!data) {
            data = new Modal(this, _config);
            $(this).data(DATA_KEY$5, data);
          }
  
          if (typeof config === 'string') {
            if (typeof data[config] === 'undefined') {
              throw new TypeError("No method named \"" + config + "\"");
            }
  
            data[config](relatedTarget);
          } else if (_config.show) {
            data.show(relatedTarget);
          }
        });
      };
  
      _createClass(Modal, null, [{
        key: "VERSION",
        get: function get() {
          return VERSION$5;
        }
      }, {
        key: "Default",
        get: function get() {
          return Default$3;
        }
      }]);
  
      return Modal;
    }();
    /**
     * ------------------------------------------------------------------------
     * Data Api implementation
     * ------------------------------------------------------------------------
     */
  
  
    $(document).on(Event$5.CLICK_DATA_API, Selector$5.DATA_TOGGLE, function (event) {
      var _this10 = this;
  
      var target;
      var selector = Util.getSelectorFromElement(this);
  
      if (selector) {
        target = document.querySelector(selector);
      }
  
      var config = $(target).data(DATA_KEY$5) ? 'toggle' : _objectSpread({}, $(target).data(), $(this).data());
  
      if (this.tagName === 'A' || this.tagName === 'AREA') {
        event.preventDefault();
      }
  
      var $target = $(target).one(Event$5.SHOW, function (showEvent) {
        if (showEvent.isDefaultPrevented()) {
          // Only register focus restorer if modal will actually get shown
          return;
        }
  
        $target.one(Event$5.HIDDEN, function () {
          if ($(_this10).is(':visible')) {
            _this10.focus();
          }
        });
      });
  
      Modal._jQueryInterface.call($(target), config, this);
    });
    /**
     * ------------------------------------------------------------------------
     * jQuery
     * ------------------------------------------------------------------------
     */
  
    $.fn[NAME$5] = Modal._jQueryInterface;
    $.fn[NAME$5].Constructor = Modal;
  
    $.fn[NAME$5].noConflict = function () {
      $.fn[NAME$5] = JQUERY_NO_CONFLICT$5;
      return Modal._jQueryInterface;
    };
  
    /**
     * --------------------------------------------------------------------------
     * Bootstrap (v4.3.1): tools/sanitizer.js
     * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
     * --------------------------------------------------------------------------
     */
    var uriAttrs = ['background', 'cite', 'href', 'itemtype', 'longdesc', 'poster', 'src', 'xlink:href'];
    var ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i;
    var DefaultWhitelist = {
      // Global attributes allowed on any supplied element below.
      '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],
      a: ['target', 'href', 'title', 'rel'],
      area: [],
      b: [],
      br: [],
      col: [],
      code: [],
      div: [],
      em: [],
      hr: [],
      h1: [],
      h2: [],
      h3: [],
      h4: [],
      h5: [],
      h6: [],
      i: [],
      img: ['src', 'alt', 'title', 'width', 'height'],
      li: [],
      ol: [],
      p: [],
      pre: [],
      s: [],
      small: [],
      span: [],
      sub: [],
      sup: [],
      strong: [],
      u: [],
      ul: []
      /**
       * A pattern that recognizes a commonly useful subset of URLs that are safe.
       *
       * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
       */
  
    };
    var SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file):|[^&:/?#]*(?:[/?#]|$))/gi;
    /**
     * A pattern that matches safe data URLs. Only matches image, video and audio types.
     *
     * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
     */
  
    var DATA_URL_PATTERN = /^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[a-z0-9+/]+=*$/i;
  
    function allowedAttribute(attr, allowedAttributeList) {
      var attrName = attr.nodeName.toLowerCase();
  
      if (allowedAttributeList.indexOf(attrName) !== -1) {
        if (uriAttrs.indexOf(attrName) !== -1) {
          return Boolean(attr.nodeValue.match(SAFE_URL_PATTERN) || attr.nodeValue.match(DATA_URL_PATTERN));
        }
  
        return true;
      }
  
      var regExp = allowedAttributeList.filter(function (attrRegex) {
        return attrRegex instanceof RegExp;
      }); // Check if a regular expression validates the attribute.
  
      for (var i = 0, l = regExp.length; i < l; i++) {
        if (attrName.match(regExp[i])) {
          return true;
        }
      }
  
      return false;
    }
  
    function sanitizeHtml(unsafeHtml, whiteList, sanitizeFn) {
      if (unsafeHtml.length === 0) {
        return unsafeHtml;
      }
  
      if (sanitizeFn && typeof sanitizeFn === 'function') {
        return sanitizeFn(unsafeHtml);
      }
  
      var domParser = new window.DOMParser();
      var createdDocument = domParser.parseFromString(unsafeHtml, 'text/html');
      var whitelistKeys = Object.keys(whiteList);
      var elements = [].slice.call(createdDocument.body.querySelectorAll('*'));
  
      var _loop = function _loop(i, len) {
        var el = elements[i];
        var elName = el.nodeName.toLowerCase();
  
        if (whitelistKeys.indexOf(el.nodeName.toLowerCase()) === -1) {
          el.parentNode.removeChild(el);
          return "continue";
        }
  
        var attributeList = [].slice.call(el.attributes);
        var whitelistedAttributes = [].concat(whiteList['*'] || [], whiteList[elName] || []);
        attributeList.forEach(function (attr) {
          if (!allowedAttribute(attr, whitelistedAttributes)) {
            el.removeAttribute(attr.nodeName);
          }
        });
      };
  
      for (var i = 0, len = elements.length; i < len; i++) {
        var _ret = _loop(i, len);
  
        if (_ret === "continue") continue;
      }
  
      return createdDocument.body.innerHTML;
    }
  
    /**
     * ------------------------------------------------------------------------
     * Constants
     * ------------------------------------------------------------------------
     */
  
    var NAME$6 = 'tooltip';
    var VERSION$6 = '4.3.1';
    var DATA_KEY$6 = 'bs.tooltip';
    var EVENT_KEY$6 = "." + DATA_KEY$6;
    var JQUERY_NO_CONFLICT$6 = $.fn[NAME$6];
    var CLASS_PREFIX = 'bs-tooltip';
    var BSCLS_PREFIX_REGEX = new RegExp("(^|\\s)" + CLASS_PREFIX + "\\S+", 'g');
    var DISALLOWED_ATTRIBUTES = ['sanitize', 'whiteList', 'sanitizeFn'];
    var DefaultType$4 = {
      animation: 'boolean',
      template: 'string',
      title: '(string|element|function)',
      trigger: 'string',
      delay: '(number|object)',
      html: 'boolean',
      selector: '(string|boolean)',
      placement: '(string|function)',
      offset: '(number|string|function)',
      container: '(string|element|boolean)',
      fallbackPlacement: '(string|array)',
      boundary: '(string|element)',
      sanitize: 'boolean',
      sanitizeFn: '(null|function)',
      whiteList: 'object'
    };
    var AttachmentMap$1 = {
      AUTO: 'auto',
      TOP: 'top',
      RIGHT: 'right',
      BOTTOM: 'bottom',
      LEFT: 'left'
    };
    var Default$4 = {
      animation: true,
      template: '<div class="tooltip" role="tooltip">' + '<div class="arrow"></div>' + '<div class="tooltip-inner"></div></div>',
      trigger: 'hover focus',
      title: '',
      delay: 0,
      html: false,
      selector: false,
      placement: 'top',
      offset: 0,
      container: false,
      fallbackPlacement: 'flip',
      boundary: 'scrollParent',
      sanitize: true,
      sanitizeFn: null,
      whiteList: DefaultWhitelist
    };
    var HoverState = {
      SHOW: 'show',
      OUT: 'out'
    };
    var Event$6 = {
      HIDE: "hide" + EVENT_KEY$6,
      HIDDEN: "hidden" + EVENT_KEY$6,
      SHOW: "show" + EVENT_KEY$6,
      SHOWN: "shown" + EVENT_KEY$6,
      INSERTED: "inserted" + EVENT_KEY$6,
      CLICK: "click" + EVENT_KEY$6,
      FOCUSIN: "focusin" + EVENT_KEY$6,
      FOCUSOUT: "focusout" + EVENT_KEY$6,
      MOUSEENTER: "mouseenter" + EVENT_KEY$6,
      MOUSELEAVE: "mouseleave" + EVENT_KEY$6
    };
    var ClassName$6 = {
      FADE: 'fade',
      SHOW: 'show'
    };
    var Selector$6 = {
      TOOLTIP: '.tooltip',
      TOOLTIP_INNER: '.tooltip-inner',
      ARROW: '.arrow'
    };
    var Trigger = {
      HOVER: 'hover',
      FOCUS: 'focus',
      CLICK: 'click',
      MANUAL: 'manual'
      /**
       * ------------------------------------------------------------------------
       * Class Definition
       * ------------------------------------------------------------------------
       */
  
    };
  
    var Tooltip =
    /*#__PURE__*/
    function () {
      function Tooltip(element, config) {
        /**
         * Check for Popper dependency
         * Popper - https://popper.js.org
         */
        if (typeof Popper === 'undefined') {
          throw new TypeError('Bootstrap\'s tooltips require Popper.js (https://popper.js.org/)');
        } // private
  
  
        this._isEnabled = true;
        this._timeout = 0;
        this._hoverState = '';
        this._activeTrigger = {};
        this._popper = null; // Protected
  
        this.element = element;
        this.config = this._getConfig(config);
        this.tip = null;
  
        this._setListeners();
      } // Getters
  
  
      var _proto = Tooltip.prototype;
  
      // Public
      _proto.enable = function enable() {
        this._isEnabled = true;
      };
  
      _proto.disable = function disable() {
        this._isEnabled = false;
      };
  
      _proto.toggleEnabled = function toggleEnabled() {
        this._isEnabled = !this._isEnabled;
      };
  
      _proto.toggle = function toggle(event) {
        if (!this._isEnabled) {
          return;
        }
  
        if (event) {
          var dataKey = this.constructor.DATA_KEY;
          var context = $(event.currentTarget).data(dataKey);
  
          if (!context) {
            context = new this.constructor(event.currentTarget, this._getDelegateConfig());
            $(event.currentTarget).data(dataKey, context);
          }
  
          context._activeTrigger.click = !context._activeTrigger.click;
  
          if (context._isWithActiveTrigger()) {
            context._enter(null, context);
          } else {
            context._leave(null, context);
          }
        } else {
          if ($(this.getTipElement()).hasClass(ClassName$6.SHOW)) {
            this._leave(null, this);
  
            return;
          }
  
          this._enter(null, this);
        }
      };
  
      _proto.dispose = function dispose() {
        clearTimeout(this._timeout);
        $.removeData(this.element, this.constructor.DATA_KEY);
        $(this.element).off(this.constructor.EVENT_KEY);
        $(this.element).closest('.modal').off('hide.bs.modal');
  
        if (this.tip) {
          $(this.tip).remove();
        }
  
        this._isEnabled = null;
        this._timeout = null;
        this._hoverState = null;
        this._activeTrigger = null;
  
        if (this._popper !== null) {
          this._popper.destroy();
        }
  
        this._popper = null;
        this.element = null;
        this.config = null;
        this.tip = null;
      };
  
      _proto.show = function show() {
        var _this = this;
  
        if ($(this.element).css('display') === 'none') {
          throw new Error('Please use show on visible elements');
        }
  
        var showEvent = $.Event(this.constructor.Event.SHOW);
  
        if (this.isWithContent() && this._isEnabled) {
          $(this.element).trigger(showEvent);
          var shadowRoot = Util.findShadowRoot(this.element);
          var isInTheDom = $.contains(shadowRoot !== null ? shadowRoot : this.element.ownerDocument.documentElement, this.element);
  
          if (showEvent.isDefaultPrevented() || !isInTheDom) {
            return;
          }
  
          var tip = this.getTipElement();
          var tipId = Util.getUID(this.constructor.NAME);
          tip.setAttribute('id', tipId);
          this.element.setAttribute('aria-describedby', tipId);
          this.setContent();
  
          if (this.config.animation) {
            $(tip).addClass(ClassName$6.FADE);
          }
  
          var placement = typeof this.config.placement === 'function' ? this.config.placement.call(this, tip, this.element) : this.config.placement;
  
          var attachment = this._getAttachment(placement);
  
          this.addAttachmentClass(attachment);
  
          var container = this._getContainer();
  
          $(tip).data(this.constructor.DATA_KEY, this);
  
          if (!$.contains(this.element.ownerDocument.documentElement, this.tip)) {
            $(tip).appendTo(container);
          }
  
          $(this.element).trigger(this.constructor.Event.INSERTED);
          this._popper = new Popper(this.element, tip, {
            placement: attachment,
            modifiers: {
              offset: this._getOffset(),
              flip: {
                behavior: this.config.fallbackPlacement
              },
              arrow: {
                element: Selector$6.ARROW
              },
              preventOverflow: {
                boundariesElement: this.config.boundary
              }
            },
            onCreate: function onCreate(data) {
              if (data.originalPlacement !== data.placement) {
                _this._handlePopperPlacementChange(data);
              }
            },
            onUpdate: function onUpdate(data) {
              return _this._handlePopperPlacementChange(data);
            }
          });
          $(tip).addClass(ClassName$6.SHOW); // If this is a touch-enabled device we add extra
          // empty mouseover listeners to the body's immediate children;
          // only needed because of broken event delegation on iOS
          // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
  
          if ('ontouchstart' in document.documentElement) {
            $(document.body).children().on('mouseover', null, $.noop);
          }
  
          var complete = function complete() {
            if (_this.config.animation) {
              _this._fixTransition();
            }
  
            var prevHoverState = _this._hoverState;
            _this._hoverState = null;
            $(_this.element).trigger(_this.constructor.Event.SHOWN);
  
            if (prevHoverState === HoverState.OUT) {
              _this._leave(null, _this);
            }
          };
  
          if ($(this.tip).hasClass(ClassName$6.FADE)) {
            var transitionDuration = Util.getTransitionDurationFromElement(this.tip);
            $(this.tip).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);
          } else {
            complete();
          }
        }
      };
  
      _proto.hide = function hide(callback) {
        var _this2 = this;
  
        var tip = this.getTipElement();
        var hideEvent = $.Event(this.constructor.Event.HIDE);
  
        var complete = function complete() {
          if (_this2._hoverState !== HoverState.SHOW && tip.parentNode) {
            tip.parentNode.removeChild(tip);
          }
  
          _this2._cleanTipClass();
  
          _this2.element.removeAttribute('aria-describedby');
  
          $(_this2.element).trigger(_this2.constructor.Event.HIDDEN);
  
          if (_this2._popper !== null) {
            _this2._popper.destroy();
          }
  
          if (callback) {
            callback();
          }
        };
  
        $(this.element).trigger(hideEvent);
  
        if (hideEvent.isDefaultPrevented()) {
          return;
        }
  
        $(tip).removeClass(ClassName$6.SHOW); // If this is a touch-enabled device we remove the extra
        // empty mouseover listeners we added for iOS support
  
        if ('ontouchstart' in document.documentElement) {
          $(document.body).children().off('mouseover', null, $.noop);
        }
  
        this._activeTrigger[Trigger.CLICK] = false;
        this._activeTrigger[Trigger.FOCUS] = false;
        this._activeTrigger[Trigger.HOVER] = false;
  
        if ($(this.tip).hasClass(ClassName$6.FADE)) {
          var transitionDuration = Util.getTransitionDurationFromElement(tip);
          $(tip).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);
        } else {
          complete();
        }
  
        this._hoverState = '';
      };
  
      _proto.update = function update() {
        if (this._popper !== null) {
          this._popper.scheduleUpdate();
        }
      } // Protected
      ;
  
      _proto.isWithContent = function isWithContent() {
        return Boolean(this.getTitle());
      };
  
      _proto.addAttachmentClass = function addAttachmentClass(attachment) {
        $(this.getTipElement()).addClass(CLASS_PREFIX + "-" + attachment);
      };
  
      _proto.getTipElement = function getTipElement() {
        this.tip = this.tip || $(this.config.template)[0];
        return this.tip;
      };
  
      _proto.setContent = function setContent() {
        var tip = this.getTipElement();
        this.setElementContent($(tip.querySelectorAll(Selector$6.TOOLTIP_INNER)), this.getTitle());
        $(tip).removeClass(ClassName$6.FADE + " " + ClassName$6.SHOW);
      };
  
      _proto.setElementContent = function setElementContent($element, content) {
        if (typeof content === 'object' && (content.nodeType || content.jquery)) {
          // Content is a DOM node or a jQuery
          if (this.config.html) {
            if (!$(content).parent().is($element)) {
              $element.empty().append(content);
            }
          } else {
            $element.text($(content).text());
          }
  
          return;
        }
  
        if (this.config.html) {
          if (this.config.sanitize) {
            content = sanitizeHtml(content, this.config.whiteList, this.config.sanitizeFn);
          }
  
          $element.html(content);
        } else {
          $element.text(content);
        }
      };
  
      _proto.getTitle = function getTitle() {
        var title = this.element.getAttribute('data-original-title');
  
        if (!title) {
          title = typeof this.config.title === 'function' ? this.config.title.call(this.element) : this.config.title;
        }
  
        return title;
      } // Private
      ;
  
      _proto._getOffset = function _getOffset() {
        var _this3 = this;
  
        var offset = {};
  
        if (typeof this.config.offset === 'function') {
          offset.fn = function (data) {
            data.offsets = _objectSpread({}, data.offsets, _this3.config.offset(data.offsets, _this3.element) || {});
            return data;
          };
        } else {
          offset.offset = this.config.offset;
        }
  
        return offset;
      };
  
      _proto._getContainer = function _getContainer() {
        if (this.config.container === false) {
          return document.body;
        }
  
        if (Util.isElement(this.config.container)) {
          return $(this.config.container);
        }
  
        return $(document).find(this.config.container);
      };
  
      _proto._getAttachment = function _getAttachment(placement) {
        return AttachmentMap$1[placement.toUpperCase()];
      };
  
      _proto._setListeners = function _setListeners() {
        var _this4 = this;
  
        var triggers = this.config.trigger.split(' ');
        triggers.forEach(function (trigger) {
          if (trigger === 'click') {
            $(_this4.element).on(_this4.constructor.Event.CLICK, _this4.config.selector, function (event) {
              return _this4.toggle(event);
            });
          } else if (trigger !== Trigger.MANUAL) {
            var eventIn = trigger === Trigger.HOVER ? _this4.constructor.Event.MOUSEENTER : _this4.constructor.Event.FOCUSIN;
            var eventOut = trigger === Trigger.HOVER ? _this4.constructor.Event.MOUSELEAVE : _this4.constructor.Event.FOCUSOUT;
            $(_this4.element).on(eventIn, _this4.config.selector, function (event) {
              return _this4._enter(event);
            }).on(eventOut, _this4.config.selector, function (event) {
              return _this4._leave(event);
            });
          }
        });
        $(this.element).closest('.modal').on('hide.bs.modal', function () {
          if (_this4.element) {
            _this4.hide();
          }
        });
  
        if (this.config.selector) {
          this.config = _objectSpread({}, this.config, {
            trigger: 'manual',
            selector: ''
          });
        } else {
          this._fixTitle();
        }
      };
  
      _proto._fixTitle = function _fixTitle() {
        var titleType = typeof this.element.getAttribute('data-original-title');
  
        if (this.element.getAttribute('title') || titleType !== 'string') {
          this.element.setAttribute('data-original-title', this.element.getAttribute('title') || '');
          this.element.setAttribute('title', '');
        }
      };
  
      _proto._enter = function _enter(event, context) {
        var dataKey = this.constructor.DATA_KEY;
        context = context || $(event.currentTarget).data(dataKey);
  
        if (!context) {
          context = new this.constructor(event.currentTarget, this._getDelegateConfig());
          $(event.currentTarget).data(dataKey, context);
        }
  
        if (event) {
          context._activeTrigger[event.type === 'focusin' ? Trigger.FOCUS : Trigger.HOVER] = true;
        }
  
        if ($(context.getTipElement()).hasClass(ClassName$6.SHOW) || context._hoverState === HoverState.SHOW) {
          context._hoverState = HoverState.SHOW;
          return;
        }
  
        clearTimeout(context._timeout);
        context._hoverState = HoverState.SHOW;
  
        if (!context.config.delay || !context.config.delay.show) {
          context.show();
          return;
        }
  
        context._timeout = setTimeout(function () {
          if (context._hoverState === HoverState.SHOW) {
            context.show();
          }
        }, context.config.delay.show);
      };
  
      _proto._leave = function _leave(event, context) {
        var dataKey = this.constructor.DATA_KEY;
        context = context || $(event.currentTarget).data(dataKey);
  
        if (!context) {
          context = new this.constructor(event.currentTarget, this._getDelegateConfig());
          $(event.currentTarget).data(dataKey, context);
        }
  
        if (event) {
          context._activeTrigger[event.type === 'focusout' ? Trigger.FOCUS : Trigger.HOVER] = false;
        }
  
        if (context._isWithActiveTrigger()) {
          return;
        }
  
        clearTimeout(context._timeout);
        context._hoverState = HoverState.OUT;
  
        if (!context.config.delay || !context.config.delay.hide) {
          context.hide();
          return;
        }
  
        context._timeout = setTimeout(function () {
          if (context._hoverState === HoverState.OUT) {
            context.hide();
          }
        }, context.config.delay.hide);
      };
  
      _proto._isWithActiveTrigger = function _isWithActiveTrigger() {
        for (var trigger in this._activeTrigger) {
          if (this._activeTrigger[trigger]) {
            return true;
          }
        }
  
        return false;
      };
  
      _proto._getConfig = function _getConfig(config) {
        var dataAttributes = $(this.element).data();
        Object.keys(dataAttributes).forEach(function (dataAttr) {
          if (DISALLOWED_ATTRIBUTES.indexOf(dataAttr) !== -1) {
            delete dataAttributes[dataAttr];
          }
        });
        config = _objectSpread({}, this.constructor.Default, dataAttributes, typeof config === 'object' && config ? config : {});
  
        if (typeof config.delay === 'number') {
          config.delay = {
            show: config.delay,
            hide: config.delay
          };
        }
  
        if (typeof config.title === 'number') {
          config.title = config.title.toString();
        }
  
        if (typeof config.content === 'number') {
          config.content = config.content.toString();
        }
  
        Util.typeCheckConfig(NAME$6, config, this.constructor.DefaultType);
  
        if (config.sanitize) {
          config.template = sanitizeHtml(config.template, config.whiteList, config.sanitizeFn);
        }
  
        return config;
      };
  
      _proto._getDelegateConfig = function _getDelegateConfig() {
        var config = {};
  
        if (this.config) {
          for (var key in this.config) {
            if (this.constructor.Default[key] !== this.config[key]) {
              config[key] = this.config[key];
            }
          }
        }
  
        return config;
      };
  
      _proto._cleanTipClass = function _cleanTipClass() {
        var $tip = $(this.getTipElement());
        var tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX);
  
        if (tabClass !== null && tabClass.length) {
          $tip.removeClass(tabClass.join(''));
        }
      };
  
      _proto._handlePopperPlacementChange = function _handlePopperPlacementChange(popperData) {
        var popperInstance = popperData.instance;
        this.tip = popperInstance.popper;
  
        this._cleanTipClass();
  
        this.addAttachmentClass(this._getAttachment(popperData.placement));
      };
  
      _proto._fixTransition = function _fixTransition() {
        var tip = this.getTipElement();
        var initConfigAnimation = this.config.animation;
  
        if (tip.getAttribute('x-placement') !== null) {
          return;
        }
  
        $(tip).removeClass(ClassName$6.FADE);
        this.config.animation = false;
        this.hide();
        this.show();
        this.config.animation = initConfigAnimation;
      } // Static
      ;
  
      Tooltip._jQueryInterface = function _jQueryInterface(config) {
        return this.each(function () {
          var data = $(this).data(DATA_KEY$6);
  
          var _config = typeof config === 'object' && config;
  
          if (!data && /dispose|hide/.test(config)) {
            return;
          }
  
          if (!data) {
            data = new Tooltip(this, _config);
            $(this).data(DATA_KEY$6, data);
          }
  
          if (typeof config === 'string') {
            if (typeof data[config] === 'undefined') {
              throw new TypeError("No method named \"" + config + "\"");
            }
  
            data[config]();
          }
        });
      };
  
      _createClass(Tooltip, null, [{
        key: "VERSION",
        get: function get() {
          return VERSION$6;
        }
      }, {
        key: "Default",
        get: function get() {
          return Default$4;
        }
      }, {
        key: "NAME",
        get: function get() {
          return NAME$6;
        }
      }, {
        key: "DATA_KEY",
        get: function get() {
          return DATA_KEY$6;
        }
      }, {
        key: "Event",
        get: function get() {
          return Event$6;
        }
      }, {
        key: "EVENT_KEY",
        get: function get() {
          return EVENT_KEY$6;
        }
      }, {
        key: "DefaultType",
        get: function get() {
          return DefaultType$4;
        }
      }]);
  
      return Tooltip;
    }();
    /**
     * ------------------------------------------------------------------------
     * jQuery
     * ------------------------------------------------------------------------
     */
  
  
    $.fn[NAME$6] = Tooltip._jQueryInterface;
    $.fn[NAME$6].Constructor = Tooltip;
  
    $.fn[NAME$6].noConflict = function () {
      $.fn[NAME$6] = JQUERY_NO_CONFLICT$6;
      return Tooltip._jQueryInterface;
    };
  
    /**
     * ------------------------------------------------------------------------
     * Constants
     * ------------------------------------------------------------------------
     */
  
    var NAME$7 = 'popover';
    var VERSION$7 = '4.3.1';
    var DATA_KEY$7 = 'bs.popover';
    var EVENT_KEY$7 = "." + DATA_KEY$7;
    var JQUERY_NO_CONFLICT$7 = $.fn[NAME$7];
    var CLASS_PREFIX$1 = 'bs-popover';
    var BSCLS_PREFIX_REGEX$1 = new RegExp("(^|\\s)" + CLASS_PREFIX$1 + "\\S+", 'g');
  
    var Default$5 = _objectSpread({}, Tooltip.Default, {
      placement: 'right',
      trigger: 'click',
      content: '',
      template: '<div class="popover" role="tooltip">' + '<div class="arrow"></div>' + '<h3 class="popover-header"></h3>' + '<div class="popover-body"></div></div>'
    });
  
    var DefaultType$5 = _objectSpread({}, Tooltip.DefaultType, {
      content: '(string|element|function)'
    });
  
    var ClassName$7 = {
      FADE: 'fade',
      SHOW: 'show'
    };
    var Selector$7 = {
      TITLE: '.popover-header',
      CONTENT: '.popover-body'
    };
    var Event$7 = {
      HIDE: "hide" + EVENT_KEY$7,
      HIDDEN: "hidden" + EVENT_KEY$7,
      SHOW: "show" + EVENT_KEY$7,
      SHOWN: "shown" + EVENT_KEY$7,
      INSERTED: "inserted" + EVENT_KEY$7,
      CLICK: "click" + EVENT_KEY$7,
      FOCUSIN: "focusin" + EVENT_KEY$7,
      FOCUSOUT: "focusout" + EVENT_KEY$7,
      MOUSEENTER: "mouseenter" + EVENT_KEY$7,
      MOUSELEAVE: "mouseleave" + EVENT_KEY$7
      /**
       * ------------------------------------------------------------------------
       * Class Definition
       * ------------------------------------------------------------------------
       */
  
    };
  
    var Popover =
    /*#__PURE__*/
    function (_Tooltip) {
      _inheritsLoose(Popover, _Tooltip);
  
      function Popover() {
        return _Tooltip.apply(this, arguments) || this;
      }
  
      var _proto = Popover.prototype;
  
      // Overrides
      _proto.isWithContent = function isWithContent() {
        return this.getTitle() || this._getContent();
      };
  
      _proto.addAttachmentClass = function addAttachmentClass(attachment) {
        $(this.getTipElement()).addClass(CLASS_PREFIX$1 + "-" + attachment);
      };
  
      _proto.getTipElement = function getTipElement() {
        this.tip = this.tip || $(this.config.template)[0];
        return this.tip;
      };
  
      _proto.setContent = function setContent() {
        var $tip = $(this.getTipElement()); // We use append for html objects to maintain js events
  
        this.setElementContent($tip.find(Selector$7.TITLE), this.getTitle());
  
        var content = this._getContent();
  
        if (typeof content === 'function') {
          content = content.call(this.element);
        }
  
        this.setElementContent($tip.find(Selector$7.CONTENT), content);
        $tip.removeClass(ClassName$7.FADE + " " + ClassName$7.SHOW);
      } // Private
      ;
  
      _proto._getContent = function _getContent() {
        return this.element.getAttribute('data-content') || this.config.content;
      };
  
      _proto._cleanTipClass = function _cleanTipClass() {
        var $tip = $(this.getTipElement());
        var tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX$1);
  
        if (tabClass !== null && tabClass.length > 0) {
          $tip.removeClass(tabClass.join(''));
        }
      } // Static
      ;
  
      Popover._jQueryInterface = function _jQueryInterface(config) {
        return this.each(function () {
          var data = $(this).data(DATA_KEY$7);
  
          var _config = typeof config === 'object' ? config : null;
  
          if (!data && /dispose|hide/.test(config)) {
            return;
          }
  
          if (!data) {
            data = new Popover(this, _config);
            $(this).data(DATA_KEY$7, data);
          }
  
          if (typeof config === 'string') {
            if (typeof data[config] === 'undefined') {
              throw new TypeError("No method named \"" + config + "\"");
            }
  
            data[config]();
          }
        });
      };
  
      _createClass(Popover, null, [{
        key: "VERSION",
        // Getters
        get: function get() {
          return VERSION$7;
        }
      }, {
        key: "Default",
        get: function get() {
          return Default$5;
        }
      }, {
        key: "NAME",
        get: function get() {
          return NAME$7;
        }
      }, {
        key: "DATA_KEY",
        get: function get() {
          return DATA_KEY$7;
        }
      }, {
        key: "Event",
        get: function get() {
          return Event$7;
        }
      }, {
        key: "EVENT_KEY",
        get: function get() {
          return EVENT_KEY$7;
        }
      }, {
        key: "DefaultType",
        get: function get() {
          return DefaultType$5;
        }
      }]);
  
      return Popover;
    }(Tooltip);
    /**
     * ------------------------------------------------------------------------
     * jQuery
     * ------------------------------------------------------------------------
     */
  
  
    $.fn[NAME$7] = Popover._jQueryInterface;
    $.fn[NAME$7].Constructor = Popover;
  
    $.fn[NAME$7].noConflict = function () {
      $.fn[NAME$7] = JQUERY_NO_CONFLICT$7;
      return Popover._jQueryInterface;
    };
  
    /**
     * ------------------------------------------------------------------------
     * Constants
     * ------------------------------------------------------------------------
     */
  
    var NAME$8 = 'scrollspy';
    var VERSION$8 = '4.3.1';
    var DATA_KEY$8 = 'bs.scrollspy';
    var EVENT_KEY$8 = "." + DATA_KEY$8;
    var DATA_API_KEY$6 = '.data-api';
    var JQUERY_NO_CONFLICT$8 = $.fn[NAME$8];
    var Default$6 = {
      offset: 10,
      method: 'auto',
      target: ''
    };
    var DefaultType$6 = {
      offset: 'number',
      method: 'string',
      target: '(string|element)'
    };
    var Event$8 = {
      ACTIVATE: "activate" + EVENT_KEY$8,
      SCROLL: "scroll" + EVENT_KEY$8,
      LOAD_DATA_API: "load" + EVENT_KEY$8 + DATA_API_KEY$6
    };
    var ClassName$8 = {
      DROPDOWN_ITEM: 'dropdown-item',
      DROPDOWN_MENU: 'dropdown-menu',
      ACTIVE: 'active'
    };
    var Selector$8 = {
      DATA_SPY: '[data-spy="scroll"]',
      ACTIVE: '.active',
      NAV_LIST_GROUP: '.nav, .list-group',
      NAV_LINKS: '.nav-link',
      NAV_ITEMS: '.nav-item',
      LIST_ITEMS: '.list-group-item',
      DROPDOWN: '.dropdown',
      DROPDOWN_ITEMS: '.dropdown-item',
      DROPDOWN_TOGGLE: '.dropdown-toggle'
    };
    var OffsetMethod = {
      OFFSET: 'offset',
      POSITION: 'position'
      /**
       * ------------------------------------------------------------------------
       * Class Definition
       * ------------------------------------------------------------------------
       */
  
    };
  
    var ScrollSpy =
    /*#__PURE__*/
    function () {
      function ScrollSpy(element, config) {
        var _this = this;
  
        this._element = element;
        this._scrollElement = element.tagName === 'BODY' ? window : element;
        this._config = this._getConfig(config);
        this._selector = this._config.target + " " + Selector$8.NAV_LINKS + "," + (this._config.target + " " + Selector$8.LIST_ITEMS + ",") + (this._config.target + " " + Selector$8.DROPDOWN_ITEMS);
        this._offsets = [];
        this._targets = [];
        this._activeTarget = null;
        this._scrollHeight = 0;
        $(this._scrollElement).on(Event$8.SCROLL, function (event) {
          return _this._process(event);
        });
        this.refresh();
  
        this._process();
      } // Getters
  
  
      var _proto = ScrollSpy.prototype;
  
      // Public
      _proto.refresh = function refresh() {
        var _this2 = this;
  
        var autoMethod = this._scrollElement === this._scrollElement.window ? OffsetMethod.OFFSET : OffsetMethod.POSITION;
        var offsetMethod = this._config.method === 'auto' ? autoMethod : this._config.method;
        var offsetBase = offsetMethod === OffsetMethod.POSITION ? this._getScrollTop() : 0;
        this._offsets = [];
        this._targets = [];
        this._scrollHeight = this._getScrollHeight();
        var targets = [].slice.call(document.querySelectorAll(this._selector));
        targets.map(function (element) {
          var target;
          var targetSelector = Util.getSelectorFromElement(element);
  
          if (targetSelector) {
            target = document.querySelector(targetSelector);
          }
  
          if (target) {
            var targetBCR = target.getBoundingClientRect();
  
            if (targetBCR.width || targetBCR.height) {
              // TODO (fat): remove sketch reliance on jQuery position/offset
              return [$(target)[offsetMethod]().top + offsetBase, targetSelector];
            }
          }
  
          return null;
        }).filter(function (item) {
          return item;
        }).sort(function (a, b) {
          return a[0] - b[0];
        }).forEach(function (item) {
          _this2._offsets.push(item[0]);
  
          _this2._targets.push(item[1]);
        });
      };
  
      _proto.dispose = function dispose() {
        $.removeData(this._element, DATA_KEY$8);
        $(this._scrollElement).off(EVENT_KEY$8);
        this._element = null;
        this._scrollElement = null;
        this._config = null;
        this._selector = null;
        this._offsets = null;
        this._targets = null;
        this._activeTarget = null;
        this._scrollHeight = null;
      } // Private
      ;
  
      _proto._getConfig = function _getConfig(config) {
        config = _objectSpread({}, Default$6, typeof config === 'object' && config ? config : {});
  
        if (typeof config.target !== 'string') {
          var id = $(config.target).attr('id');
  
          if (!id) {
            id = Util.getUID(NAME$8);
            $(config.target).attr('id', id);
          }
  
          config.target = "#" + id;
        }
  
        Util.typeCheckConfig(NAME$8, config, DefaultType$6);
        return config;
      };
  
      _proto._getScrollTop = function _getScrollTop() {
        return this._scrollElement === window ? this._scrollElement.pageYOffset : this._scrollElement.scrollTop;
      };
  
      _proto._getScrollHeight = function _getScrollHeight() {
        return this._scrollElement.scrollHeight || Math.max(document.body.scrollHeight, document.documentElement.scrollHeight);
      };
  
      _proto._getOffsetHeight = function _getOffsetHeight() {
        return this._scrollElement === window ? window.innerHeight : this._scrollElement.getBoundingClientRect().height;
      };
  
      _proto._process = function _process() {
        var scrollTop = this._getScrollTop() + this._config.offset;
  
        var scrollHeight = this._getScrollHeight();
  
        var maxScroll = this._config.offset + scrollHeight - this._getOffsetHeight();
  
        if (this._scrollHeight !== scrollHeight) {
          this.refresh();
        }
  
        if (scrollTop >= maxScroll) {
          var target = this._targets[this._targets.length - 1];
  
          if (this._activeTarget !== target) {
            this._activate(target);
          }
  
          return;
        }
  
        if (this._activeTarget && scrollTop < this._offsets[0] && this._offsets[0] > 0) {
          this._activeTarget = null;
  
          this._clear();
  
          return;
        }
  
        var offsetLength = this._offsets.length;
  
        for (var i = offsetLength; i--;) {
          var isActiveTarget = this._activeTarget !== this._targets[i] && scrollTop >= this._offsets[i] && (typeof this._offsets[i + 1] === 'undefined' || scrollTop < this._offsets[i + 1]);
  
          if (isActiveTarget) {
            this._activate(this._targets[i]);
          }
        }
      };
  
      _proto._activate = function _activate(target) {
        this._activeTarget = target;
  
        this._clear();
  
        var queries = this._selector.split(',').map(function (selector) {
          return selector + "[data-target=\"" + target + "\"]," + selector + "[href=\"" + target + "\"]";
        });
  
        var $link = $([].slice.call(document.querySelectorAll(queries.join(','))));
  
        if ($link.hasClass(ClassName$8.DROPDOWN_ITEM)) {
          $link.closest(Selector$8.DROPDOWN).find(Selector$8.DROPDOWN_TOGGLE).addClass(ClassName$8.ACTIVE);
          $link.addClass(ClassName$8.ACTIVE);
        } else {
          // Set triggered link as active
          $link.addClass(ClassName$8.ACTIVE); // Set triggered links parents as active
          // With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor
  
          $link.parents(Selector$8.NAV_LIST_GROUP).prev(Selector$8.NAV_LINKS + ", " + Selector$8.LIST_ITEMS).addClass(ClassName$8.ACTIVE); // Handle special case when .nav-link is inside .nav-item
  
          $link.parents(Selector$8.NAV_LIST_GROUP).prev(Selector$8.NAV_ITEMS).children(Selector$8.NAV_LINKS).addClass(ClassName$8.ACTIVE);
        }
  
        $(this._scrollElement).trigger(Event$8.ACTIVATE, {
          relatedTarget: target
        });
      };
  
      _proto._clear = function _clear() {
        [].slice.call(document.querySelectorAll(this._selector)).filter(function (node) {
          return node.classList.contains(ClassName$8.ACTIVE);
        }).forEach(function (node) {
          return node.classList.remove(ClassName$8.ACTIVE);
        });
      } // Static
      ;
  
      ScrollSpy._jQueryInterface = function _jQueryInterface(config) {
        return this.each(function () {
          var data = $(this).data(DATA_KEY$8);
  
          var _config = typeof config === 'object' && config;
  
          if (!data) {
            data = new ScrollSpy(this, _config);
            $(this).data(DATA_KEY$8, data);
          }
  
          if (typeof config === 'string') {
            if (typeof data[config] === 'undefined') {
              throw new TypeError("No method named \"" + config + "\"");
            }
  
            data[config]();
          }
        });
      };
  
      _createClass(ScrollSpy, null, [{
        key: "VERSION",
        get: function get() {
          return VERSION$8;
        }
      }, {
        key: "Default",
        get: function get() {
          return Default$6;
        }
      }]);
  
      return ScrollSpy;
    }();
    /**
     * ------------------------------------------------------------------------
     * Data Api implementation
     * ------------------------------------------------------------------------
     */
  
  
    $(window).on(Event$8.LOAD_DATA_API, function () {
      var scrollSpys = [].slice.call(document.querySelectorAll(Selector$8.DATA_SPY));
      var scrollSpysLength = scrollSpys.length;
  
      for (var i = scrollSpysLength; i--;) {
        var $spy = $(scrollSpys[i]);
  
        ScrollSpy._jQueryInterface.call($spy, $spy.data());
      }
    });
    /**
     * ------------------------------------------------------------------------
     * jQuery
     * ------------------------------------------------------------------------
     */
  
    $.fn[NAME$8] = ScrollSpy._jQueryInterface;
    $.fn[NAME$8].Constructor = ScrollSpy;
  
    $.fn[NAME$8].noConflict = function () {
      $.fn[NAME$8] = JQUERY_NO_CONFLICT$8;
      return ScrollSpy._jQueryInterface;
    };
  
    /**
     * ------------------------------------------------------------------------
     * Constants
     * ------------------------------------------------------------------------
     */
  
    var NAME$9 = 'tab';
    var VERSION$9 = '4.3.1';
    var DATA_KEY$9 = 'bs.tab';
    var EVENT_KEY$9 = "." + DATA_KEY$9;
    var DATA_API_KEY$7 = '.data-api';
    var JQUERY_NO_CONFLICT$9 = $.fn[NAME$9];
    var Event$9 = {
      HIDE: "hide" + EVENT_KEY$9,
      HIDDEN: "hidden" + EVENT_KEY$9,
      SHOW: "show" + EVENT_KEY$9,
      SHOWN: "shown" + EVENT_KEY$9,
      CLICK_DATA_API: "click" + EVENT_KEY$9 + DATA_API_KEY$7
    };
    var ClassName$9 = {
      DROPDOWN_MENU: 'dropdown-menu',
      ACTIVE: 'active',
      DISABLED: 'disabled',
      FADE: 'fade',
      SHOW: 'show'
    };
    var Selector$9 = {
      DROPDOWN: '.dropdown',
      NAV_LIST_GROUP: '.nav, .list-group',
      ACTIVE: '.active',
      ACTIVE_UL: '> li > .active',
      DATA_TOGGLE: '[data-toggle="tab"], [data-toggle="pill"], [data-toggle="list"]',
      DROPDOWN_TOGGLE: '.dropdown-toggle',
      DROPDOWN_ACTIVE_CHILD: '> .dropdown-menu .active'
      /**
       * ------------------------------------------------------------------------
       * Class Definition
       * ------------------------------------------------------------------------
       */
  
    };
  
    var Tab =
    /*#__PURE__*/
    function () {
      function Tab(element) {
        this._element = element;
      } // Getters
  
  
      var _proto = Tab.prototype;
  
      // Public
      _proto.show = function show() {
        var _this = this;
  
        if (this._element.parentNode && this._element.parentNode.nodeType === Node.ELEMENT_NODE && $(this._element).hasClass(ClassName$9.ACTIVE) || $(this._element).hasClass(ClassName$9.DISABLED)) {
          return;
        }
  
        var target;
        var previous;
        var listElement = $(this._element).closest(Selector$9.NAV_LIST_GROUP)[0];
        var selector = Util.getSelectorFromElement(this._element);
  
        if (listElement) {
          var itemSelector = listElement.nodeName === 'UL' || listElement.nodeName === 'OL' ? Selector$9.ACTIVE_UL : Selector$9.ACTIVE;
          previous = $.makeArray($(listElement).find(itemSelector));
          previous = previous[previous.length - 1];
        }
  
        var hideEvent = $.Event(Event$9.HIDE, {
          relatedTarget: this._element
        });
        var showEvent = $.Event(Event$9.SHOW, {
          relatedTarget: previous
        });
  
        if (previous) {
          $(previous).trigger(hideEvent);
        }
  
        $(this._element).trigger(showEvent);
  
        if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) {
          return;
        }
  
        if (selector) {
          target = document.querySelector(selector);
        }
  
        this._activate(this._element, listElement);
  
        var complete = function complete() {
          var hiddenEvent = $.Event(Event$9.HIDDEN, {
            relatedTarget: _this._element
          });
          var shownEvent = $.Event(Event$9.SHOWN, {
            relatedTarget: previous
          });
          $(previous).trigger(hiddenEvent);
          $(_this._element).trigger(shownEvent);
        };
  
        if (target) {
          this._activate(target, target.parentNode, complete);
        } else {
          complete();
        }
      };
  
      _proto.dispose = function dispose() {
        $.removeData(this._element, DATA_KEY$9);
        this._element = null;
      } // Private
      ;
  
      _proto._activate = function _activate(element, container, callback) {
        var _this2 = this;
  
        var activeElements = container && (container.nodeName === 'UL' || container.nodeName === 'OL') ? $(container).find(Selector$9.ACTIVE_UL) : $(container).children(Selector$9.ACTIVE);
        var active = activeElements[0];
        var isTransitioning = callback && active && $(active).hasClass(ClassName$9.FADE);
  
        var complete = function complete() {
          return _this2._transitionComplete(element, active, callback);
        };
  
        if (active && isTransitioning) {
          var transitionDuration = Util.getTransitionDurationFromElement(active);
          $(active).removeClass(ClassName$9.SHOW).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);
        } else {
          complete();
        }
      };
  
      _proto._transitionComplete = function _transitionComplete(element, active, callback) {
        if (active) {
          $(active).removeClass(ClassName$9.ACTIVE);
          var dropdownChild = $(active.parentNode).find(Selector$9.DROPDOWN_ACTIVE_CHILD)[0];
  
          if (dropdownChild) {
            $(dropdownChild).removeClass(ClassName$9.ACTIVE);
          }
  
          if (active.getAttribute('role') === 'tab') {
            active.setAttribute('aria-selected', false);
          }
        }
  
        $(element).addClass(ClassName$9.ACTIVE);
  
        if (element.getAttribute('role') === 'tab') {
          element.setAttribute('aria-selected', true);
        }
  
        Util.reflow(element);
  
        if (element.classList.contains(ClassName$9.FADE)) {
          element.classList.add(ClassName$9.SHOW);
        }
  
        if (element.parentNode && $(element.parentNode).hasClass(ClassName$9.DROPDOWN_MENU)) {
          var dropdownElement = $(element).closest(Selector$9.DROPDOWN)[0];
  
          if (dropdownElement) {
            var dropdownToggleList = [].slice.call(dropdownElement.querySelectorAll(Selector$9.DROPDOWN_TOGGLE));
            $(dropdownToggleList).addClass(ClassName$9.ACTIVE);
          }
  
          element.setAttribute('aria-expanded', true);
        }
  
        if (callback) {
          callback();
        }
      } // Static
      ;
  
      Tab._jQueryInterface = function _jQueryInterface(config) {
        return this.each(function () {
          var $this = $(this);
          var data = $this.data(DATA_KEY$9);
  
          if (!data) {
            data = new Tab(this);
            $this.data(DATA_KEY$9, data);
          }
  
          if (typeof config === 'string') {
            if (typeof data[config] === 'undefined') {
              throw new TypeError("No method named \"" + config + "\"");
            }
  
            data[config]();
          }
        });
      };
  
      _createClass(Tab, null, [{
        key: "VERSION",
        get: function get() {
          return VERSION$9;
        }
      }]);
  
      return Tab;
    }();
    /**
     * ------------------------------------------------------------------------
     * Data Api implementation
     * ------------------------------------------------------------------------
     */
  
  
    $(document).on(Event$9.CLICK_DATA_API, Selector$9.DATA_TOGGLE, function (event) {
      event.preventDefault();
  
      Tab._jQueryInterface.call($(this), 'show');
    });
    /**
     * ------------------------------------------------------------------------
     * jQuery
     * ------------------------------------------------------------------------
     */
  
    $.fn[NAME$9] = Tab._jQueryInterface;
    $.fn[NAME$9].Constructor = Tab;
  
    $.fn[NAME$9].noConflict = function () {
      $.fn[NAME$9] = JQUERY_NO_CONFLICT$9;
      return Tab._jQueryInterface;
    };
  
    /**
     * ------------------------------------------------------------------------
     * Constants
     * ------------------------------------------------------------------------
     */
  
    var NAME$a = 'toast';
    var VERSION$a = '4.3.1';
    var DATA_KEY$a = 'bs.toast';
    var EVENT_KEY$a = "." + DATA_KEY$a;
    var JQUERY_NO_CONFLICT$a = $.fn[NAME$a];
    var Event$a = {
      CLICK_DISMISS: "click.dismiss" + EVENT_KEY$a,
      HIDE: "hide" + EVENT_KEY$a,
      HIDDEN: "hidden" + EVENT_KEY$a,
      SHOW: "show" + EVENT_KEY$a,
      SHOWN: "shown" + EVENT_KEY$a
    };
    var ClassName$a = {
      FADE: 'fade',
      HIDE: 'hide',
      SHOW: 'show',
      SHOWING: 'showing'
    };
    var DefaultType$7 = {
      animation: 'boolean',
      autohide: 'boolean',
      delay: 'number'
    };
    var Default$7 = {
      animation: true,
      autohide: true,
      delay: 500
    };
    var Selector$a = {
      DATA_DISMISS: '[data-dismiss="toast"]'
      /**
       * ------------------------------------------------------------------------
       * Class Definition
       * ------------------------------------------------------------------------
       */
  
    };
  
    var Toast =
    /*#__PURE__*/
    function () {
      function Toast(element, config) {
        this._element = element;
        this._config = this._getConfig(config);
        this._timeout = null;
  
        this._setListeners();
      } // Getters
  
  
      var _proto = Toast.prototype;
  
      // Public
      _proto.show = function show() {
        var _this = this;
  
        $(this._element).trigger(Event$a.SHOW);
  
        if (this._config.animation) {
          this._element.classList.add(ClassName$a.FADE);
        }
  
        var complete = function complete() {
          _this._element.classList.remove(ClassName$a.SHOWING);
  
          _this._element.classList.add(ClassName$a.SHOW);
  
          $(_this._element).trigger(Event$a.SHOWN);
  
          if (_this._config.autohide) {
            _this.hide();
          }
        };
  
        this._element.classList.remove(ClassName$a.HIDE);
  
        this._element.classList.add(ClassName$a.SHOWING);
  
        if (this._config.animation) {
          var transitionDuration = Util.getTransitionDurationFromElement(this._element);
          $(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);
        } else {
          complete();
        }
      };
  
      _proto.hide = function hide(withoutTimeout) {
        var _this2 = this;
  
        if (!this._element.classList.contains(ClassName$a.SHOW)) {
          return;
        }
  
        $(this._element).trigger(Event$a.HIDE);
  
        if (withoutTimeout) {
          this._close();
        } else {
          this._timeout = setTimeout(function () {
            _this2._close();
          }, this._config.delay);
        }
      };
  
      _proto.dispose = function dispose() {
        clearTimeout(this._timeout);
        this._timeout = null;
  
        if (this._element.classList.contains(ClassName$a.SHOW)) {
          this._element.classList.remove(ClassName$a.SHOW);
        }
  
        $(this._element).off(Event$a.CLICK_DISMISS);
        $.removeData(this._element, DATA_KEY$a);
        this._element = null;
        this._config = null;
      } // Private
      ;
  
      _proto._getConfig = function _getConfig(config) {
        config = _objectSpread({}, Default$7, $(this._element).data(), typeof config === 'object' && config ? config : {});
        Util.typeCheckConfig(NAME$a, config, this.constructor.DefaultType);
        return config;
      };
  
      _proto._setListeners = function _setListeners() {
        var _this3 = this;
  
        $(this._element).on(Event$a.CLICK_DISMISS, Selector$a.DATA_DISMISS, function () {
          return _this3.hide(true);
        });
      };
  
      _proto._close = function _close() {
        var _this4 = this;
  
        var complete = function complete() {
          _this4._element.classList.add(ClassName$a.HIDE);
  
          $(_this4._element).trigger(Event$a.HIDDEN);
        };
  
        this._element.classList.remove(ClassName$a.SHOW);
  
        if (this._config.animation) {
          var transitionDuration = Util.getTransitionDurationFromElement(this._element);
          $(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);
        } else {
          complete();
        }
      } // Static
      ;
  
      Toast._jQueryInterface = function _jQueryInterface(config) {
        return this.each(function () {
          var $element = $(this);
          var data = $element.data(DATA_KEY$a);
  
          var _config = typeof config === 'object' && config;
  
          if (!data) {
            data = new Toast(this, _config);
            $element.data(DATA_KEY$a, data);
          }
  
          if (typeof config === 'string') {
            if (typeof data[config] === 'undefined') {
              throw new TypeError("No method named \"" + config + "\"");
            }
  
            data[config](this);
          }
        });
      };
  
      _createClass(Toast, null, [{
        key: "VERSION",
        get: function get() {
          return VERSION$a;
        }
      }, {
        key: "DefaultType",
        get: function get() {
          return DefaultType$7;
        }
      }, {
        key: "Default",
        get: function get() {
          return Default$7;
        }
      }]);
  
      return Toast;
    }();
    /**
     * ------------------------------------------------------------------------
     * jQuery
     * ------------------------------------------------------------------------
     */
  
  
    $.fn[NAME$a] = Toast._jQueryInterface;
    $.fn[NAME$a].Constructor = Toast;
  
    $.fn[NAME$a].noConflict = function () {
      $.fn[NAME$a] = JQUERY_NO_CONFLICT$a;
      return Toast._jQueryInterface;
    };
  
    /**
     * --------------------------------------------------------------------------
     * Bootstrap (v4.3.1): index.js
     * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
     * --------------------------------------------------------------------------
     */
  
    (function () {
      if (typeof $ === 'undefined') {
        throw new TypeError('Bootstrap\'s JavaScript requires jQuery. jQuery must be included before Bootstrap\'s JavaScript.');
      }
  
      var version = $.fn.jquery.split(' ')[0].split('.');
      var minMajor = 1;
      var ltMajor = 2;
      var minMinor = 9;
      var minPatch = 1;
      var maxMajor = 4;
  
      if (version[0] < ltMajor && version[1] < minMinor || version[0] === minMajor && version[1] === minMinor && version[2] < minPatch || version[0] >= maxMajor) {
        throw new Error('Bootstrap\'s JavaScript requires at least jQuery v1.9.1 but less than v4.0.0');
      }
    })();
  
    exports.Util = Util;
    exports.Alert = Alert;
    exports.Button = Button;
    exports.Carousel = Carousel;
    exports.Collapse = Collapse;
    exports.Dropdown = Dropdown;
    exports.Modal = Modal;
    exports.Popover = Popover;
    exports.Scrollspy = ScrollSpy;
    exports.Tab = Tab;
    exports.Toast = Toast;
    exports.Tooltip = Tooltip;
  
    Object.defineProperty(exports, '__esModule', { value: true });
  
  }));
  //# sourceMappingURL=bootstrap.bundle.js.map
  
  
  /* ====================================================================================================
    Retina image replace
  ==================================================================================================== */
  /* ============================================================
   * retina-replace.js v1.0
   * http://github.com/leonsmith/retina-replace-js
   * ============================================================
   * Author: Leon Smith
   * Twitter: @nullUK
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   * http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   * ============================================================ */
   (function($) {
      "use strict";
      
      var retinaReplace = function(element, options) {
  
          this.options = options;
          var $el = $(element);
          var is_image = $el.is('img');
          var normal_url = is_image ? $el.attr('src') : $el.backgroundImageUrl();
          var retina_url = this.options.generateUrl($el, normal_url);
  
          $('<img/>').attr('src', retina_url).load(function() {
  
              if (is_image) {
                  $el.attr('src', $(this).attr('src'));
              } else {
                  $el.backgroundImageUrl($(this).attr('src'));
                  $el.backgroundSize($(this)[0].width, $(this)[0].height);
              }
  
              $el.attr('data-retina', 'complete');
          });
      }
  
      retinaReplace.prototype = {
          constructor: retinaReplace
      }
  
      $.fn.retinaReplace = function(option) {
          // Finish if we arn't a retina device
          if (getDevicePixelRatio() <= 1) { return this; }
  
          return this.each(function() {
              var $this = $(this);
              var data = $this.data('retinaReplace');
              var options = $.extend({}, $.fn.retinaReplace.defaults, $this.data(), typeof option == 'object' && option);
              if (!data) { $this.data('retinaReplace', (data = new retinaReplace(this, options))); }
              if (typeof option == 'string') { data[option](); }
          });
      }
      
      $.fn.retinaReplace.defaults = {
          suffix: '_2x', 
          generateUrl: function(element, url) {
              var dot_index = url.lastIndexOf('.');
              var extension = url.substr(dot_index + 1);
              var file = url.substr(0, dot_index);
              return file + this.suffix + '.' + extension;
          }
      }
  
      $.fn.retinaReplace.Constructor = retinaReplace;
  
      // Helper Functions
      var getDevicePixelRatio = function() {
          if (window.devicePixelRatio === undefined) { return 1; }
          return window.devicePixelRatio;
      }
  
      $.fn.backgroundImageUrl = function(url) {
          return url ? this.each(function () { 
              $(this).css("background-image", 'url("' + url + '")')
          }) : $(this).css("background-image").replace(/url\(|\)|"|'/g, "");
      }
  
      $.fn.backgroundSize = function(retinaWidth, retinaHeight) {
          var sizeValue = Math.floor(retinaWidth/2) + 'px ' + Math.floor(retinaHeight/2) + 'px';
          $(this).css("background-size", sizeValue);
          $(this).css("-webkit-background-size", sizeValue);
      }
  
      // Trigger replacement on elements that hav been marked up
      $(function(){
          $("[data-retina='true']").retinaReplace();
      });
  
  })(window.jQuery);
  
  /* ====================================================================================================
    Parallax
  ==================================================================================================== */
  /*!
   * parallax.js v1.5.0 (http://pixelcog.github.io/parallax.js/)
   * @copyright 2016 PixelCog, Inc.
   * @license MIT (https://github.com/pixelcog/parallax.js/blob/master/LICENSE)
   */
  
  ;(function ( $, window, document, undefined ) {
  
    // Polyfill for requestAnimationFrame
    // via: https://gist.github.com/paulirish/1579671
  
    (function() {
      var lastTime = 0;
      var vendors = ['ms', 'moz', 'webkit', 'o'];
      for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
        window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
        window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];
      }
  
      if (!window.requestAnimationFrame)
        window.requestAnimationFrame = function(callback) {
          var currTime = new Date().getTime();
          var timeToCall = Math.max(0, 16 - (currTime - lastTime));
          var id = window.setTimeout(function() { callback(currTime + timeToCall); },
            timeToCall);
          lastTime = currTime + timeToCall;
          return id;
        };
  
      if (!window.cancelAnimationFrame)
        window.cancelAnimationFrame = function(id) {
          clearTimeout(id);
        };
    }());
  
  
    // Parallax Constructor
  
    function Parallax(element, options) {
      var self = this;
  
      if (typeof options == 'object') {
        delete options.refresh;
        delete options.render;
        $.extend(this, options);
      }
  
      this.$element = $(element);
  
      if (!this.imageSrc && this.$element.is('img')) {
        this.imageSrc = this.$element.attr('src');
      }
  
      var positions = (this.position + '').toLowerCase().match(/\S+/g) || [];
  
      if (positions.length < 1) {
        positions.push('center');
      }
      if (positions.length == 1) {
        positions.push(positions[0]);
      }
  
      if (positions[0] == 'top' || positions[0] == 'bottom' || positions[1] == 'left' || positions[1] == 'right') {
        positions = [positions[1], positions[0]];
      }
  
      if (this.positionX !== undefined) positions[0] = this.positionX.toLowerCase();
      if (this.positionY !== undefined) positions[1] = this.positionY.toLowerCase();
  
      self.positionX = positions[0];
      self.positionY = positions[1];
  
      if (this.positionX != 'left' && this.positionX != 'right') {
        if (isNaN(parseInt(this.positionX))) {
          this.positionX = 'center';
        } else {
          this.positionX = parseInt(this.positionX);
        }
      }
  
      if (this.positionY != 'top' && this.positionY != 'bottom') {
        if (isNaN(parseInt(this.positionY))) {
          this.positionY = 'center';
        } else {
          this.positionY = parseInt(this.positionY);
        }
      }
  
      this.position =
        this.positionX + (isNaN(this.positionX)? '' : 'px') + ' ' +
        this.positionY + (isNaN(this.positionY)? '' : 'px');
  
      if (navigator.userAgent.match(/(iPod|iPhone|iPad)/)) {
        if (this.imageSrc && this.iosFix && !this.$element.is('img')) {
          this.$element.css({
            backgroundImage: 'url("' + this.imageSrc + '")',
            backgroundSize: 'cover',
            backgroundPosition: this.position
          });
        }
        return this;
      }
  
      if (navigator.userAgent.match(/(Android)/)) {
        if (this.imageSrc && this.androidFix && !this.$element.is('img')) {
          this.$element.css({
            backgroundImage: 'url("' + this.imageSrc + '")',
            backgroundSize: 'cover',
            backgroundPosition: this.position
          });
        }
        return this;
      }
  
      this.$mirror = $('<div />').prependTo(this.mirrorContainer);
  
      var slider = this.$element.find('>.parallax-slider');
      var sliderExisted = false;
  
      if (slider.length == 0)
        this.$slider = $('<img />').prependTo(this.$mirror);
      else {
        this.$slider = slider.prependTo(this.$mirror)
        sliderExisted = true;
      }
  
      this.$mirror.addClass('parallax-mirror').css({
        visibility: 'hidden',
        zIndex: this.zIndex,
        position: 'fixed',
        top: 0,
        left: 0,
        overflow: 'hidden'
      });
  
      this.$slider.addClass('parallax-slider').one('load', function() {
        if (!self.naturalHeight || !self.naturalWidth) {
          self.naturalHeight = this.naturalHeight || this.height || 1;
          self.naturalWidth  = this.naturalWidth  || this.width  || 1;
        }
        self.aspectRatio = self.naturalWidth / self.naturalHeight;
  
        Parallax.isSetup || Parallax.setup();
        Parallax.sliders.push(self);
        Parallax.isFresh = false;
        Parallax.requestRender();
      });
  
      if (!sliderExisted)
        this.$slider[0].src = this.imageSrc;
  
      if (this.naturalHeight && this.naturalWidth || this.$slider[0].complete || slider.length > 0) {
        this.$slider.trigger('load');
      }
  
    }
  
  
    // Parallax Instance Methods
  
    $.extend(Parallax.prototype, {
      speed:    0.2,
      bleed:    0,
      zIndex:   1,
      iosFix:   true,
      androidFix: true,
      position: 'center',
      overScrollFix: false,
      mirrorContainer: 'body',
  
      refresh: function() {
        this.boxWidth        = this.$element.outerWidth();
        this.boxHeight       = this.$element.outerHeight() + this.bleed * 2;
        this.boxOffsetTop    = this.$element.offset().top - this.bleed;
        this.boxOffsetLeft   = this.$element.offset().left;
        this.boxOffsetBottom = this.boxOffsetTop + this.boxHeight;
  
        var winHeight = Parallax.winHeight;
        var docHeight = Parallax.docHeight;
        var maxOffset = Math.min(this.boxOffsetTop, docHeight - winHeight);
        var minOffset = Math.max(this.boxOffsetTop + this.boxHeight - winHeight, 0);
        var imageHeightMin = this.boxHeight + (maxOffset - minOffset) * (1 - this.speed) | 0;
        var imageOffsetMin = (this.boxOffsetTop - maxOffset) * (1 - this.speed) | 0;
        var margin;
  
        if (imageHeightMin * this.aspectRatio >= this.boxWidth) {
          this.imageWidth    = imageHeightMin * this.aspectRatio | 0;
          this.imageHeight   = imageHeightMin;
          this.offsetBaseTop = imageOffsetMin;
  
          margin = this.imageWidth - this.boxWidth;
  
          if (this.positionX == 'left') {
            this.offsetLeft = 0;
          } else if (this.positionX == 'right') {
            this.offsetLeft = - margin;
          } else if (!isNaN(this.positionX)) {
            this.offsetLeft = Math.max(this.positionX, - margin);
          } else {
            this.offsetLeft = - margin / 2 | 0;
          }
        } else {
          this.imageWidth    = this.boxWidth;
          this.imageHeight   = this.boxWidth / this.aspectRatio | 0;
          this.offsetLeft    = 0;
  
          margin = this.imageHeight - imageHeightMin;
  
          if (this.positionY == 'top') {
            this.offsetBaseTop = imageOffsetMin;
          } else if (this.positionY == 'bottom') {
            this.offsetBaseTop = imageOffsetMin - margin;
          } else if (!isNaN(this.positionY)) {
            this.offsetBaseTop = imageOffsetMin + Math.max(this.positionY, - margin);
          } else {
            this.offsetBaseTop = imageOffsetMin - margin / 2 | 0;
          }
        }
      },
  
      render: function() {
        var scrollTop    = Parallax.scrollTop;
        var scrollLeft   = Parallax.scrollLeft;
        var overScroll   = this.overScrollFix ? Parallax.overScroll : 0;
        var scrollBottom = scrollTop + Parallax.winHeight;
  
        if (this.boxOffsetBottom > scrollTop && this.boxOffsetTop <= scrollBottom) {
          this.visibility = 'visible';
          this.mirrorTop = this.boxOffsetTop  - scrollTop;
          this.mirrorLeft = this.boxOffsetLeft - scrollLeft;
          this.offsetTop = this.offsetBaseTop - this.mirrorTop * (1 - this.speed);
        } else {
          this.visibility = 'hidden';
        }
  
        this.$mirror.css({
          transform: 'translate3d('+this.mirrorLeft+'px, '+(this.mirrorTop - overScroll)+'px, 0px)',
          visibility: this.visibility,
          height: this.boxHeight,
          width: this.boxWidth
        });
  
        this.$slider.css({
          transform: 'translate3d('+this.offsetLeft+'px, '+this.offsetTop+'px, 0px)',
          position: 'absolute',
          height: this.imageHeight,
          width: this.imageWidth,
          maxWidth: 'none'
        });
      }
    });
  
  
    // Parallax Static Methods
  
    $.extend(Parallax, {
      scrollTop:    0,
      scrollLeft:   0,
      winHeight:    0,
      winWidth:     0,
      docHeight:    1 << 30,
      docWidth:     1 << 30,
      sliders:      [],
      isReady:      false,
      isFresh:      false,
      isBusy:       false,
  
      setup: function() {
        if (this.isReady) return;
  
        var self = this;
  
        var $doc = $(document), $win = $(window);
  
        var loadDimensions = function() {
          Parallax.winHeight = $win.height();
          Parallax.winWidth  = $win.width();
          Parallax.docHeight = $doc.height();
          Parallax.docWidth  = $doc.width();
        };
  
        var loadScrollPosition = function() {
          var winScrollTop  = $win.scrollTop();
          var scrollTopMax  = Parallax.docHeight - Parallax.winHeight;
          var scrollLeftMax = Parallax.docWidth  - Parallax.winWidth;
          Parallax.scrollTop  = Math.max(0, Math.min(scrollTopMax,  winScrollTop));
          Parallax.scrollLeft = Math.max(0, Math.min(scrollLeftMax, $win.scrollLeft()));
          Parallax.overScroll = Math.max(winScrollTop - scrollTopMax, Math.min(winScrollTop, 0));
        };
  
        $win.on('resize.px.parallax load.px.parallax', function() {
            loadDimensions();
            self.refresh();
            Parallax.isFresh = false;
            Parallax.requestRender();
          })
          .on('scroll.px.parallax load.px.parallax', function() {
            loadScrollPosition();
            Parallax.requestRender();
          });
  
        loadDimensions();
        loadScrollPosition();
  
        this.isReady = true;
  
        var lastPosition = -1;
  
        function frameLoop() {
          if (lastPosition == window.pageYOffset) {   // Avoid overcalculations
            window.requestAnimationFrame(frameLoop);
            return false;
          } else lastPosition = window.pageYOffset;
  
          self.render();
          window.requestAnimationFrame(frameLoop);
        }
  
        frameLoop();
      },
  
      configure: function(options) {
        if (typeof options == 'object') {
          delete options.refresh;
          delete options.render;
          $.extend(this.prototype, options);
        }
      },
  
      refresh: function() {
        $.each(this.sliders, function(){ this.refresh(); });
        this.isFresh = true;
      },
  
      render: function() {
        this.isFresh || this.refresh();
        $.each(this.sliders, function(){ this.render(); });
      },
  
      requestRender: function() {
        var self = this;
        self.render();
        self.isBusy = false;
      },
      destroy: function(el){
        var i,
            parallaxElement = $(el).data('px.parallax');
        parallaxElement.$mirror.remove();
        for(i=0; i < this.sliders.length; i+=1){
          if(this.sliders[i] == parallaxElement){
            this.sliders.splice(i, 1);
          }
        }
        $(el).data('px.parallax', false);
        if(this.sliders.length === 0){
          $(window).off('scroll.px.parallax resize.px.parallax load.px.parallax');
          this.isReady = false;
          Parallax.isSetup = false;
        }
      }
    });
  
  
    // Parallax Plugin Definition
  
    function Plugin(option) {
      return this.each(function () {
        var $this = $(this);
        var options = typeof option == 'object' && option;
  
        if (this == window || this == document || $this.is('body')) {
          Parallax.configure(options);
        }
        else if (!$this.data('px.parallax')) {
          options = $.extend({}, $this.data(), options);
          $this.data('px.parallax', new Parallax(this, options));
        }
        else if (typeof option == 'object')
        {
          $.extend($this.data('px.parallax'), options);
        }
        if (typeof option == 'string') {
          if(option == 'destroy'){
              Parallax.destroy(this);
          }else{
            Parallax[option]();
          }
        }
      });
    }
  
    var old = $.fn.parallax;
  
    $.fn.parallax             = Plugin;
    $.fn.parallax.Constructor = Parallax;
  
  
    // Parallax No Conflict
  
    $.fn.parallax.noConflict = function () {
      $.fn.parallax = old;
      return this;
    };
  
  
    // Parallax Data-API
  
    $( function () { 
      $('[data-parallax="scroll"]').parallax(); 
    });
  
  }(jQuery, window, document));
  
  /* ====================================================================================================
    Magnific Popup
  ==================================================================================================== */
  /*! Magnific Popup - v1.1.0 - 2016-02-20
  * http://dimsemenov.com/plugins/magnific-popup/
  * Copyright (c) 2016 Dmitry Semenov; */
  ;(function (factory) { 
  if (typeof define === 'function' && define.amd) { 
   // AMD. Register as an anonymous module. 
   define(['jquery'], factory); 
   } else if (typeof exports === 'object') { 
   // Node/CommonJS 
   factory(require('jquery')); 
   } else { 
   // Browser globals 
   factory(window.jQuery || window.Zepto); 
   } 
   }(function($) { 
  
  /*>>core*/
  /**
   * 
   * Magnific Popup Core JS file
   * 
   */
  
  
  /**
   * Private static constants
   */
  var CLOSE_EVENT = 'Close',
  	BEFORE_CLOSE_EVENT = 'BeforeClose',
  	AFTER_CLOSE_EVENT = 'AfterClose',
  	BEFORE_APPEND_EVENT = 'BeforeAppend',
  	MARKUP_PARSE_EVENT = 'MarkupParse',
  	OPEN_EVENT = 'Open',
  	CHANGE_EVENT = 'Change',
  	NS = 'mfp',
  	EVENT_NS = '.' + NS,
  	READY_CLASS = 'mfp-ready',
  	REMOVING_CLASS = 'mfp-removing',
  	PREVENT_CLOSE_CLASS = 'mfp-prevent-close';
  
  
  /**
   * Private vars 
   */
  /*jshint -W079 */
  var mfp, // As we have only one instance of MagnificPopup object, we define it locally to not to use 'this'
  	MagnificPopup = function(){},
  	_isJQ = !!(window.jQuery),
  	_prevStatus,
  	_window = $(window),
  	_document,
  	_prevContentType,
  	_wrapClasses,
  	_currPopupType;
  
  
  /**
   * Private functions
   */
  var _mfpOn = function(name, f) {
  		mfp.ev.on(NS + name + EVENT_NS, f);
  	},
  	_getEl = function(className, appendTo, html, raw) {
  		var el = document.createElement('div');
  		el.className = 'mfp-'+className;
  		if(html) {
  			el.innerHTML = html;
  		}
  		if(!raw) {
  			el = $(el);
  			if(appendTo) {
  				el.appendTo(appendTo);
  			}
  		} else if(appendTo) {
  			appendTo.appendChild(el);
  		}
  		return el;
  	},
  	_mfpTrigger = function(e, data) {
  		mfp.ev.triggerHandler(NS + e, data);
  
  		if(mfp.st.callbacks) {
  			// converts "mfpEventName" to "eventName" callback and triggers it if it's present
  			e = e.charAt(0).toLowerCase() + e.slice(1);
  			if(mfp.st.callbacks[e]) {
  				mfp.st.callbacks[e].apply(mfp, $.isArray(data) ? data : [data]);
  			}
  		}
  	},
  	_getCloseBtn = function(type) {
  		if(type !== _currPopupType || !mfp.currTemplate.closeBtn) {
  			mfp.currTemplate.closeBtn = $( mfp.st.closeMarkup.replace('%title%', mfp.st.tClose ) );
  			_currPopupType = type;
  		}
  		return mfp.currTemplate.closeBtn;
  	},
  	// Initialize Magnific Popup only when called at least once
  	_checkInstance = function() {
  		if(!$.magnificPopup.instance) {
  			/*jshint -W020 */
  			mfp = new MagnificPopup();
  			mfp.init();
  			$.magnificPopup.instance = mfp;
  		}
  	},
  	// CSS transition detection, http://stackoverflow.com/questions/7264899/detect-css-transitions-using-javascript-and-without-modernizr
  	supportsTransitions = function() {
  		var s = document.createElement('p').style, // 's' for style. better to create an element if body yet to exist
  			v = ['ms','O','Moz','Webkit']; // 'v' for vendor
  
  		if( s['transition'] !== undefined ) {
  			return true; 
  		}
  			
  		while( v.length ) {
  			if( v.pop() + 'Transition' in s ) {
  				return true;
  			}
  		}
  				
  		return false;
  	};
  
  
  
  /**
   * Public functions
   */
  MagnificPopup.prototype = {
  
  	constructor: MagnificPopup,
  
  	/**
  	 * Initializes Magnific Popup plugin. 
  	 * This function is triggered only once when $.fn.magnificPopup or $.magnificPopup is executed
  	 */
  	init: function() {
  		var appVersion = navigator.appVersion;
  		mfp.isLowIE = mfp.isIE8 = document.all && !document.addEventListener;
  		mfp.isAndroid = (/android/gi).test(appVersion);
  		mfp.isIOS = (/iphone|ipad|ipod/gi).test(appVersion);
  		mfp.supportsTransition = supportsTransitions();
  
  		// We disable fixed positioned lightbox on devices that don't handle it nicely.
  		// If you know a better way of detecting this - let me know.
  		mfp.probablyMobile = (mfp.isAndroid || mfp.isIOS || /(Opera Mini)|Kindle|webOS|BlackBerry|(Opera Mobi)|(Windows Phone)|IEMobile/i.test(navigator.userAgent) );
  		_document = $(document);
  
  		mfp.popupsCache = {};
  	},
  
  	/**
  	 * Opens popup
  	 * @param  data [description]
  	 */
  	open: function(data) {
  
  		var i;
  
  		if(data.isObj === false) { 
  			// convert jQuery collection to array to avoid conflicts later
  			mfp.items = data.items.toArray();
  
  			mfp.index = 0;
  			var items = data.items,
  				item;
  			for(i = 0; i < items.length; i++) {
  				item = items[i];
  				if(item.parsed) {
  					item = item.el[0];
  				}
  				if(item === data.el[0]) {
  					mfp.index = i;
  					break;
  				}
  			}
  		} else {
  			mfp.items = $.isArray(data.items) ? data.items : [data.items];
  			mfp.index = data.index || 0;
  		}
  
  		// if popup is already opened - we just update the content
  		if(mfp.isOpen) {
  			mfp.updateItemHTML();
  			return;
  		}
  		
  		mfp.types = []; 
  		_wrapClasses = '';
  		if(data.mainEl && data.mainEl.length) {
  			mfp.ev = data.mainEl.eq(0);
  		} else {
  			mfp.ev = _document;
  		}
  
  		if(data.key) {
  			if(!mfp.popupsCache[data.key]) {
  				mfp.popupsCache[data.key] = {};
  			}
  			mfp.currTemplate = mfp.popupsCache[data.key];
  		} else {
  			mfp.currTemplate = {};
  		}
  
  
  
  		mfp.st = $.extend(true, {}, $.magnificPopup.defaults, data ); 
  		mfp.fixedContentPos = mfp.st.fixedContentPos === 'auto' ? !mfp.probablyMobile : mfp.st.fixedContentPos;
  
  		if(mfp.st.modal) {
  			mfp.st.closeOnContentClick = false;
  			mfp.st.closeOnBgClick = false;
  			mfp.st.showCloseBtn = false;
  			mfp.st.enableEscapeKey = false;
  		}
  		
  
  		// Building markup
  		// main containers are created only once
  		if(!mfp.bgOverlay) {
  
  			// Dark overlay
  			mfp.bgOverlay = _getEl('bg').on('click'+EVENT_NS, function() {
  				mfp.close();
  			});
  
  			mfp.wrap = _getEl('wrap').attr('tabindex', -1).on('click'+EVENT_NS, function(e) {
  				if(mfp._checkIfClose(e.target)) {
  					mfp.close();
  				}
  			});
  
  			mfp.container = _getEl('container', mfp.wrap);
  		}
  
  		mfp.contentContainer = _getEl('content');
  		if(mfp.st.preloader) {
  			mfp.preloader = _getEl('preloader', mfp.container, mfp.st.tLoading);
  		}
  
  
  		// Initializing modules
  		var modules = $.magnificPopup.modules;
  		for(i = 0; i < modules.length; i++) {
  			var n = modules[i];
  			n = n.charAt(0).toUpperCase() + n.slice(1);
  			mfp['init'+n].call(mfp);
  		}
  		_mfpTrigger('BeforeOpen');
  
  
  		if(mfp.st.showCloseBtn) {
  			// Close button
  			if(!mfp.st.closeBtnInside) {
  				mfp.wrap.append( _getCloseBtn() );
  			} else {
  				_mfpOn(MARKUP_PARSE_EVENT, function(e, template, values, item) {
  					values.close_replaceWith = _getCloseBtn(item.type);
  				});
  				_wrapClasses += ' mfp-close-btn-in';
  			}
  		}
  
  		if(mfp.st.alignTop) {
  			_wrapClasses += ' mfp-align-top';
  		}
  
  	
  
  		if(mfp.fixedContentPos) {
  			mfp.wrap.css({
  				overflow: mfp.st.overflowY,
  				overflowX: 'hidden',
  				overflowY: mfp.st.overflowY
  			});
  		} else {
  			mfp.wrap.css({ 
  				top: _window.scrollTop(),
  				position: 'absolute'
  			});
  		}
  		if( mfp.st.fixedBgPos === false || (mfp.st.fixedBgPos === 'auto' && !mfp.fixedContentPos) ) {
  			mfp.bgOverlay.css({
  				height: _document.height(),
  				position: 'absolute'
  			});
  		}
  
  		
  
  		if(mfp.st.enableEscapeKey) {
  			// Close on ESC key
  			_document.on('keyup' + EVENT_NS, function(e) {
  				if(e.keyCode === 27) {
  					mfp.close();
  				}
  			});
  		}
  
  		_window.on('resize' + EVENT_NS, function() {
  			mfp.updateSize();
  		});
  
  
  		if(!mfp.st.closeOnContentClick) {
  			_wrapClasses += ' mfp-auto-cursor';
  		}
  		
  		if(_wrapClasses)
  			mfp.wrap.addClass(_wrapClasses);
  
  
  		// this triggers recalculation of layout, so we get it once to not to trigger twice
  		var windowHeight = mfp.wH = _window.height();
  
  		
  		var windowStyles = {};
  
  		if( mfp.fixedContentPos ) {
              if(mfp._hasScrollBar(windowHeight)){
                  var s = mfp._getScrollbarSize();
                  if(s) {
                      windowStyles.marginRight = s;
                  }
              }
          }
  
  		if(mfp.fixedContentPos) {
  			if(!mfp.isIE7) {
  				windowStyles.overflow = 'hidden';
  			} else {
  				// ie7 double-scroll bug
  				$('body, html').css('overflow', 'hidden');
  			}
  		}
  
  		
  		
  		var classesToadd = mfp.st.mainClass;
  		if(mfp.isIE7) {
  			classesToadd += ' mfp-ie7';
  		}
  		if(classesToadd) {
  			mfp._addClassToMFP( classesToadd );
  		}
  
  		// add content
  		mfp.updateItemHTML();
  
  		_mfpTrigger('BuildControls');
  
  		// remove scrollbar, add margin e.t.c
  		$('html').css(windowStyles);
  		
  		// add everything to DOM
  		mfp.bgOverlay.add(mfp.wrap).prependTo( mfp.st.prependTo || $(document.body) );
  
  		// Save last focused element
  		mfp._lastFocusedEl = document.activeElement;
  		
  		// Wait for next cycle to allow CSS transition
  		setTimeout(function() {
  			
  			if(mfp.content) {
  				mfp._addClassToMFP(READY_CLASS);
  				mfp._setFocus();
  			} else {
  				// if content is not defined (not loaded e.t.c) we add class only for BG
  				mfp.bgOverlay.addClass(READY_CLASS);
  			}
  			
  			// Trap the focus in popup
  			_document.on('focusin' + EVENT_NS, mfp._onFocusIn);
  
  		}, 16);
  
  		mfp.isOpen = true;
  		mfp.updateSize(windowHeight);
  		_mfpTrigger(OPEN_EVENT);
  
  		return data;
  	},
  
  	/**
  	 * Closes the popup
  	 */
  	close: function() {
  		if(!mfp.isOpen) return;
  		_mfpTrigger(BEFORE_CLOSE_EVENT);
  
  		mfp.isOpen = false;
  		// for CSS3 animation
  		if(mfp.st.removalDelay && !mfp.isLowIE && mfp.supportsTransition )  {
  			mfp._addClassToMFP(REMOVING_CLASS);
  			setTimeout(function() {
  				mfp._close();
  			}, mfp.st.removalDelay);
  		} else {
  			mfp._close();
  		}
  	},
  
  	/**
  	 * Helper for close() function
  	 */
  	_close: function() {
  		_mfpTrigger(CLOSE_EVENT);
  
  		var classesToRemove = REMOVING_CLASS + ' ' + READY_CLASS + ' ';
  
  		mfp.bgOverlay.detach();
  		mfp.wrap.detach();
  		mfp.container.empty();
  
  		if(mfp.st.mainClass) {
  			classesToRemove += mfp.st.mainClass + ' ';
  		}
  
  		mfp._removeClassFromMFP(classesToRemove);
  
  		if(mfp.fixedContentPos) {
  			var windowStyles = {marginRight: ''};
  			if(mfp.isIE7) {
  				$('body, html').css('overflow', '');
  			} else {
  				windowStyles.overflow = '';
  			}
  			$('html').css(windowStyles);
  		}
  		
  		_document.off('keyup' + EVENT_NS + ' focusin' + EVENT_NS);
  		mfp.ev.off(EVENT_NS);
  
  		// clean up DOM elements that aren't removed
  		mfp.wrap.attr('class', 'mfp-wrap').removeAttr('style');
  		mfp.bgOverlay.attr('class', 'mfp-bg');
  		mfp.container.attr('class', 'mfp-container');
  
  		// remove close button from target element
  		if(mfp.st.showCloseBtn &&
  		(!mfp.st.closeBtnInside || mfp.currTemplate[mfp.currItem.type] === true)) {
  			if(mfp.currTemplate.closeBtn)
  				mfp.currTemplate.closeBtn.detach();
  		}
  
  
  		if(mfp.st.autoFocusLast && mfp._lastFocusedEl) {
  			$(mfp._lastFocusedEl).focus(); // put tab focus back
  		}
  		mfp.currItem = null;	
  		mfp.content = null;
  		mfp.currTemplate = null;
  		mfp.prevHeight = 0;
  
  		_mfpTrigger(AFTER_CLOSE_EVENT);
  	},
  	
  	updateSize: function(winHeight) {
  
  		if(mfp.isIOS) {
  			// fixes iOS nav bars https://github.com/dimsemenov/Magnific-Popup/issues/2
  			var zoomLevel = document.documentElement.clientWidth / window.innerWidth;
  			var height = window.innerHeight * zoomLevel;
  			mfp.wrap.css('height', height);
  			mfp.wH = height;
  		} else {
  			mfp.wH = winHeight || _window.height();
  		}
  		// Fixes #84: popup incorrectly positioned with position:relative on body
  		if(!mfp.fixedContentPos) {
  			mfp.wrap.css('height', mfp.wH);
  		}
  
  		_mfpTrigger('Resize');
  
  	},
  
  	/**
  	 * Set content of popup based on current index
  	 */
  	updateItemHTML: function() {
  		var item = mfp.items[mfp.index];
  
  		// Detach and perform modifications
  		mfp.contentContainer.detach();
  
  		if(mfp.content)
  			mfp.content.detach();
  
  		if(!item.parsed) {
  			item = mfp.parseEl( mfp.index );
  		}
  
  		var type = item.type;
  
  		_mfpTrigger('BeforeChange', [mfp.currItem ? mfp.currItem.type : '', type]);
  		// BeforeChange event works like so:
  		// _mfpOn('BeforeChange', function(e, prevType, newType) { });
  
  		mfp.currItem = item;
  
  		if(!mfp.currTemplate[type]) {
  			var markup = mfp.st[type] ? mfp.st[type].markup : false;
  
  			// allows to modify markup
  			_mfpTrigger('FirstMarkupParse', markup);
  
  			if(markup) {
  				mfp.currTemplate[type] = $(markup);
  			} else {
  				// if there is no markup found we just define that template is parsed
  				mfp.currTemplate[type] = true;
  			}
  		}
  
  		if(_prevContentType && _prevContentType !== item.type) {
  			mfp.container.removeClass('mfp-'+_prevContentType+'-holder');
  		}
  
  		var newContent = mfp['get' + type.charAt(0).toUpperCase() + type.slice(1)](item, mfp.currTemplate[type]);
  		mfp.appendContent(newContent, type);
  
  		item.preloaded = true;
  
  		_mfpTrigger(CHANGE_EVENT, item);
  		_prevContentType = item.type;
  
  		// Append container back after its content changed
  		mfp.container.prepend(mfp.contentContainer);
  
  		_mfpTrigger('AfterChange');
  	},
  
  
  	/**
  	 * Set HTML content of popup
  	 */
  	appendContent: function(newContent, type) {
  		mfp.content = newContent;
  
  		if(newContent) {
  			if(mfp.st.showCloseBtn && mfp.st.closeBtnInside &&
  				mfp.currTemplate[type] === true) {
  				// if there is no markup, we just append close button element inside
  				if(!mfp.content.find('.mfp-close').length) {
  					mfp.content.append(_getCloseBtn());
  				}
  			} else {
  				mfp.content = newContent;
  			}
  		} else {
  			mfp.content = '';
  		}
  
  		_mfpTrigger(BEFORE_APPEND_EVENT);
  		mfp.container.addClass('mfp-'+type+'-holder');
  
  		mfp.contentContainer.append(mfp.content);
  	},
  
  
  	/**
  	 * Creates Magnific Popup data object based on given data
  	 * @param  {int} index Index of item to parse
  	 */
  	parseEl: function(index) {
  		var item = mfp.items[index],
  			type;
  
  		if(item.tagName) {
  			item = { el: $(item) };
  		} else {
  			type = item.type;
  			item = { data: item, src: item.src };
  		}
  
  		if(item.el) {
  			var types = mfp.types;
  
  			// check for 'mfp-TYPE' class
  			for(var i = 0; i < types.length; i++) {
  				if( item.el.hasClass('mfp-'+types[i]) ) {
  					type = types[i];
  					break;
  				}
  			}
  
  			item.src = item.el.attr('data-mfp-src');
  			if(!item.src) {
  				item.src = item.el.attr('href');
  			}
  		}
  
  		item.type = type || mfp.st.type || 'inline';
  		item.index = index;
  		item.parsed = true;
  		mfp.items[index] = item;
  		_mfpTrigger('ElementParse', item);
  
  		return mfp.items[index];
  	},
  
  
  	/**
  	 * Initializes single popup or a group of popups
  	 */
  	addGroup: function(el, options) {
  		var eHandler = function(e) {
  			e.mfpEl = this;
  			mfp._openClick(e, el, options);
  		};
  
  		if(!options) {
  			options = {};
  		}
  
  		var eName = 'click.magnificPopup';
  		options.mainEl = el;
  
  		if(options.items) {
  			options.isObj = true;
  			el.off(eName).on(eName, eHandler);
  		} else {
  			options.isObj = false;
  			if(options.delegate) {
  				el.off(eName).on(eName, options.delegate , eHandler);
  			} else {
  				options.items = el;
  				el.off(eName).on(eName, eHandler);
  			}
  		}
  	},
  	_openClick: function(e, el, options) {
  		var midClick = options.midClick !== undefined ? options.midClick : $.magnificPopup.defaults.midClick;
  
  
  		if(!midClick && ( e.which === 2 || e.ctrlKey || e.metaKey || e.altKey || e.shiftKey ) ) {
  			return;
  		}
  
  		var disableOn = options.disableOn !== undefined ? options.disableOn : $.magnificPopup.defaults.disableOn;
  
  		if(disableOn) {
  			if($.isFunction(disableOn)) {
  				if( !disableOn.call(mfp) ) {
  					return true;
  				}
  			} else { // else it's number
  				if( _window.width() < disableOn ) {
  					return true;
  				}
  			}
  		}
  
  		if(e.type) {
  			e.preventDefault();
  
  			// This will prevent popup from closing if element is inside and popup is already opened
  			if(mfp.isOpen) {
  				e.stopPropagation();
  			}
  		}
  
  		options.el = $(e.mfpEl);
  		if(options.delegate) {
  			options.items = el.find(options.delegate);
  		}
  		mfp.open(options);
  	},
  
  
  	/**
  	 * Updates text on preloader
  	 */
  	updateStatus: function(status, text) {
  
  		if(mfp.preloader) {
  			if(_prevStatus !== status) {
  				mfp.container.removeClass('mfp-s-'+_prevStatus);
  			}
  
  			if(!text && status === 'loading') {
  				text = mfp.st.tLoading;
  			}
  
  			var data = {
  				status: status,
  				text: text
  			};
  			// allows to modify status
  			_mfpTrigger('UpdateStatus', data);
  
  			status = data.status;
  			text = data.text;
  
  			mfp.preloader.html(text);
  
  			mfp.preloader.find('a').on('click', function(e) {
  				e.stopImmediatePropagation();
  			});
  
  			mfp.container.addClass('mfp-s-'+status);
  			_prevStatus = status;
  		}
  	},
  
  
  	/*
  		"Private" helpers that aren't private at all
  	 */
  	// Check to close popup or not
  	// "target" is an element that was clicked
  	_checkIfClose: function(target) {
  
  		if($(target).hasClass(PREVENT_CLOSE_CLASS)) {
  			return;
  		}
  
  		var closeOnContent = mfp.st.closeOnContentClick;
  		var closeOnBg = mfp.st.closeOnBgClick;
  
  		if(closeOnContent && closeOnBg) {
  			return true;
  		} else {
  
  			// We close the popup if click is on close button or on preloader. Or if there is no content.
  			if(!mfp.content || $(target).hasClass('mfp-close') || (mfp.preloader && target === mfp.preloader[0]) ) {
  				return true;
  			}
  
  			// if click is outside the content
  			if(  (target !== mfp.content[0] && !$.contains(mfp.content[0], target))  ) {
  				if(closeOnBg) {
  					// last check, if the clicked element is in DOM, (in case it's removed onclick)
  					if( $.contains(document, target) ) {
  						return true;
  					}
  				}
  			} else if(closeOnContent) {
  				return true;
  			}
  
  		}
  		return false;
  	},
  	_addClassToMFP: function(cName) {
  		mfp.bgOverlay.addClass(cName);
  		mfp.wrap.addClass(cName);
  	},
  	_removeClassFromMFP: function(cName) {
  		this.bgOverlay.removeClass(cName);
  		mfp.wrap.removeClass(cName);
  	},
  	_hasScrollBar: function(winHeight) {
  		return (  (mfp.isIE7 ? _document.height() : document.body.scrollHeight) > (winHeight || _window.height()) );
  	},
  	_setFocus: function() {
  		(mfp.st.focus ? mfp.content.find(mfp.st.focus).eq(0) : mfp.wrap).focus();
  	},
  	_onFocusIn: function(e) {
  		if( e.target !== mfp.wrap[0] && !$.contains(mfp.wrap[0], e.target) ) {
  			mfp._setFocus();
  			return false;
  		}
  	},
  	_parseMarkup: function(template, values, item) {
  		var arr;
  		if(item.data) {
  			values = $.extend(item.data, values);
  		}
  		_mfpTrigger(MARKUP_PARSE_EVENT, [template, values, item] );
  
  		$.each(values, function(key, value) {
  			if(value === undefined || value === false) {
  				return true;
  			}
  			arr = key.split('_');
  			if(arr.length > 1) {
  				var el = template.find(EVENT_NS + '-'+arr[0]);
  
  				if(el.length > 0) {
  					var attr = arr[1];
  					if(attr === 'replaceWith') {
  						if(el[0] !== value[0]) {
  							el.replaceWith(value);
  						}
  					} else if(attr === 'img') {
  						if(el.is('img')) {
  							el.attr('src', value);
  						} else {
  							el.replaceWith( $('<img>').attr('src', value).attr('class', el.attr('class')) );
  						}
  					} else {
  						el.attr(arr[1], value);
  					}
  				}
  
  			} else {
  				template.find(EVENT_NS + '-'+key).html(value);
  			}
  		});
  	},
  
  	_getScrollbarSize: function() {
  		// thx David
  		if(mfp.scrollbarSize === undefined) {
  			var scrollDiv = document.createElement("div");
  			scrollDiv.style.cssText = 'width: 99px; height: 99px; overflow: scroll; position: absolute; top: -9999px;';
  			document.body.appendChild(scrollDiv);
  			mfp.scrollbarSize = scrollDiv.offsetWidth - scrollDiv.clientWidth;
  			document.body.removeChild(scrollDiv);
  		}
  		return mfp.scrollbarSize;
  	}
  
  }; /* MagnificPopup core prototype end */
  
  
  
  
  /**
   * Public static functions
   */
  $.magnificPopup = {
  	instance: null,
  	proto: MagnificPopup.prototype,
  	modules: [],
  
  	open: function(options, index) {
  		_checkInstance();
  
  		if(!options) {
  			options = {};
  		} else {
  			options = $.extend(true, {}, options);
  		}
  
  		options.isObj = true;
  		options.index = index || 0;
  		return this.instance.open(options);
  	},
  
  	close: function() {
  		return $.magnificPopup.instance && $.magnificPopup.instance.close();
  	},
  
  	registerModule: function(name, module) {
  		if(module.options) {
  			$.magnificPopup.defaults[name] = module.options;
  		}
  		$.extend(this.proto, module.proto);
  		this.modules.push(name);
  	},
  
  	defaults: {
  
  		// Info about options is in docs:
  		// http://dimsemenov.com/plugins/magnific-popup/documentation.html#options
  
  		disableOn: 0,
  
  		key: null,
  
  		midClick: false,
  
  		mainClass: '',
  
  		preloader: true,
  
  		focus: '', // CSS selector of input to focus after popup is opened
  
  		closeOnContentClick: false,
  
  		closeOnBgClick: true,
  
  		closeBtnInside: true,
  
  		showCloseBtn: true,
  
  		enableEscapeKey: true,
  
  		modal: false,
  
  		alignTop: false,
  
  		removalDelay: 0,
  
  		prependTo: null,
  
  		fixedContentPos: 'auto',
  
  		fixedBgPos: 'auto',
  
  		overflowY: 'auto',
  
  		closeMarkup: '<button title="%title%" type="button" class="mfp-close"></button>',
  
  		tClose: 'Close (Esc)',
  
  		tLoading: 'Loading...',
  
  		autoFocusLast: true
  
  	}
  };
  
  
  
  $.fn.magnificPopup = function(options) {
  	_checkInstance();
  
  	var jqEl = $(this);
  
  	// We call some API method of first param is a string
  	if (typeof options === "string" ) {
  
  		if(options === 'open') {
  			var items,
  				itemOpts = _isJQ ? jqEl.data('magnificPopup') : jqEl[0].magnificPopup,
  				index = parseInt(arguments[1], 10) || 0;
  
  			if(itemOpts.items) {
  				items = itemOpts.items[index];
  			} else {
  				items = jqEl;
  				if(itemOpts.delegate) {
  					items = items.find(itemOpts.delegate);
  				}
  				items = items.eq( index );
  			}
  			mfp._openClick({mfpEl:items}, jqEl, itemOpts);
  		} else {
  			if(mfp.isOpen)
  				mfp[options].apply(mfp, Array.prototype.slice.call(arguments, 1));
  		}
  
  	} else {
  		// clone options obj
  		options = $.extend(true, {}, options);
  
  		/*
  		 * As Zepto doesn't support .data() method for objects
  		 * and it works only in normal browsers
  		 * we assign "options" object directly to the DOM element. FTW!
  		 */
  		if(_isJQ) {
  			jqEl.data('magnificPopup', options);
  		} else {
  			jqEl[0].magnificPopup = options;
  		}
  
  		mfp.addGroup(jqEl, options);
  
  	}
  	return jqEl;
  };
  
  /*>>core*/
  
  /*>>inline*/
  
  var INLINE_NS = 'inline',
  	_hiddenClass,
  	_inlinePlaceholder,
  	_lastInlineElement,
  	_putInlineElementsBack = function() {
  		if(_lastInlineElement) {
  			_inlinePlaceholder.after( _lastInlineElement.addClass(_hiddenClass) ).detach();
  			_lastInlineElement = null;
  		}
  	};
  
  $.magnificPopup.registerModule(INLINE_NS, {
  	options: {
  		hiddenClass: 'hide', // will be appended with `mfp-` prefix
  		markup: '',
  		tNotFound: 'Content not found'
  	},
  	proto: {
  
  		initInline: function() {
  			mfp.types.push(INLINE_NS);
  
  			_mfpOn(CLOSE_EVENT+'.'+INLINE_NS, function() {
  				_putInlineElementsBack();
  			});
  		},
  
  		getInline: function(item, template) {
  
  			_putInlineElementsBack();
  
  			if(item.src) {
  				var inlineSt = mfp.st.inline,
  					el = $(item.src);
  
  				if(el.length) {
  
  					// If target element has parent - we replace it with placeholder and put it back after popup is closed
  					var parent = el[0].parentNode;
  					if(parent && parent.tagName) {
  						if(!_inlinePlaceholder) {
  							_hiddenClass = inlineSt.hiddenClass;
  							_inlinePlaceholder = _getEl(_hiddenClass);
  							_hiddenClass = 'mfp-'+_hiddenClass;
  						}
  						// replace target inline element with placeholder
  						_lastInlineElement = el.after(_inlinePlaceholder).detach().removeClass(_hiddenClass);
  					}
  
  					mfp.updateStatus('ready');
  				} else {
  					mfp.updateStatus('error', inlineSt.tNotFound);
  					el = $('<div>');
  				}
  
  				item.inlineElement = el;
  				return el;
  			}
  
  			mfp.updateStatus('ready');
  			mfp._parseMarkup(template, {}, item);
  			return template;
  		}
  	}
  });
  
  /*>>inline*/
  
  /*>>ajax*/
  var AJAX_NS = 'ajax',
  	_ajaxCur,
  	_removeAjaxCursor = function() {
  		if(_ajaxCur) {
  			$(document.body).removeClass(_ajaxCur);
  		}
  	},
  	_destroyAjaxRequest = function() {
  		_removeAjaxCursor();
  		if(mfp.req) {
  			mfp.req.abort();
  		}
  	};
  
  $.magnificPopup.registerModule(AJAX_NS, {
  
  	options: {
  		settings: null,
  		cursor: 'mfp-ajax-cur',
  		tError: '<a href="%url%">The content</a> could not be loaded.'
  	},
  
  	proto: {
  		initAjax: function() {
  			mfp.types.push(AJAX_NS);
  			_ajaxCur = mfp.st.ajax.cursor;
  
  			_mfpOn(CLOSE_EVENT+'.'+AJAX_NS, _destroyAjaxRequest);
  			_mfpOn('BeforeChange.' + AJAX_NS, _destroyAjaxRequest);
  		},
  		getAjax: function(item) {
  
  			if(_ajaxCur) {
  				$(document.body).addClass(_ajaxCur);
  			}
  
  			mfp.updateStatus('loading');
  
  			var opts = $.extend({
  				url: item.src,
  				success: function(data, textStatus, jqXHR) {
  					var temp = {
  						data:data,
  						xhr:jqXHR
  					};
  
  					_mfpTrigger('ParseAjax', temp);
  
  					mfp.appendContent( $(temp.data), AJAX_NS );
  
  					item.finished = true;
  
  					_removeAjaxCursor();
  
  					mfp._setFocus();
  
  					setTimeout(function() {
  						mfp.wrap.addClass(READY_CLASS);
  					}, 16);
  
  					mfp.updateStatus('ready');
  
  					_mfpTrigger('AjaxContentAdded');
  				},
  				error: function() {
  					_removeAjaxCursor();
  					item.finished = item.loadError = true;
  					mfp.updateStatus('error', mfp.st.ajax.tError.replace('%url%', item.src));
  				}
  			}, mfp.st.ajax.settings);
  
  			mfp.req = $.ajax(opts);
  
  			return '';
  		}
  	}
  });
  
  /*>>ajax*/
  
  /*>>image*/
  var _imgInterval,
  	_getTitle = function(item) {
  		if(item.data && item.data.title !== undefined)
  			return item.data.title;
  
  		var src = mfp.st.image.titleSrc;
  
  		if(src) {
  			if($.isFunction(src)) {
  				return src.call(mfp, item);
  			} else if(item.el) {
  				return item.el.attr(src) || '';
  			}
  		}
  		return '';
  	};
  
  $.magnificPopup.registerModule('image', {
  
  	options: {
  		markup: '<div class="mfp-figure">'+
  					'<div class="mfp-close"></div>'+
  					'<figure>'+
  						'<div class="mfp-img"></div>'+
  						'<figcaption>'+
  							'<div class="mfp-bottom-bar">'+
  								'<div class="mfp-title"></div>'+
  								'<div class="mfp-counter"></div>'+
  							'</div>'+
  						'</figcaption>'+
  					'</figure>'+
  				'</div>',
  		cursor: 'mfp-zoom-out-cur',
  		titleSrc: 'title',
  		verticalFit: true,
  		tError: '<a href="%url%">The image</a> could not be loaded.'
  	},
  
  	proto: {
  		initImage: function() {
  			var imgSt = mfp.st.image,
  				ns = '.image';
  
  			mfp.types.push('image');
  
  			_mfpOn(OPEN_EVENT+ns, function() {
  				if(mfp.currItem.type === 'image' && imgSt.cursor) {
  					$(document.body).addClass(imgSt.cursor);
  				}
  			});
  
  			_mfpOn(CLOSE_EVENT+ns, function() {
  				if(imgSt.cursor) {
  					$(document.body).removeClass(imgSt.cursor);
  				}
  				_window.off('resize' + EVENT_NS);
  			});
  
  			_mfpOn('Resize'+ns, mfp.resizeImage);
  			if(mfp.isLowIE) {
  				_mfpOn('AfterChange', mfp.resizeImage);
  			}
  		},
  		resizeImage: function() {
  			var item = mfp.currItem;
  			if(!item || !item.img) return;
  
  			if(mfp.st.image.verticalFit) {
  				var decr = 0;
  				// fix box-sizing in ie7/8
  				if(mfp.isLowIE) {
  					decr = parseInt(item.img.css('padding-top'), 10) + parseInt(item.img.css('padding-bottom'),10);
  				}
  				item.img.css('max-height', mfp.wH-decr);
  			}
  		},
  		_onImageHasSize: function(item) {
  			if(item.img) {
  
  				item.hasSize = true;
  
  				if(_imgInterval) {
  					clearInterval(_imgInterval);
  				}
  
  				item.isCheckingImgSize = false;
  
  				_mfpTrigger('ImageHasSize', item);
  
  				if(item.imgHidden) {
  					if(mfp.content)
  						mfp.content.removeClass('mfp-loading');
  
  					item.imgHidden = false;
  				}
  
  			}
  		},
  
  		/**
  		 * Function that loops until the image has size to display elements that rely on it asap
  		 */
  		findImageSize: function(item) {
  
  			var counter = 0,
  				img = item.img[0],
  				mfpSetInterval = function(delay) {
  
  					if(_imgInterval) {
  						clearInterval(_imgInterval);
  					}
  					// decelerating interval that checks for size of an image
  					_imgInterval = setInterval(function() {
  						if(img.naturalWidth > 0) {
  							mfp._onImageHasSize(item);
  							return;
  						}
  
  						if(counter > 200) {
  							clearInterval(_imgInterval);
  						}
  
  						counter++;
  						if(counter === 3) {
  							mfpSetInterval(10);
  						} else if(counter === 40) {
  							mfpSetInterval(50);
  						} else if(counter === 100) {
  							mfpSetInterval(500);
  						}
  					}, delay);
  				};
  
  			mfpSetInterval(1);
  		},
  
  		getImage: function(item, template) {
  
  			var guard = 0,
  
  				// image load complete handler
  				onLoadComplete = function() {
  					if(item) {
  						if (item.img[0].complete) {
  							item.img.off('.mfploader');
  
  							if(item === mfp.currItem){
  								mfp._onImageHasSize(item);
  
  								mfp.updateStatus('ready');
  							}
  
  							item.hasSize = true;
  							item.loaded = true;
  
  							_mfpTrigger('ImageLoadComplete');
  
  						}
  						else {
  							// if image complete check fails 200 times (20 sec), we assume that there was an error.
  							guard++;
  							if(guard < 200) {
  								setTimeout(onLoadComplete,100);
  							} else {
  								onLoadError();
  							}
  						}
  					}
  				},
  
  				// image error handler
  				onLoadError = function() {
  					if(item) {
  						item.img.off('.mfploader');
  						if(item === mfp.currItem){
  							mfp._onImageHasSize(item);
  							mfp.updateStatus('error', imgSt.tError.replace('%url%', item.src) );
  						}
  
  						item.hasSize = true;
  						item.loaded = true;
  						item.loadError = true;
  					}
  				},
  				imgSt = mfp.st.image;
  
  
  			var el = template.find('.mfp-img');
  			if(el.length) {
  				var img = document.createElement('img');
  				img.className = 'mfp-img';
  				if(item.el && item.el.find('img').length) {
  					img.alt = item.el.find('img').attr('alt');
  				}
  				item.img = $(img).on('load.mfploader', onLoadComplete).on('error.mfploader', onLoadError);
  				img.src = item.src;
  
  				// without clone() "error" event is not firing when IMG is replaced by new IMG
  				// TODO: find a way to avoid such cloning
  				if(el.is('img')) {
  					item.img = item.img.clone();
  				}
  
  				img = item.img[0];
  				if(img.naturalWidth > 0) {
  					item.hasSize = true;
  				} else if(!img.width) {
  					item.hasSize = false;
  				}
  			}
  
  			mfp._parseMarkup(template, {
  				title: _getTitle(item),
  				img_replaceWith: item.img
  			}, item);
  
  			mfp.resizeImage();
  
  			if(item.hasSize) {
  				if(_imgInterval) clearInterval(_imgInterval);
  
  				if(item.loadError) {
  					template.addClass('mfp-loading');
  					mfp.updateStatus('error', imgSt.tError.replace('%url%', item.src) );
  				} else {
  					template.removeClass('mfp-loading');
  					mfp.updateStatus('ready');
  				}
  				return template;
  			}
  
  			mfp.updateStatus('loading');
  			item.loading = true;
  
  			if(!item.hasSize) {
  				item.imgHidden = true;
  				template.addClass('mfp-loading');
  				mfp.findImageSize(item);
  			}
  
  			return template;
  		}
  	}
  });
  
  /*>>image*/
  
  /*>>zoom*/
  var hasMozTransform,
  	getHasMozTransform = function() {
  		if(hasMozTransform === undefined) {
  			hasMozTransform = document.createElement('p').style.MozTransform !== undefined;
  		}
  		return hasMozTransform;
  	};
  
  $.magnificPopup.registerModule('zoom', {
  
  	options: {
  		enabled: false,
  		easing: 'ease-in-out',
  		duration: 300,
  		opener: function(element) {
  			return element.is('img') ? element : element.find('img');
  		}
  	},
  
  	proto: {
  
  		initZoom: function() {
  			var zoomSt = mfp.st.zoom,
  				ns = '.zoom',
  				image;
  
  			if(!zoomSt.enabled || !mfp.supportsTransition) {
  				return;
  			}
  
  			var duration = zoomSt.duration,
  				getElToAnimate = function(image) {
  					var newImg = image.clone().removeAttr('style').removeAttr('class').addClass('mfp-animated-image'),
  						transition = 'all '+(zoomSt.duration/1000)+'s ' + zoomSt.easing,
  						cssObj = {
  							position: 'fixed',
  							zIndex: 9999,
  							left: 0,
  							top: 0,
  							'-webkit-backface-visibility': 'hidden'
  						},
  						t = 'transition';
  
  					cssObj['-webkit-'+t] = cssObj['-moz-'+t] = cssObj['-o-'+t] = cssObj[t] = transition;
  
  					newImg.css(cssObj);
  					return newImg;
  				},
  				showMainContent = function() {
  					mfp.content.css('visibility', 'visible');
  				},
  				openTimeout,
  				animatedImg;
  
  			_mfpOn('BuildControls'+ns, function() {
  				if(mfp._allowZoom()) {
  
  					clearTimeout(openTimeout);
  					mfp.content.css('visibility', 'hidden');
  
  					// Basically, all code below does is clones existing image, puts in on top of the current one and animated it
  
  					image = mfp._getItemToZoom();
  
  					if(!image) {
  						showMainContent();
  						return;
  					}
  
  					animatedImg = getElToAnimate(image);
  
  					animatedImg.css( mfp._getOffset() );
  
  					mfp.wrap.append(animatedImg);
  
  					openTimeout = setTimeout(function() {
  						animatedImg.css( mfp._getOffset( true ) );
  						openTimeout = setTimeout(function() {
  
  							showMainContent();
  
  							setTimeout(function() {
  								animatedImg.remove();
  								image = animatedImg = null;
  								_mfpTrigger('ZoomAnimationEnded');
  							}, 16); // avoid blink when switching images
  
  						}, duration); // this timeout equals animation duration
  
  					}, 16); // by adding this timeout we avoid short glitch at the beginning of animation
  
  
  					// Lots of timeouts...
  				}
  			});
  			_mfpOn(BEFORE_CLOSE_EVENT+ns, function() {
  				if(mfp._allowZoom()) {
  
  					clearTimeout(openTimeout);
  
  					mfp.st.removalDelay = duration;
  
  					if(!image) {
  						image = mfp._getItemToZoom();
  						if(!image) {
  							return;
  						}
  						animatedImg = getElToAnimate(image);
  					}
  
  					animatedImg.css( mfp._getOffset(true) );
  					mfp.wrap.append(animatedImg);
  					mfp.content.css('visibility', 'hidden');
  
  					setTimeout(function() {
  						animatedImg.css( mfp._getOffset() );
  					}, 16);
  				}
  
  			});
  
  			_mfpOn(CLOSE_EVENT+ns, function() {
  				if(mfp._allowZoom()) {
  					showMainContent();
  					if(animatedImg) {
  						animatedImg.remove();
  					}
  					image = null;
  				}
  			});
  		},
  
  		_allowZoom: function() {
  			return mfp.currItem.type === 'image';
  		},
  
  		_getItemToZoom: function() {
  			if(mfp.currItem.hasSize) {
  				return mfp.currItem.img;
  			} else {
  				return false;
  			}
  		},
  
  		// Get element postion relative to viewport
  		_getOffset: function(isLarge) {
  			var el;
  			if(isLarge) {
  				el = mfp.currItem.img;
  			} else {
  				el = mfp.st.zoom.opener(mfp.currItem.el || mfp.currItem);
  			}
  
  			var offset = el.offset();
  			var paddingTop = parseInt(el.css('padding-top'),10);
  			var paddingBottom = parseInt(el.css('padding-bottom'),10);
  			offset.top -= ( $(window).scrollTop() - paddingTop );
  
  
  			/*
  
  			Animating left + top + width/height looks glitchy in Firefox, but perfect in Chrome. And vice-versa.
  
  			 */
  			var obj = {
  				width: el.width(),
  				// fix Zepto height+padding issue
  				height: (_isJQ ? el.innerHeight() : el[0].offsetHeight) - paddingBottom - paddingTop
  			};
  
  			// I hate to do this, but there is no another option
  			if( getHasMozTransform() ) {
  				obj['-moz-transform'] = obj['transform'] = 'translate(' + offset.left + 'px,' + offset.top + 'px)';
  			} else {
  				obj.left = offset.left;
  				obj.top = offset.top;
  			}
  			return obj;
  		}
  
  	}
  });
  
  
  
  /*>>zoom*/
  
  /*>>iframe*/
  
  var IFRAME_NS = 'iframe',
  	_emptyPage = '//about:blank',
  
  	_fixIframeBugs = function(isShowing) {
  		if(mfp.currTemplate[IFRAME_NS]) {
  			var el = mfp.currTemplate[IFRAME_NS].find('iframe');
  			if(el.length) {
  				// reset src after the popup is closed to avoid "video keeps playing after popup is closed" bug
  				if(!isShowing) {
  					el[0].src = _emptyPage;
  				}
  
  				// IE8 black screen bug fix
  				if(mfp.isIE8) {
  					el.css('display', isShowing ? 'block' : 'none');
  				}
  			}
  		}
  	};
  
  $.magnificPopup.registerModule(IFRAME_NS, {
  
  	options: {
  		markup: '<div class="mfp-iframe-scaler">'+
  					'<div class="mfp-close"></div>'+
  					'<iframe class="mfp-iframe" src="//about:blank" frameborder="0" allowfullscreen></iframe>'+
  				'</div>',
  
  		srcAction: 'iframe_src',
  
  		// we don't care and support only one default type of URL by default
  		patterns: {
  			youtube: {
  				index: 'youtube.com',
  				id: 'v=',
  				src: '//www.youtube.com/embed/%id%?autoplay=1'
  			},
  			vimeo: {
  				index: 'vimeo.com/',
  				id: '/',
  				src: '//player.vimeo.com/video/%id%?autoplay=1'
  			},
  			gmaps: {
  				index: '//maps.google.',
  				src: '%id%&output=embed'
  			}
  		}
  	},
  
  	proto: {
  		initIframe: function() {
  			mfp.types.push(IFRAME_NS);
  
  			_mfpOn('BeforeChange', function(e, prevType, newType) {
  				if(prevType !== newType) {
  					if(prevType === IFRAME_NS) {
  						_fixIframeBugs(); // iframe if removed
  					} else if(newType === IFRAME_NS) {
  						_fixIframeBugs(true); // iframe is showing
  					}
  				}// else {
  					// iframe source is switched, don't do anything
  				//}
  			});
  
  			_mfpOn(CLOSE_EVENT + '.' + IFRAME_NS, function() {
  				_fixIframeBugs();
  			});
  		},
  
  		getIframe: function(item, template) {
  			var embedSrc = item.src;
  			var iframeSt = mfp.st.iframe;
  
  			$.each(iframeSt.patterns, function() {
  				if(embedSrc.indexOf( this.index ) > -1) {
  					if(this.id) {
  						if(typeof this.id === 'string') {
  							embedSrc = embedSrc.substr(embedSrc.lastIndexOf(this.id)+this.id.length, embedSrc.length);
  						} else {
  							embedSrc = this.id.call( this, embedSrc );
  						}
  					}
  					embedSrc = this.src.replace('%id%', embedSrc );
  					return false; // break;
  				}
  			});
  
  			var dataObj = {};
  			if(iframeSt.srcAction) {
  				dataObj[iframeSt.srcAction] = embedSrc;
  			}
  			mfp._parseMarkup(template, dataObj, item);
  
  			mfp.updateStatus('ready');
  
  			return template;
  		}
  	}
  });
  
  
  
  /*>>iframe*/
  
  /*>>gallery*/
  /**
   * Get looped index depending on number of slides
   */
  var _getLoopedId = function(index) {
  		var numSlides = mfp.items.length;
  		if(index > numSlides - 1) {
  			return index - numSlides;
  		} else  if(index < 0) {
  			return numSlides + index;
  		}
  		return index;
  	},
  	_replaceCurrTotal = function(text, curr, total) {
  		return text.replace(/%curr%/gi, curr + 1).replace(/%total%/gi, total);
  	};
  
  $.magnificPopup.registerModule('gallery', {
  
  	options: {
  		enabled: false,
  		arrowMarkup: '<button title="%title%" type="button" class="mfp-arrow mfp-arrow-%dir%"></button>',
  		preload: [0,2],
  		navigateByImgClick: true,
  		arrows: true,
  
  		tPrev: 'Previous (Left arrow key)',
  		tNext: 'Next (Right arrow key)',
  		tCounter: '%curr% of %total%'
  	},
  
  	proto: {
  		initGallery: function() {
  
  			var gSt = mfp.st.gallery,
  				ns = '.mfp-gallery';
  
  			mfp.direction = true; // true - next, false - prev
  
  			if(!gSt || !gSt.enabled ) return false;
  
  			_wrapClasses += ' mfp-gallery';
  
  			_mfpOn(OPEN_EVENT+ns, function() {
  
  				if(gSt.navigateByImgClick) {
  					mfp.wrap.on('click'+ns, '.mfp-img', function() {
  						if(mfp.items.length > 1) {
  							mfp.next();
  							return false;
  						}
  					});
  				}
  
  				_document.on('keydown'+ns, function(e) {
  					if (e.keyCode === 37) {
  						mfp.prev();
  					} else if (e.keyCode === 39) {
  						mfp.next();
  					}
  				});
  			});
  
  			_mfpOn('UpdateStatus'+ns, function(e, data) {
  				if(data.text) {
  					data.text = _replaceCurrTotal(data.text, mfp.currItem.index, mfp.items.length);
  				}
  			});
  
  			_mfpOn(MARKUP_PARSE_EVENT+ns, function(e, element, values, item) {
  				var l = mfp.items.length;
  				values.counter = l > 1 ? _replaceCurrTotal(gSt.tCounter, item.index, l) : '';
  			});
  
  			_mfpOn('BuildControls' + ns, function() {
  				if(mfp.items.length > 1 && gSt.arrows && !mfp.arrowLeft) {
  					var markup = gSt.arrowMarkup,
  						arrowLeft = mfp.arrowLeft = $( markup.replace(/%title%/gi, gSt.tPrev).replace(/%dir%/gi, 'left') ).addClass(PREVENT_CLOSE_CLASS),
  						arrowRight = mfp.arrowRight = $( markup.replace(/%title%/gi, gSt.tNext).replace(/%dir%/gi, 'right') ).addClass(PREVENT_CLOSE_CLASS);
  
  					arrowLeft.click(function() {
  						mfp.prev();
  					});
  					arrowRight.click(function() {
  						mfp.next();
  					});
  
  					mfp.container.append(arrowLeft.add(arrowRight));
  				}
  			});
  
  			_mfpOn(CHANGE_EVENT+ns, function() {
  				if(mfp._preloadTimeout) clearTimeout(mfp._preloadTimeout);
  
  				mfp._preloadTimeout = setTimeout(function() {
  					mfp.preloadNearbyImages();
  					mfp._preloadTimeout = null;
  				}, 16);
  			});
  
  
  			_mfpOn(CLOSE_EVENT+ns, function() {
  				_document.off(ns);
  				mfp.wrap.off('click'+ns);
  				mfp.arrowRight = mfp.arrowLeft = null;
  			});
  
  		},
  		next: function() {
  			mfp.direction = true;
  			mfp.index = _getLoopedId(mfp.index + 1);
  			mfp.updateItemHTML();
  		},
  		prev: function() {
  			mfp.direction = false;
  			mfp.index = _getLoopedId(mfp.index - 1);
  			mfp.updateItemHTML();
  		},
  		goTo: function(newIndex) {
  			mfp.direction = (newIndex >= mfp.index);
  			mfp.index = newIndex;
  			mfp.updateItemHTML();
  		},
  		preloadNearbyImages: function() {
  			var p = mfp.st.gallery.preload,
  				preloadBefore = Math.min(p[0], mfp.items.length),
  				preloadAfter = Math.min(p[1], mfp.items.length),
  				i;
  
  			for(i = 1; i <= (mfp.direction ? preloadAfter : preloadBefore); i++) {
  				mfp._preloadItem(mfp.index+i);
  			}
  			for(i = 1; i <= (mfp.direction ? preloadBefore : preloadAfter); i++) {
  				mfp._preloadItem(mfp.index-i);
  			}
  		},
  		_preloadItem: function(index) {
  			index = _getLoopedId(index);
  
  			if(mfp.items[index].preloaded) {
  				return;
  			}
  
  			var item = mfp.items[index];
  			if(!item.parsed) {
  				item = mfp.parseEl( index );
  			}
  
  			_mfpTrigger('LazyLoad', item);
  
  			if(item.type === 'image') {
  				item.img = $('<img class="mfp-img" />').on('load.mfploader', function() {
  					item.hasSize = true;
  				}).on('error.mfploader', function() {
  					item.hasSize = true;
  					item.loadError = true;
  					_mfpTrigger('LazyLoadError', item);
  				}).attr('src', item.src);
  			}
  
  
  			item.preloaded = true;
  		}
  	}
  });
  
  /*>>gallery*/
  
  /*>>retina*/
  
  var RETINA_NS = 'retina';
  
  $.magnificPopup.registerModule(RETINA_NS, {
  	options: {
  		replaceSrc: function(item) {
  			return item.src.replace(/\.\w+$/, function(m) { return '@2x' + m; });
  		},
  		ratio: 1 // Function or number.  Set to 1 to disable.
  	},
  	proto: {
  		initRetina: function() {
  			if(window.devicePixelRatio > 1) {
  
  				var st = mfp.st.retina,
  					ratio = st.ratio;
  
  				ratio = !isNaN(ratio) ? ratio : ratio();
  
  				if(ratio > 1) {
  					_mfpOn('ImageHasSize' + '.' + RETINA_NS, function(e, item) {
  						item.img.css({
  							'max-width': item.img[0].naturalWidth / ratio,
  							'width': '100%'
  						});
  					});
  					_mfpOn('ElementParse' + '.' + RETINA_NS, function(e, item) {
  						item.src = st.replaceSrc(item, ratio);
  					});
  				}
  			}
  
  		}
  	}
  });
  
  /*>>retina*/
   _checkInstance(); }));
  
  /* ====================================================================================================
    WOW animate on scroll
  ==================================================================================================== */
  /*! WOW - v1.1.3 - 2016-05-06
  * Copyright (c) 2016 Matthieu Aussaguel;*/
  (function() {
    var MutationObserver, Util, WeakMap, getComputedStyle, getComputedStyleRX,
      bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
      indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
  
    Util = (function() {
      function Util() {}
  
      Util.prototype.extend = function(custom, defaults) {
        var key, value;
        for (key in defaults) {
          value = defaults[key];
          if (custom[key] == null) {
            custom[key] = value;
          }
        }
        return custom;
      };
  
      Util.prototype.isMobile = function(agent) {
        return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(agent);
      };
  
      Util.prototype.createEvent = function(event, bubble, cancel, detail) {
        var customEvent;
        if (bubble == null) {
          bubble = false;
        }
        if (cancel == null) {
          cancel = false;
        }
        if (detail == null) {
          detail = null;
        }
        if (document.createEvent != null) {
          customEvent = document.createEvent('CustomEvent');
          customEvent.initCustomEvent(event, bubble, cancel, detail);
        } else if (document.createEventObject != null) {
          customEvent = document.createEventObject();
          customEvent.eventType = event;
        } else {
          customEvent.eventName = event;
        }
        return customEvent;
      };
  
      Util.prototype.emitEvent = function(elem, event) {
        if (elem.dispatchEvent != null) {
          return elem.dispatchEvent(event);
        } else if (event in (elem != null)) {
          return elem[event]();
        } else if (("on" + event) in (elem != null)) {
          return elem["on" + event]();
        }
      };
  
      Util.prototype.addEvent = function(elem, event, fn) {
        if (elem.addEventListener != null) {
          return elem.addEventListener(event, fn, false);
        } else if (elem.attachEvent != null) {
          return elem.attachEvent("on" + event, fn);
        } else {
          return elem[event] = fn;
        }
      };
  
      Util.prototype.removeEvent = function(elem, event, fn) {
        if (elem.removeEventListener != null) {
          return elem.removeEventListener(event, fn, false);
        } else if (elem.detachEvent != null) {
          return elem.detachEvent("on" + event, fn);
        } else {
          return delete elem[event];
        }
      };
  
      Util.prototype.innerHeight = function() {
        if ('innerHeight' in window) {
          return window.innerHeight;
        } else {
          return document.documentElement.clientHeight;
        }
      };
  
      return Util;
  
    })();
  
    WeakMap = this.WeakMap || this.MozWeakMap || (WeakMap = (function() {
      function WeakMap() {
        this.keys = [];
        this.values = [];
      }
  
      WeakMap.prototype.get = function(key) {
        var i, item, j, len, ref;
        ref = this.keys;
        for (i = j = 0, len = ref.length; j < len; i = ++j) {
          item = ref[i];
          if (item === key) {
            return this.values[i];
          }
        }
      };
  
      WeakMap.prototype.set = function(key, value) {
        var i, item, j, len, ref;
        ref = this.keys;
        for (i = j = 0, len = ref.length; j < len; i = ++j) {
          item = ref[i];
          if (item === key) {
            this.values[i] = value;
            return;
          }
        }
        this.keys.push(key);
        return this.values.push(value);
      };
  
      return WeakMap;
  
    })());
  
    MutationObserver = this.MutationObserver || this.WebkitMutationObserver || this.MozMutationObserver || (MutationObserver = (function() {
      function MutationObserver() {
        if (typeof console !== "undefined" && console !== null) {
          console.warn('MutationObserver is not supported by your browser.');
        }
        if (typeof console !== "undefined" && console !== null) {
          console.warn('WOW.js cannot detect dom mutations, please call .sync() after loading new content.');
        }
      }
  
      MutationObserver.notSupported = true;
  
      MutationObserver.prototype.observe = function() {};
  
      return MutationObserver;
  
    })());
  
    getComputedStyle = this.getComputedStyle || function(el, pseudo) {
      this.getPropertyValue = function(prop) {
        var ref;
        if (prop === 'float') {
          prop = 'styleFloat';
        }
        if (getComputedStyleRX.test(prop)) {
          prop.replace(getComputedStyleRX, function(_, _char) {
            return _char.toUpperCase();
          });
        }
        return ((ref = el.currentStyle) != null ? ref[prop] : void 0) || null;
      };
      return this;
    };
  
    getComputedStyleRX = /(\-([a-z]){1})/g;
  
    this.WOW = (function() {
      WOW.prototype.defaults = {
        boxClass: 'wow',
        animateClass: 'animated',
        offset: 0,
        mobile: true,
        live: true,
        callback: null,
        scrollContainer: null
      };
  
      function WOW(options) {
        if (options == null) {
          options = {};
        }
        this.scrollCallback = bind(this.scrollCallback, this);
        this.scrollHandler = bind(this.scrollHandler, this);
        this.resetAnimation = bind(this.resetAnimation, this);
        this.start = bind(this.start, this);
        this.scrolled = true;
        this.config = this.util().extend(options, this.defaults);
        if (options.scrollContainer != null) {
          this.config.scrollContainer = document.querySelector(options.scrollContainer);
        }
        this.animationNameCache = new WeakMap();
        this.wowEvent = this.util().createEvent(this.config.boxClass);
      }
  
      WOW.prototype.init = function() {
        var ref;
        this.element = window.document.documentElement;
        if ((ref = document.readyState) === "interactive" || ref === "complete") {
          this.start();
        } else {
          this.util().addEvent(document, 'DOMContentLoaded', this.start);
        }
        return this.finished = [];
      };
  
      WOW.prototype.start = function() {
        var box, j, len, ref;
        this.stopped = false;
        this.boxes = (function() {
          var j, len, ref, results;
          ref = this.element.querySelectorAll("." + this.config.boxClass);
          results = [];
          for (j = 0, len = ref.length; j < len; j++) {
            box = ref[j];
            results.push(box);
          }
          return results;
        }).call(this);
        this.all = (function() {
          var j, len, ref, results;
          ref = this.boxes;
          results = [];
          for (j = 0, len = ref.length; j < len; j++) {
            box = ref[j];
            results.push(box);
          }
          return results;
        }).call(this);
        if (this.boxes.length) {
          if (this.disabled()) {
            this.resetStyle();
          } else {
            ref = this.boxes;
            for (j = 0, len = ref.length; j < len; j++) {
              box = ref[j];
              this.applyStyle(box, true);
            }
          }
        }
        if (!this.disabled()) {
          this.util().addEvent(this.config.scrollContainer || window, 'scroll', this.scrollHandler);
          this.util().addEvent(window, 'resize', this.scrollHandler);
          this.interval = setInterval(this.scrollCallback, 50);
        }
        if (this.config.live) {
          return new MutationObserver((function(_this) {
            return function(records) {
              var k, len1, node, record, results;
              results = [];
              for (k = 0, len1 = records.length; k < len1; k++) {
                record = records[k];
                results.push((function() {
                  var l, len2, ref1, results1;
                  ref1 = record.addedNodes || [];
                  results1 = [];
                  for (l = 0, len2 = ref1.length; l < len2; l++) {
                    node = ref1[l];
                    results1.push(this.doSync(node));
                  }
                  return results1;
                }).call(_this));
              }
              return results;
            };
          })(this)).observe(document.body, {
            childList: true,
            subtree: true
          });
        }
      };
  
      WOW.prototype.stop = function() {
        this.stopped = true;
        this.util().removeEvent(this.config.scrollContainer || window, 'scroll', this.scrollHandler);
        this.util().removeEvent(window, 'resize', this.scrollHandler);
        if (this.interval != null) {
          return clearInterval(this.interval);
        }
      };
  
      WOW.prototype.sync = function(element) {
        if (MutationObserver.notSupported) {
          return this.doSync(this.element);
        }
      };
  
      WOW.prototype.doSync = function(element) {
        var box, j, len, ref, results;
        if (element == null) {
          element = this.element;
        }
        if (element.nodeType !== 1) {
          return;
        }
        element = element.parentNode || element;
        ref = element.querySelectorAll("." + this.config.boxClass);
        results = [];
        for (j = 0, len = ref.length; j < len; j++) {
          box = ref[j];
          if (indexOf.call(this.all, box) < 0) {
            this.boxes.push(box);
            this.all.push(box);
            if (this.stopped || this.disabled()) {
              this.resetStyle();
            } else {
              this.applyStyle(box, true);
            }
            results.push(this.scrolled = true);
          } else {
            results.push(void 0);
          }
        }
        return results;
      };
  
      WOW.prototype.show = function(box) {
        this.applyStyle(box);
        box.className = box.className + " " + this.config.animateClass;
        if (this.config.callback != null) {
          this.config.callback(box);
        }
        this.util().emitEvent(box, this.wowEvent);
        this.util().addEvent(box, 'animationend', this.resetAnimation);
        this.util().addEvent(box, 'oanimationend', this.resetAnimation);
        this.util().addEvent(box, 'webkitAnimationEnd', this.resetAnimation);
        this.util().addEvent(box, 'MSAnimationEnd', this.resetAnimation);
        return box;
      };
  
      WOW.prototype.applyStyle = function(box, hidden) {
        var delay, duration, iteration;
        duration = box.getAttribute('data-wow-duration');
        delay = box.getAttribute('data-wow-delay');
        iteration = box.getAttribute('data-wow-iteration');
        return this.animate((function(_this) {
          return function() {
            return _this.customStyle(box, hidden, duration, delay, iteration);
          };
        })(this));
      };
  
      WOW.prototype.animate = (function() {
        if ('requestAnimationFrame' in window) {
          return function(callback) {
            return window.requestAnimationFrame(callback);
          };
        } else {
          return function(callback) {
            return callback();
          };
        }
      })();
  
      WOW.prototype.resetStyle = function() {
        var box, j, len, ref, results;
        ref = this.boxes;
        results = [];
        for (j = 0, len = ref.length; j < len; j++) {
          box = ref[j];
          results.push(box.style.visibility = 'visible');
        }
        return results;
      };
  
      WOW.prototype.resetAnimation = function(event) {
        var target;
        if (event.type.toLowerCase().indexOf('animationend') >= 0) {
          target = event.target || event.srcElement;
          return target.className = target.className.replace(this.config.animateClass, '').trim();
        }
      };
  
      WOW.prototype.customStyle = function(box, hidden, duration, delay, iteration) {
        if (hidden) {
          this.cacheAnimationName(box);
        }
        box.style.visibility = hidden ? 'hidden' : 'visible';
        if (duration) {
          this.vendorSet(box.style, {
            animationDuration: duration
          });
        }
        if (delay) {
          this.vendorSet(box.style, {
            animationDelay: delay
          });
        }
        if (iteration) {
          this.vendorSet(box.style, {
            animationIterationCount: iteration
          });
        }
        this.vendorSet(box.style, {
          animationName: hidden ? 'none' : this.cachedAnimationName(box)
        });
        return box;
      };
  
      WOW.prototype.vendors = ["moz", "webkit"];
  
      WOW.prototype.vendorSet = function(elem, properties) {
        var name, results, value, vendor;
        results = [];
        for (name in properties) {
          value = properties[name];
          elem["" + name] = value;
          results.push((function() {
            var j, len, ref, results1;
            ref = this.vendors;
            results1 = [];
            for (j = 0, len = ref.length; j < len; j++) {
              vendor = ref[j];
              results1.push(elem["" + vendor + (name.charAt(0).toUpperCase()) + (name.substr(1))] = value);
            }
            return results1;
          }).call(this));
        }
        return results;
      };
  
      WOW.prototype.vendorCSS = function(elem, property) {
        var j, len, ref, result, style, vendor;
        style = getComputedStyle(elem);
        result = style.getPropertyCSSValue(property);
        ref = this.vendors;
        for (j = 0, len = ref.length; j < len; j++) {
          vendor = ref[j];
          result = result || style.getPropertyCSSValue("-" + vendor + "-" + property);
        }
        return result;
      };
  
      WOW.prototype.animationName = function(box) {
        var animationName, error;
        try {
          animationName = this.vendorCSS(box, 'animation-name').cssText;
        } catch (error) {
          animationName = getComputedStyle(box).getPropertyValue('animation-name');
        }
        if (animationName === 'none') {
          return '';
        } else {
          return animationName;
        }
      };
  
      WOW.prototype.cacheAnimationName = function(box) {
        return this.animationNameCache.set(box, this.animationName(box));
      };
  
      WOW.prototype.cachedAnimationName = function(box) {
        return this.animationNameCache.get(box);
      };
  
      WOW.prototype.scrollHandler = function() {
        return this.scrolled = true;
      };
  
      WOW.prototype.scrollCallback = function() {
        var box;
        if (this.scrolled) {
          this.scrolled = false;
          this.boxes = (function() {
            var j, len, ref, results;
            ref = this.boxes;
            results = [];
            for (j = 0, len = ref.length; j < len; j++) {
              box = ref[j];
              if (!(box)) {
                continue;
              }
              if (this.isVisible(box)) {
                this.show(box);
                continue;
              }
              results.push(box);
            }
            return results;
          }).call(this);
          if (!(this.boxes.length || this.config.live)) {
            return this.stop();
          }
        }
      };
  
      WOW.prototype.offsetTop = function(element) {
        var top;
        while (element.offsetTop === void 0) {
          element = element.parentNode;
        }
        top = element.offsetTop;
        while (element = element.offsetParent) {
          top += element.offsetTop;
        }
        return top;
      };
  
      WOW.prototype.isVisible = function(box) {
        var bottom, offset, top, viewBottom, viewTop;
        offset = box.getAttribute('data-wow-offset') || this.config.offset;
        viewTop = (this.config.scrollContainer && this.config.scrollContainer.scrollTop) || window.pageYOffset;
        viewBottom = viewTop + Math.min(this.element.clientHeight, this.util().innerHeight()) - offset;
        top = this.offsetTop(box);
        bottom = top + box.clientHeight;
        return top <= viewBottom && bottom >= viewTop;
      };
  
      WOW.prototype.util = function() {
        return this._util != null ? this._util : this._util = new Util();
      };
  
      WOW.prototype.disabled = function() {
        return !this.config.mobile && this.util().isMobile(navigator.userAgent);
      };
  
      return WOW;
  
    })();
  
  }).call(this);
  
  /* ====================================================================================================
    Ion.RangeSlider
  ==================================================================================================== */
  // Ion.RangeSlider
  // version 2.2.0 Build: 380
  // © Denis Ineshin, 2017
  // https://github.com/IonDen
  //
  // Project page:    http://ionden.com/a/plugins/ion.rangeSlider/en.html
  // GitHub page:     https://github.com/IonDen/ion.rangeSlider
  //
  // Released under MIT licence:
  // http://ionden.com/a/plugins/licence-en.html
  // =====================================================================================================================
  
  ;(function(factory) {
      if (typeof define === "function" && define.amd) {
          define(["jquery"], function (jQuery) {
              return factory(jQuery, document, window, navigator);
          });
      } else if (typeof exports === "object") {
          factory(require("jquery"), document, window, navigator);
      } else {
          factory(jQuery, document, window, navigator);
      }
  } (function ($, document, window, navigator, undefined) {
      "use strict";
  
      // =================================================================================================================
      // Service
  
      var plugin_count = 0;
  
      // IE8 fix
      var is_old_ie = (function () {
          var n = navigator.userAgent,
              r = /msie\s\d+/i,
              v;
          if (n.search(r) > 0) {
              v = r.exec(n).toString();
              v = v.split(" ")[1];
              if (v < 9) {
                  $("html").addClass("lt-ie9");
                  return true;
              }
          }
          return false;
      } ());
      if (!Function.prototype.bind) {
          Function.prototype.bind = function bind(that) {
  
              var target = this;
              var slice = [].slice;
  
              if (typeof target != "function") {
                  throw new TypeError();
              }
  
              var args = slice.call(arguments, 1),
                  bound = function () {
  
                      if (this instanceof bound) {
  
                          var F = function(){};
                          F.prototype = target.prototype;
                          var self = new F();
  
                          var result = target.apply(
                              self,
                              args.concat(slice.call(arguments))
                          );
                          if (Object(result) === result) {
                              return result;
                          }
                          return self;
  
                      } else {
  
                          return target.apply(
                              that,
                              args.concat(slice.call(arguments))
                          );
  
                      }
  
                  };
  
              return bound;
          };
      }
      if (!Array.prototype.indexOf) {
          Array.prototype.indexOf = function(searchElement, fromIndex) {
              var k;
              if (this == null) {
                  throw new TypeError('"this" is null or not defined');
              }
              var O = Object(this);
              var len = O.length >>> 0;
              if (len === 0) {
                  return -1;
              }
              var n = +fromIndex || 0;
              if (Math.abs(n) === Infinity) {
                  n = 0;
              }
              if (n >= len) {
                  return -1;
              }
              k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);
              while (k < len) {
                  if (k in O && O[k] === searchElement) {
                      return k;
                  }
                  k++;
              }
              return -1;
          };
      }
  
  
  
      // =================================================================================================================
      // Template
  
      var base_html =
          '<span class="irs">' +
          '<span class="irs-line" tabindex="0"><span class="irs-line-left"></span><span class="irs-line-mid"></span><span class="irs-line-right"></span></span>' +
          '<span class="irs-min">0</span><span class="irs-max">1</span>' +
          '<span class="irs-from">0</span><span class="irs-to">0</span><span class="irs-single">0</span>' +
          '</span>' +
          '<span class="irs-grid"></span>' +
          '<span class="irs-bar"></span>';
  
      var single_html =
          '<span class="irs-bar-edge"></span>' +
          '<span class="irs-shadow shadow-single"></span>' +
          '<span class="irs-slider single"></span>';
  
      var double_html =
          '<span class="irs-shadow shadow-from"></span>' +
          '<span class="irs-shadow shadow-to"></span>' +
          '<span class="irs-slider from"></span>' +
          '<span class="irs-slider to"></span>';
  
      var disable_html =
          '<span class="irs-disable-mask"></span>';
  
  
  
      // =================================================================================================================
      // Core
  
      /**
       * Main plugin constructor
       *
       * @param input {Object} link to base input element
       * @param options {Object} slider config
       * @param plugin_count {Number}
       * @constructor
       */
      var IonRangeSlider = function (input, options, plugin_count) {
          this.VERSION = "2.2.0";
          this.input = input;
          this.plugin_count = plugin_count;
          this.current_plugin = 0;
          this.calc_count = 0;
          this.update_tm = 0;
          this.old_from = 0;
          this.old_to = 0;
          this.old_min_interval = null;
          this.raf_id = null;
          this.dragging = false;
          this.force_redraw = false;
          this.no_diapason = false;
          this.has_tab_index = true;
          this.is_key = false;
          this.is_update = false;
          this.is_start = true;
          this.is_finish = false;
          this.is_active = false;
          this.is_resize = false;
          this.is_click = false;
  
          options = options || {};
  
          // cache for links to all DOM elements
          this.$cache = {
              win: $(window),
              body: $(document.body),
              input: $(input),
              cont: null,
              rs: null,
              min: null,
              max: null,
              from: null,
              to: null,
              single: null,
              bar: null,
              line: null,
              s_single: null,
              s_from: null,
              s_to: null,
              shad_single: null,
              shad_from: null,
              shad_to: null,
              edge: null,
              grid: null,
              grid_labels: []
          };
  
          // storage for measure variables
          this.coords = {
              // left
              x_gap: 0,
              x_pointer: 0,
  
              // width
              w_rs: 0,
              w_rs_old: 0,
              w_handle: 0,
  
              // percents
              p_gap: 0,
              p_gap_left: 0,
              p_gap_right: 0,
              p_step: 0,
              p_pointer: 0,
              p_handle: 0,
              p_single_fake: 0,
              p_single_real: 0,
              p_from_fake: 0,
              p_from_real: 0,
              p_to_fake: 0,
              p_to_real: 0,
              p_bar_x: 0,
              p_bar_w: 0,
  
              // grid
              grid_gap: 0,
              big_num: 0,
              big: [],
              big_w: [],
              big_p: [],
              big_x: []
          };
  
          // storage for labels measure variables
          this.labels = {
              // width
              w_min: 0,
              w_max: 0,
              w_from: 0,
              w_to: 0,
              w_single: 0,
  
              // percents
              p_min: 0,
              p_max: 0,
              p_from_fake: 0,
              p_from_left: 0,
              p_to_fake: 0,
              p_to_left: 0,
              p_single_fake: 0,
              p_single_left: 0
          };
  
  
  
          /**
           * get and validate config
           */
          var $inp = this.$cache.input,
              val = $inp.prop("value"),
              config, config_from_data, prop;
  
          // default config
          config = {
              type: "single",
  
              min: 10,
              max: 100,
              from: null,
              to: null,
              step: 1,
  
              min_interval: 0,
              max_interval: 0,
              drag_interval: false,
  
              values: [],
              p_values: [],
  
              from_fixed: false,
              from_min: null,
              from_max: null,
              from_shadow: false,
  
              to_fixed: false,
              to_min: null,
              to_max: null,
              to_shadow: false,
  
              prettify_enabled: true,
              prettify_separator: " ",
              prettify: null,
  
              force_edges: false,
  
              keyboard: true,
  
              grid: false,
              grid_margin: true,
              grid_num: 4,
              grid_snap: false,
  
              hide_min_max: false,
              hide_from_to: false,
  
              prefix: "",
              postfix: "",
              max_postfix: "",
              decorate_both: true,
              values_separator: " — ",
  
              input_values_separator: ";",
  
              disable: false,
              block: false,
  
              extra_classes: "",
  
              scope: null,
              onStart: null,
              onChange: null,
              onFinish: null,
              onUpdate: null
          };
  
  
          // check if base element is input
          if ($inp[0].nodeName !== "INPUT") {
              console && console.warn && console.warn("Base element should be <input>!", $inp[0]);
          }
  
  
          // config from data-attributes extends js config
          config_from_data = {
              type: $inp.data("type"),
  
              min: $inp.data("min"),
              max: $inp.data("max"),
              from: $inp.data("from"),
              to: $inp.data("to"),
              step: $inp.data("step"),
  
              min_interval: $inp.data("minInterval"),
              max_interval: $inp.data("maxInterval"),
              drag_interval: $inp.data("dragInterval"),
  
              values: $inp.data("values"),
  
              from_fixed: $inp.data("fromFixed"),
              from_min: $inp.data("fromMin"),
              from_max: $inp.data("fromMax"),
              from_shadow: $inp.data("fromShadow"),
  
              to_fixed: $inp.data("toFixed"),
              to_min: $inp.data("toMin"),
              to_max: $inp.data("toMax"),
              to_shadow: $inp.data("toShadow"),
  
              prettify_enabled: $inp.data("prettifyEnabled"),
              prettify_separator: $inp.data("prettifySeparator"),
  
              force_edges: $inp.data("forceEdges"),
  
              keyboard: $inp.data("keyboard"),
  
              grid: $inp.data("grid"),
              grid_margin: $inp.data("gridMargin"),
              grid_num: $inp.data("gridNum"),
              grid_snap: $inp.data("gridSnap"),
  
              hide_min_max: $inp.data("hideMinMax"),
              hide_from_to: $inp.data("hideFromTo"),
  
              prefix: $inp.data("prefix"),
              postfix: $inp.data("postfix"),
              max_postfix: $inp.data("maxPostfix"),
              decorate_both: $inp.data("decorateBoth"),
              values_separator: $inp.data("valuesSeparator"),
  
              input_values_separator: $inp.data("inputValuesSeparator"),
  
              disable: $inp.data("disable"),
              block: $inp.data("block"),
  
              extra_classes: $inp.data("extraClasses"),
          };
          config_from_data.values = config_from_data.values && config_from_data.values.split(",");
  
          for (prop in config_from_data) {
              if (config_from_data.hasOwnProperty(prop)) {
                  if (config_from_data[prop] === undefined || config_from_data[prop] === "") {
                      delete config_from_data[prop];
                  }
              }
          }
  
  
          // input value extends default config
          if (val !== undefined && val !== "") {
              val = val.split(config_from_data.input_values_separator || options.input_values_separator || ";");
  
              if (val[0] && val[0] == +val[0]) {
                  val[0] = +val[0];
              }
              if (val[1] && val[1] == +val[1]) {
                  val[1] = +val[1];
              }
  
              if (options && options.values && options.values.length) {
                  config.from = val[0] && options.values.indexOf(val[0]);
                  config.to = val[1] && options.values.indexOf(val[1]);
              } else {
                  config.from = val[0] && +val[0];
                  config.to = val[1] && +val[1];
              }
          }
  
  
  
          // js config extends default config
          $.extend(config, options);
  
  
          // data config extends config
          $.extend(config, config_from_data);
          this.options = config;
  
  
  
          // validate config, to be sure that all data types are correct
          this.update_check = {};
          this.validate();
  
  
  
          // default result object, returned to callbacks
          this.result = {
              input: this.$cache.input,
              slider: null,
  
              min: this.options.min,
              max: this.options.max,
  
              from: this.options.from,
              from_percent: 0,
              from_value: null,
  
              to: this.options.to,
              to_percent: 0,
              to_value: null
          };
  
  
  
          this.init();
      };
  
      IonRangeSlider.prototype = {
  
          /**
           * Starts or updates the plugin instance
           *
           * @param [is_update] {boolean}
           */
          init: function (is_update) {
              this.no_diapason = false;
              this.coords.p_step = this.convertToPercent(this.options.step, true);
  
              this.target = "base";
  
              this.toggleInput();
              this.append();
              this.setMinMax();
  
              if (is_update) {
                  this.force_redraw = true;
                  this.calc(true);
  
                  // callbacks called
                  this.callOnUpdate();
              } else {
                  this.force_redraw = true;
                  this.calc(true);
  
                  // callbacks called
                  this.callOnStart();
              }
  
              this.updateScene();
          },
  
          /**
           * Appends slider template to a DOM
           */
          append: function () {
              var container_html = '<span class="irs js-irs-' + this.plugin_count + ' ' + this.options.extra_classes + '"></span>';
              this.$cache.input.before(container_html);
              this.$cache.input.prop("readonly", true);
              this.$cache.cont = this.$cache.input.prev();
              this.result.slider = this.$cache.cont;
  
              this.$cache.cont.html(base_html);
              this.$cache.rs = this.$cache.cont.find(".irs");
              this.$cache.min = this.$cache.cont.find(".irs-min");
              this.$cache.max = this.$cache.cont.find(".irs-max");
              this.$cache.from = this.$cache.cont.find(".irs-from");
              this.$cache.to = this.$cache.cont.find(".irs-to");
              this.$cache.single = this.$cache.cont.find(".irs-single");
              this.$cache.bar = this.$cache.cont.find(".irs-bar");
              this.$cache.line = this.$cache.cont.find(".irs-line");
              this.$cache.grid = this.$cache.cont.find(".irs-grid");
  
              if (this.options.type === "single") {
                  this.$cache.cont.append(single_html);
                  this.$cache.edge = this.$cache.cont.find(".irs-bar-edge");
                  this.$cache.s_single = this.$cache.cont.find(".single");
                  this.$cache.from[0].style.visibility = "hidden";
                  this.$cache.to[0].style.visibility = "hidden";
                  this.$cache.shad_single = this.$cache.cont.find(".shadow-single");
              } else {
                  this.$cache.cont.append(double_html);
                  this.$cache.s_from = this.$cache.cont.find(".from");
                  this.$cache.s_to = this.$cache.cont.find(".to");
                  this.$cache.shad_from = this.$cache.cont.find(".shadow-from");
                  this.$cache.shad_to = this.$cache.cont.find(".shadow-to");
  
                  this.setTopHandler();
              }
  
              if (this.options.hide_from_to) {
                  this.$cache.from[0].style.display = "none";
                  this.$cache.to[0].style.display = "none";
                  this.$cache.single[0].style.display = "none";
              }
  
              this.appendGrid();
  
              if (this.options.disable) {
                  this.appendDisableMask();
                  this.$cache.input[0].disabled = true;
              } else {
                  this.$cache.input[0].disabled = false;
                  this.removeDisableMask();
                  this.bindEvents();
              }
  
              // block only if not disabled
              if (!this.options.disable) {
                  if (this.options.block) {
                      this.appendDisableMask();
                  } else {
                      this.removeDisableMask();
                  }
              }
  
              if (this.options.drag_interval) {
                  this.$cache.bar[0].style.cursor = "ew-resize";
              }
          },
  
          /**
           * Determine which handler has a priority
           * works only for double slider type
           */
          setTopHandler: function () {
              var min = this.options.min,
                  max = this.options.max,
                  from = this.options.from,
                  to = this.options.to;
  
              if (from > min && to === max) {
                  this.$cache.s_from.addClass("type_last");
              } else if (to < max) {
                  this.$cache.s_to.addClass("type_last");
              }
          },
  
          /**
           * Determine which handles was clicked last
           * and which handler should have hover effect
           *
           * @param target {String}
           */
          changeLevel: function (target) {
              switch (target) {
                  case "single":
                      this.coords.p_gap = this.toFixed(this.coords.p_pointer - this.coords.p_single_fake);
                      this.$cache.s_single.addClass("state_hover");
                      break;
                  case "from":
                      this.coords.p_gap = this.toFixed(this.coords.p_pointer - this.coords.p_from_fake);
                      this.$cache.s_from.addClass("state_hover");
                      this.$cache.s_from.addClass("type_last");
                      this.$cache.s_to.removeClass("type_last");
                      break;
                  case "to":
                      this.coords.p_gap = this.toFixed(this.coords.p_pointer - this.coords.p_to_fake);
                      this.$cache.s_to.addClass("state_hover");
                      this.$cache.s_to.addClass("type_last");
                      this.$cache.s_from.removeClass("type_last");
                      break;
                  case "both":
                      this.coords.p_gap_left = this.toFixed(this.coords.p_pointer - this.coords.p_from_fake);
                      this.coords.p_gap_right = this.toFixed(this.coords.p_to_fake - this.coords.p_pointer);
                      this.$cache.s_to.removeClass("type_last");
                      this.$cache.s_from.removeClass("type_last");
                      break;
              }
          },
  
          /**
           * Then slider is disabled
           * appends extra layer with opacity
           */
          appendDisableMask: function () {
              this.$cache.cont.append(disable_html);
              this.$cache.cont.addClass("irs-disabled");
          },
  
          /**
           * Then slider is not disabled
           * remove disable mask
           */
          removeDisableMask: function () {
              this.$cache.cont.remove(".irs-disable-mask");
              this.$cache.cont.removeClass("irs-disabled");
          },
  
          /**
           * Remove slider instance
           * and unbind all events
           */
          remove: function () {
              this.$cache.cont.remove();
              this.$cache.cont = null;
  
              this.$cache.line.off("keydown.irs_" + this.plugin_count);
  
              this.$cache.body.off("touchmove.irs_" + this.plugin_count);
              this.$cache.body.off("mousemove.irs_" + this.plugin_count);
  
              this.$cache.win.off("touchend.irs_" + this.plugin_count);
              this.$cache.win.off("mouseup.irs_" + this.plugin_count);
  
              if (is_old_ie) {
                  this.$cache.body.off("mouseup.irs_" + this.plugin_count);
                  this.$cache.body.off("mouseleave.irs_" + this.plugin_count);
              }
  
              this.$cache.grid_labels = [];
              this.coords.big = [];
              this.coords.big_w = [];
              this.coords.big_p = [];
              this.coords.big_x = [];
  
              cancelAnimationFrame(this.raf_id);
          },
  
          /**
           * bind all slider events
           */
          bindEvents: function () {
              if (this.no_diapason) {
                  return;
              }
  
              this.$cache.body.on("touchmove.irs_" + this.plugin_count, this.pointerMove.bind(this));
              this.$cache.body.on("mousemove.irs_" + this.plugin_count, this.pointerMove.bind(this));
  
              this.$cache.win.on("touchend.irs_" + this.plugin_count, this.pointerUp.bind(this));
              this.$cache.win.on("mouseup.irs_" + this.plugin_count, this.pointerUp.bind(this));
  
              this.$cache.line.on("touchstart.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
              this.$cache.line.on("mousedown.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
  
              this.$cache.line.on("focus.irs_" + this.plugin_count, this.pointerFocus.bind(this));
  
              if (this.options.drag_interval && this.options.type === "double") {
                  this.$cache.bar.on("touchstart.irs_" + this.plugin_count, this.pointerDown.bind(this, "both"));
                  this.$cache.bar.on("mousedown.irs_" + this.plugin_count, this.pointerDown.bind(this, "both"));
              } else {
                  this.$cache.bar.on("touchstart.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
                  this.$cache.bar.on("mousedown.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
              }
  
              if (this.options.type === "single") {
                  this.$cache.single.on("touchstart.irs_" + this.plugin_count, this.pointerDown.bind(this, "single"));
                  this.$cache.s_single.on("touchstart.irs_" + this.plugin_count, this.pointerDown.bind(this, "single"));
                  this.$cache.shad_single.on("touchstart.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
  
                  this.$cache.single.on("mousedown.irs_" + this.plugin_count, this.pointerDown.bind(this, "single"));
                  this.$cache.s_single.on("mousedown.irs_" + this.plugin_count, this.pointerDown.bind(this, "single"));
                  this.$cache.edge.on("mousedown.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
                  this.$cache.shad_single.on("mousedown.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
              } else {
                  this.$cache.single.on("touchstart.irs_" + this.plugin_count, this.pointerDown.bind(this, null));
                  this.$cache.single.on("mousedown.irs_" + this.plugin_count, this.pointerDown.bind(this, null));
  
                  this.$cache.from.on("touchstart.irs_" + this.plugin_count, this.pointerDown.bind(this, "from"));
                  this.$cache.s_from.on("touchstart.irs_" + this.plugin_count, this.pointerDown.bind(this, "from"));
                  this.$cache.to.on("touchstart.irs_" + this.plugin_count, this.pointerDown.bind(this, "to"));
                  this.$cache.s_to.on("touchstart.irs_" + this.plugin_count, this.pointerDown.bind(this, "to"));
                  this.$cache.shad_from.on("touchstart.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
                  this.$cache.shad_to.on("touchstart.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
  
                  this.$cache.from.on("mousedown.irs_" + this.plugin_count, this.pointerDown.bind(this, "from"));
                  this.$cache.s_from.on("mousedown.irs_" + this.plugin_count, this.pointerDown.bind(this, "from"));
                  this.$cache.to.on("mousedown.irs_" + this.plugin_count, this.pointerDown.bind(this, "to"));
                  this.$cache.s_to.on("mousedown.irs_" + this.plugin_count, this.pointerDown.bind(this, "to"));
                  this.$cache.shad_from.on("mousedown.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
                  this.$cache.shad_to.on("mousedown.irs_" + this.plugin_count, this.pointerClick.bind(this, "click"));
              }
  
              if (this.options.keyboard) {
                  this.$cache.line.on("keydown.irs_" + this.plugin_count, this.key.bind(this, "keyboard"));
              }
  
              if (is_old_ie) {
                  this.$cache.body.on("mouseup.irs_" + this.plugin_count, this.pointerUp.bind(this));
                  this.$cache.body.on("mouseleave.irs_" + this.plugin_count, this.pointerUp.bind(this));
              }
          },
  
          /**
           * Focus with tabIndex
           *
           * @param e {Object} event object
           */
          pointerFocus: function (e) {
              if (!this.target) {
                  var x;
                  var $handle;
  
                  if (this.options.type === "single") {
                      $handle = this.$cache.single;
                  } else {
                      $handle = this.$cache.from;
                  }
  
                  x = $handle.offset().left;
                  x += ($handle.width() / 2) - 1;
  
                  this.pointerClick("single", {preventDefault: function () {}, pageX: x});
              }
          },
  
          /**
           * Mousemove or touchmove
           * only for handlers
           *
           * @param e {Object} event object
           */
          pointerMove: function (e) {
              if (!this.dragging) {
                  return;
              }
  
              var x = e.pageX || e.originalEvent.touches && e.originalEvent.touches[0].pageX;
              this.coords.x_pointer = x - this.coords.x_gap;
  
              this.calc();
          },
  
          /**
           * Mouseup or touchend
           * only for handlers
           *
           * @param e {Object} event object
           */
          pointerUp: function (e) {
              if (this.current_plugin !== this.plugin_count) {
                  return;
              }
  
              if (this.is_active) {
                  this.is_active = false;
              } else {
                  return;
              }
  
              this.$cache.cont.find(".state_hover").removeClass("state_hover");
  
              this.force_redraw = true;
  
              if (is_old_ie) {
                  $("*").prop("unselectable", false);
              }
  
              this.updateScene();
              this.restoreOriginalMinInterval();
  
              // callbacks call
              if ($.contains(this.$cache.cont[0], e.target) || this.dragging) {
                  this.callOnFinish();
              }
              
              this.dragging = false;
          },
  
          /**
           * Mousedown or touchstart
           * only for handlers
           *
           * @param target {String|null}
           * @param e {Object} event object
           */
          pointerDown: function (target, e) {
              e.preventDefault();
              var x = e.pageX || e.originalEvent.touches && e.originalEvent.touches[0].pageX;
              if (e.button === 2) {
                  return;
              }
  
              if (target === "both") {
                  this.setTempMinInterval();
              }
  
              if (!target) {
                  target = this.target || "from";
              }
  
              this.current_plugin = this.plugin_count;
              this.target = target;
  
              this.is_active = true;
              this.dragging = true;
  
              this.coords.x_gap = this.$cache.rs.offset().left;
              this.coords.x_pointer = x - this.coords.x_gap;
  
              this.calcPointerPercent();
              this.changeLevel(target);
  
              if (is_old_ie) {
                  $("*").prop("unselectable", true);
              }
  
              this.$cache.line.trigger("focus");
  
              this.updateScene();
          },
  
          /**
           * Mousedown or touchstart
           * for other slider elements, like diapason line
           *
           * @param target {String}
           * @param e {Object} event object
           */
          pointerClick: function (target, e) {
              e.preventDefault();
              var x = e.pageX || e.originalEvent.touches && e.originalEvent.touches[0].pageX;
              if (e.button === 2) {
                  return;
              }
  
              this.current_plugin = this.plugin_count;
              this.target = target;
  
              this.is_click = true;
              this.coords.x_gap = this.$cache.rs.offset().left;
              this.coords.x_pointer = +(x - this.coords.x_gap).toFixed();
  
              this.force_redraw = true;
              this.calc();
  
              this.$cache.line.trigger("focus");
          },
  
          /**
           * Keyborard controls for focused slider
           *
           * @param target {String}
           * @param e {Object} event object
           * @returns {boolean|undefined}
           */
          key: function (target, e) {
              if (this.current_plugin !== this.plugin_count || e.altKey || e.ctrlKey || e.shiftKey || e.metaKey) {
                  return;
              }
  
              switch (e.which) {
                  case 83: // W
                  case 65: // A
                  case 40: // DOWN
                  case 37: // LEFT
                      e.preventDefault();
                      this.moveByKey(false);
                      break;
  
                  case 87: // S
                  case 68: // D
                  case 38: // UP
                  case 39: // RIGHT
                      e.preventDefault();
                      this.moveByKey(true);
                      break;
              }
  
              return true;
          },
  
          /**
           * Move by key
           *
           * @param right {boolean} direction to move
           */
          moveByKey: function (right) {
              var p = this.coords.p_pointer;
              var p_step = (this.options.max - this.options.min) / 100;
              p_step = this.options.step / p_step;
  
              if (right) {
                  p += p_step;
              } else {
                  p -= p_step;
              }
  
              this.coords.x_pointer = this.toFixed(this.coords.w_rs / 100 * p);
              this.is_key = true;
              this.calc();
          },
  
          /**
           * Set visibility and content
           * of Min and Max labels
           */
          setMinMax: function () {
              if (!this.options) {
                  return;
              }
  
              if (this.options.hide_min_max) {
                  this.$cache.min[0].style.display = "none";
                  this.$cache.max[0].style.display = "none";
                  return;
              }
  
              if (this.options.values.length) {
                  this.$cache.min.html(this.decorate(this.options.p_values[this.options.min]));
                  this.$cache.max.html(this.decorate(this.options.p_values[this.options.max]));
              } else {
                  var min_pretty = this._prettify(this.options.min);
                  var max_pretty = this._prettify(this.options.max);
  
                  this.result.min_pretty = min_pretty;
                  this.result.max_pretty = max_pretty;
  
                  this.$cache.min.html(this.decorate(min_pretty, this.options.min));
                  this.$cache.max.html(this.decorate(max_pretty, this.options.max));
              }
  
              this.labels.w_min = this.$cache.min.outerWidth(false);
              this.labels.w_max = this.$cache.max.outerWidth(false);
          },
  
          /**
           * Then dragging interval, prevent interval collapsing
           * using min_interval option
           */
          setTempMinInterval: function () {
              var interval = this.result.to - this.result.from;
  
              if (this.old_min_interval === null) {
                  this.old_min_interval = this.options.min_interval;
              }
  
              this.options.min_interval = interval;
          },
  
          /**
           * Restore min_interval option to original
           */
          restoreOriginalMinInterval: function () {
              if (this.old_min_interval !== null) {
                  this.options.min_interval = this.old_min_interval;
                  this.old_min_interval = null;
              }
          },
  
  
  
          // =============================================================================================================
          // Calculations
  
          /**
           * All calculations and measures start here
           *
           * @param update {boolean=}
           */
          calc: function (update) {
              if (!this.options) {
                  return;
              }
  
              this.calc_count++;
  
              if (this.calc_count === 10 || update) {
                  this.calc_count = 0;
                  this.coords.w_rs = this.$cache.rs.outerWidth(false);
  
                  this.calcHandlePercent();
              }
  
              if (!this.coords.w_rs) {
                  return;
              }
  
              this.calcPointerPercent();
              var handle_x = this.getHandleX();
  
  
              if (this.target === "both") {
                  this.coords.p_gap = 0;
                  handle_x = this.getHandleX();
              }
  
              if (this.target === "click") {
                  this.coords.p_gap = this.coords.p_handle / 2;
                  handle_x = this.getHandleX();
  
                  if (this.options.drag_interval) {
                      this.target = "both_one";
                  } else {
                      this.target = this.chooseHandle(handle_x);
                  }
              }
  
              switch (this.target) {
                  case "base":
                      var w = (this.options.max - this.options.min) / 100,
                          f = (this.result.from - this.options.min) / w,
                          t = (this.result.to - this.options.min) / w;
  
                      this.coords.p_single_real = this.toFixed(f);
                      this.coords.p_from_real = this.toFixed(f);
                      this.coords.p_to_real = this.toFixed(t);
  
                      this.coords.p_single_real = this.checkDiapason(this.coords.p_single_real, this.options.from_min, this.options.from_max);
                      this.coords.p_from_real = this.checkDiapason(this.coords.p_from_real, this.options.from_min, this.options.from_max);
                      this.coords.p_to_real = this.checkDiapason(this.coords.p_to_real, this.options.to_min, this.options.to_max);
  
                      this.coords.p_single_fake = this.convertToFakePercent(this.coords.p_single_real);
                      this.coords.p_from_fake = this.convertToFakePercent(this.coords.p_from_real);
                      this.coords.p_to_fake = this.convertToFakePercent(this.coords.p_to_real);
  
                      this.target = null;
  
                      break;
  
                  case "single":
                      if (this.options.from_fixed) {
                          break;
                      }
  
                      this.coords.p_single_real = this.convertToRealPercent(handle_x);
                      this.coords.p_single_real = this.calcWithStep(this.coords.p_single_real);
                      this.coords.p_single_real = this.checkDiapason(this.coords.p_single_real, this.options.from_min, this.options.from_max);
  
                      this.coords.p_single_fake = this.convertToFakePercent(this.coords.p_single_real);
  
                      break;
  
                  case "from":
                      if (this.options.from_fixed) {
                          break;
                      }
  
                      this.coords.p_from_real = this.convertToRealPercent(handle_x);
                      this.coords.p_from_real = this.calcWithStep(this.coords.p_from_real);
                      if (this.coords.p_from_real > this.coords.p_to_real) {
                          this.coords.p_from_real = this.coords.p_to_real;
                      }
                      this.coords.p_from_real = this.checkDiapason(this.coords.p_from_real, this.options.from_min, this.options.from_max);
                      this.coords.p_from_real = this.checkMinInterval(this.coords.p_from_real, this.coords.p_to_real, "from");
                      this.coords.p_from_real = this.checkMaxInterval(this.coords.p_from_real, this.coords.p_to_real, "from");
  
                      this.coords.p_from_fake = this.convertToFakePercent(this.coords.p_from_real);
  
                      break;
  
                  case "to":
                      if (this.options.to_fixed) {
                          break;
                      }
  
                      this.coords.p_to_real = this.convertToRealPercent(handle_x);
                      this.coords.p_to_real = this.calcWithStep(this.coords.p_to_real);
                      if (this.coords.p_to_real < this.coords.p_from_real) {
                          this.coords.p_to_real = this.coords.p_from_real;
                      }
                      this.coords.p_to_real = this.checkDiapason(this.coords.p_to_real, this.options.to_min, this.options.to_max);
                      this.coords.p_to_real = this.checkMinInterval(this.coords.p_to_real, this.coords.p_from_real, "to");
                      this.coords.p_to_real = this.checkMaxInterval(this.coords.p_to_real, this.coords.p_from_real, "to");
  
                      this.coords.p_to_fake = this.convertToFakePercent(this.coords.p_to_real);
  
                      break;
  
                  case "both":
                      if (this.options.from_fixed || this.options.to_fixed) {
                          break;
                      }
  
                      handle_x = this.toFixed(handle_x + (this.coords.p_handle * 0.001));
  
                      this.coords.p_from_real = this.convertToRealPercent(handle_x) - this.coords.p_gap_left;
                      this.coords.p_from_real = this.calcWithStep(this.coords.p_from_real);
                      this.coords.p_from_real = this.checkDiapason(this.coords.p_from_real, this.options.from_min, this.options.from_max);
                      this.coords.p_from_real = this.checkMinInterval(this.coords.p_from_real, this.coords.p_to_real, "from");
                      this.coords.p_from_fake = this.convertToFakePercent(this.coords.p_from_real);
  
                      this.coords.p_to_real = this.convertToRealPercent(handle_x) + this.coords.p_gap_right;
                      this.coords.p_to_real = this.calcWithStep(this.coords.p_to_real);
                      this.coords.p_to_real = this.checkDiapason(this.coords.p_to_real, this.options.to_min, this.options.to_max);
                      this.coords.p_to_real = this.checkMinInterval(this.coords.p_to_real, this.coords.p_from_real, "to");
                      this.coords.p_to_fake = this.convertToFakePercent(this.coords.p_to_real);
  
                      break;
  
                  case "both_one":
                      if (this.options.from_fixed || this.options.to_fixed) {
                          break;
                      }
  
                      var real_x = this.convertToRealPercent(handle_x),
                          from = this.result.from_percent,
                          to = this.result.to_percent,
                          full = to - from,
                          half = full / 2,
                          new_from = real_x - half,
                          new_to = real_x + half;
  
                      if (new_from < 0) {
                          new_from = 0;
                          new_to = new_from + full;
                      }
  
                      if (new_to > 100) {
                          new_to = 100;
                          new_from = new_to - full;
                      }
  
                      this.coords.p_from_real = this.calcWithStep(new_from);
                      this.coords.p_from_real = this.checkDiapason(this.coords.p_from_real, this.options.from_min, this.options.from_max);
                      this.coords.p_from_fake = this.convertToFakePercent(this.coords.p_from_real);
  
                      this.coords.p_to_real = this.calcWithStep(new_to);
                      this.coords.p_to_real = this.checkDiapason(this.coords.p_to_real, this.options.to_min, this.options.to_max);
                      this.coords.p_to_fake = this.convertToFakePercent(this.coords.p_to_real);
  
                      break;
              }
  
              if (this.options.type === "single") {
                  this.coords.p_bar_x = (this.coords.p_handle / 2);
                  this.coords.p_bar_w = this.coords.p_single_fake;
  
                  this.result.from_percent = this.coords.p_single_real;
                  this.result.from = this.convertToValue(this.coords.p_single_real);
                  this.result.from_pretty = this._prettify(this.result.from);
  
                  if (this.options.values.length) {
                      this.result.from_value = this.options.values[this.result.from];
                  }
              } else {
                  this.coords.p_bar_x = this.toFixed(this.coords.p_from_fake + (this.coords.p_handle / 2));
                  this.coords.p_bar_w = this.toFixed(this.coords.p_to_fake - this.coords.p_from_fake);
  
                  this.result.from_percent = this.coords.p_from_real;
                  this.result.from = this.convertToValue(this.coords.p_from_real);
                  this.result.from_pretty = this._prettify(this.result.from);
                  this.result.to_percent = this.coords.p_to_real;
                  this.result.to = this.convertToValue(this.coords.p_to_real);
                  this.result.to_pretty = this._prettify(this.result.to);
  
                  if (this.options.values.length) {
                      this.result.from_value = this.options.values[this.result.from];
                      this.result.to_value = this.options.values[this.result.to];
                  }
              }
  
              this.calcMinMax();
              this.calcLabels();
          },
  
  
          /**
           * calculates pointer X in percent
           */
          calcPointerPercent: function () {
              if (!this.coords.w_rs) {
                  this.coords.p_pointer = 0;
                  return;
              }
  
              if (this.coords.x_pointer < 0 || isNaN(this.coords.x_pointer)  ) {
                  this.coords.x_pointer = 0;
              } else if (this.coords.x_pointer > this.coords.w_rs) {
                  this.coords.x_pointer = this.coords.w_rs;
              }
  
              this.coords.p_pointer = this.toFixed(this.coords.x_pointer / this.coords.w_rs * 100);
          },
  
          convertToRealPercent: function (fake) {
              var full = 100 - this.coords.p_handle;
              return fake / full * 100;
          },
  
          convertToFakePercent: function (real) {
              var full = 100 - this.coords.p_handle;
              return real / 100 * full;
          },
  
          getHandleX: function () {
              var max = 100 - this.coords.p_handle,
                  x = this.toFixed(this.coords.p_pointer - this.coords.p_gap);
  
              if (x < 0) {
                  x = 0;
              } else if (x > max) {
                  x = max;
              }
  
              return x;
          },
  
          calcHandlePercent: function () {
              if (this.options.type === "single") {
                  this.coords.w_handle = this.$cache.s_single.outerWidth(false);
              } else {
                  this.coords.w_handle = this.$cache.s_from.outerWidth(false);
              }
  
              this.coords.p_handle = this.toFixed(this.coords.w_handle / this.coords.w_rs * 100);
          },
  
          /**
           * Find closest handle to pointer click
           *
           * @param real_x {Number}
           * @returns {String}
           */
          chooseHandle: function (real_x) {
              if (this.options.type === "single") {
                  return "single";
              } else {
                  var m_point = this.coords.p_from_real + ((this.coords.p_to_real - this.coords.p_from_real) / 2);
                  if (real_x >= m_point) {
                      return this.options.to_fixed ? "from" : "to";
                  } else {
                      return this.options.from_fixed ? "to" : "from";
                  }
              }
          },
  
          /**
           * Measure Min and Max labels width in percent
           */
          calcMinMax: function () {
              if (!this.coords.w_rs) {
                  return;
              }
  
              this.labels.p_min = this.labels.w_min / this.coords.w_rs * 100;
              this.labels.p_max = this.labels.w_max / this.coords.w_rs * 100;
          },
  
          /**
           * Measure labels width and X in percent
           */
          calcLabels: function () {
              if (!this.coords.w_rs || this.options.hide_from_to) {
                  return;
              }
  
              if (this.options.type === "single") {
  
                  this.labels.w_single = this.$cache.single.outerWidth(false);
                  this.labels.p_single_fake = this.labels.w_single / this.coords.w_rs * 100;
                  this.labels.p_single_left = this.coords.p_single_fake + (this.coords.p_handle / 2) - (this.labels.p_single_fake / 2);
                  this.labels.p_single_left = this.checkEdges(this.labels.p_single_left, this.labels.p_single_fake);
  
              } else {
  
                  this.labels.w_from = this.$cache.from.outerWidth(false);
                  this.labels.p_from_fake = this.labels.w_from / this.coords.w_rs * 100;
                  this.labels.p_from_left = this.coords.p_from_fake + (this.coords.p_handle / 2) - (this.labels.p_from_fake / 2);
                  this.labels.p_from_left = this.toFixed(this.labels.p_from_left);
                  this.labels.p_from_left = this.checkEdges(this.labels.p_from_left, this.labels.p_from_fake);
  
                  this.labels.w_to = this.$cache.to.outerWidth(false);
                  this.labels.p_to_fake = this.labels.w_to / this.coords.w_rs * 100;
                  this.labels.p_to_left = this.coords.p_to_fake + (this.coords.p_handle / 2) - (this.labels.p_to_fake / 2);
                  this.labels.p_to_left = this.toFixed(this.labels.p_to_left);
                  this.labels.p_to_left = this.checkEdges(this.labels.p_to_left, this.labels.p_to_fake);
  
                  this.labels.w_single = this.$cache.single.outerWidth(false);
                  this.labels.p_single_fake = this.labels.w_single / this.coords.w_rs * 100;
                  this.labels.p_single_left = ((this.labels.p_from_left + this.labels.p_to_left + this.labels.p_to_fake) / 2) - (this.labels.p_single_fake / 2);
                  this.labels.p_single_left = this.toFixed(this.labels.p_single_left);
                  this.labels.p_single_left = this.checkEdges(this.labels.p_single_left, this.labels.p_single_fake);
  
              }
          },
  
  
  
          // =============================================================================================================
          // Drawings
  
          /**
           * Main function called in request animation frame
           * to update everything
           */
          updateScene: function () {
              if (this.raf_id) {
                  cancelAnimationFrame(this.raf_id);
                  this.raf_id = null;
              }
  
              clearTimeout(this.update_tm);
              this.update_tm = null;
  
              if (!this.options) {
                  return;
              }
  
              this.drawHandles();
  
              if (this.is_active) {
                  this.raf_id = requestAnimationFrame(this.updateScene.bind(this));
              } else {
                  this.update_tm = setTimeout(this.updateScene.bind(this), 300);
              }
          },
  
          /**
           * Draw handles
           */
          drawHandles: function () {
              this.coords.w_rs = this.$cache.rs.outerWidth(false);
  
              if (!this.coords.w_rs) {
                  return;
              }
  
              if (this.coords.w_rs !== this.coords.w_rs_old) {
                  this.target = "base";
                  this.is_resize = true;
              }
  
              if (this.coords.w_rs !== this.coords.w_rs_old || this.force_redraw) {
                  this.setMinMax();
                  this.calc(true);
                  this.drawLabels();
                  if (this.options.grid) {
                      this.calcGridMargin();
                      this.calcGridLabels();
                  }
                  this.force_redraw = true;
                  this.coords.w_rs_old = this.coords.w_rs;
                  this.drawShadow();
              }
  
              if (!this.coords.w_rs) {
                  return;
              }
  
              if (!this.dragging && !this.force_redraw && !this.is_key) {
                  return;
              }
  
              if (this.old_from !== this.result.from || this.old_to !== this.result.to || this.force_redraw || this.is_key) {
  
                  this.drawLabels();
  
                  this.$cache.bar[0].style.left = this.coords.p_bar_x + "%";
                  this.$cache.bar[0].style.width = this.coords.p_bar_w + "%";
  
                  if (this.options.type === "single") {
                      this.$cache.s_single[0].style.left = this.coords.p_single_fake + "%";
  
                      this.$cache.single[0].style.left = this.labels.p_single_left + "%";
                  } else {
                      this.$cache.s_from[0].style.left = this.coords.p_from_fake + "%";
                      this.$cache.s_to[0].style.left = this.coords.p_to_fake + "%";
  
                      if (this.old_from !== this.result.from || this.force_redraw) {
                          this.$cache.from[0].style.left = this.labels.p_from_left + "%";
                      }
                      if (this.old_to !== this.result.to || this.force_redraw) {
                          this.$cache.to[0].style.left = this.labels.p_to_left + "%";
                      }
  
                      this.$cache.single[0].style.left = this.labels.p_single_left + "%";
                  }
  
                  this.writeToInput();
  
                  if ((this.old_from !== this.result.from || this.old_to !== this.result.to) && !this.is_start) {
                      this.$cache.input.trigger("change");
                      this.$cache.input.trigger("input");
                  }
  
                  this.old_from = this.result.from;
                  this.old_to = this.result.to;
  
                  // callbacks call
                  if (!this.is_resize && !this.is_update && !this.is_start && !this.is_finish) {
                      this.callOnChange();
                  }
                  if (this.is_key || this.is_click) {
                      this.is_key = false;
                      this.is_click = false;
                      this.callOnFinish();
                  }
  
                  this.is_update = false;
                  this.is_resize = false;
                  this.is_finish = false;
              }
  
              this.is_start = false;
              this.is_key = false;
              this.is_click = false;
              this.force_redraw = false;
          },
  
          /**
           * Draw labels
           * measure labels collisions
           * collapse close labels
           */
          drawLabels: function () {
              if (!this.options) {
                  return;
              }
  
              var values_num = this.options.values.length;
              var p_values = this.options.p_values;
              var text_single;
              var text_from;
              var text_to;
              var from_pretty;
              var to_pretty;
  
              if (this.options.hide_from_to) {
                  return;
              }
  
              if (this.options.type === "single") {
  
                  if (values_num) {
                      text_single = this.decorate(p_values[this.result.from]);
                      this.$cache.single.html(text_single);
                  } else {
                      from_pretty = this._prettify(this.result.from);
  
                      text_single = this.decorate(from_pretty, this.result.from);
                      this.$cache.single.html(text_single);
                  }
  
                  this.calcLabels();
  
                  if (this.labels.p_single_left < this.labels.p_min + 1) {
                      this.$cache.min[0].style.visibility = "hidden";
                  } else {
                      this.$cache.min[0].style.visibility = "visible";
                  }
  
                  if (this.labels.p_single_left + this.labels.p_single_fake > 100 - this.labels.p_max - 1) {
                      this.$cache.max[0].style.visibility = "hidden";
                  } else {
                      this.$cache.max[0].style.visibility = "visible";
                  }
  
              } else {
  
                  if (values_num) {
  
                      if (this.options.decorate_both) {
                          text_single = this.decorate(p_values[this.result.from]);
                          text_single += this.options.values_separator;
                          text_single += this.decorate(p_values[this.result.to]);
                      } else {
                          text_single = this.decorate(p_values[this.result.from] + this.options.values_separator + p_values[this.result.to]);
                      }
                      text_from = this.decorate(p_values[this.result.from]);
                      text_to = this.decorate(p_values[this.result.to]);
  
                      this.$cache.single.html(text_single);
                      this.$cache.from.html(text_from);
                      this.$cache.to.html(text_to);
  
                  } else {
                      from_pretty = this._prettify(this.result.from);
                      to_pretty = this._prettify(this.result.to);
  
                      if (this.options.decorate_both) {
                          text_single = this.decorate(from_pretty, this.result.from);
                          text_single += this.options.values_separator;
                          text_single += this.decorate(to_pretty, this.result.to);
                      } else {
                          text_single = this.decorate(from_pretty + this.options.values_separator + to_pretty, this.result.to);
                      }
                      text_from = this.decorate(from_pretty, this.result.from);
                      text_to = this.decorate(to_pretty, this.result.to);
  
                      this.$cache.single.html(text_single);
                      this.$cache.from.html(text_from);
                      this.$cache.to.html(text_to);
  
                  }
  
                  this.calcLabels();
  
                  var min = Math.min(this.labels.p_single_left, this.labels.p_from_left),
                      single_left = this.labels.p_single_left + this.labels.p_single_fake,
                      to_left = this.labels.p_to_left + this.labels.p_to_fake,
                      max = Math.max(single_left, to_left);
  
                  if (this.labels.p_from_left + this.labels.p_from_fake >= this.labels.p_to_left) {
                      this.$cache.from[0].style.visibility = "hidden";
                      this.$cache.to[0].style.visibility = "hidden";
                      this.$cache.single[0].style.visibility = "visible";
  
                      if (this.result.from === this.result.to) {
                          if (this.target === "from") {
                              this.$cache.from[0].style.visibility = "visible";
                          } else if (this.target === "to") {
                              this.$cache.to[0].style.visibility = "visible";
                          } else if (!this.target) {
                              this.$cache.from[0].style.visibility = "visible";
                          }
                          this.$cache.single[0].style.visibility = "hidden";
                          max = to_left;
                      } else {
                          this.$cache.from[0].style.visibility = "hidden";
                          this.$cache.to[0].style.visibility = "hidden";
                          this.$cache.single[0].style.visibility = "visible";
                          max = Math.max(single_left, to_left);
                      }
                  } else {
                      this.$cache.from[0].style.visibility = "visible";
                      this.$cache.to[0].style.visibility = "visible";
                      this.$cache.single[0].style.visibility = "hidden";
                  }
  
                  if (min < this.labels.p_min + 1) {
                      this.$cache.min[0].style.visibility = "hidden";
                  } else {
                      this.$cache.min[0].style.visibility = "visible";
                  }
  
                  if (max > 100 - this.labels.p_max - 1) {
                      this.$cache.max[0].style.visibility = "hidden";
                  } else {
                      this.$cache.max[0].style.visibility = "visible";
                  }
  
              }
          },
  
          /**
           * Draw shadow intervals
           */
          drawShadow: function () {
              var o = this.options,
                  c = this.$cache,
  
                  is_from_min = typeof o.from_min === "number" && !isNaN(o.from_min),
                  is_from_max = typeof o.from_max === "number" && !isNaN(o.from_max),
                  is_to_min = typeof o.to_min === "number" && !isNaN(o.to_min),
                  is_to_max = typeof o.to_max === "number" && !isNaN(o.to_max),
  
                  from_min,
                  from_max,
                  to_min,
                  to_max;
  
              if (o.type === "single") {
                  if (o.from_shadow && (is_from_min || is_from_max)) {
                      from_min = this.convertToPercent(is_from_min ? o.from_min : o.min);
                      from_max = this.convertToPercent(is_from_max ? o.from_max : o.max) - from_min;
                      from_min = this.toFixed(from_min - (this.coords.p_handle / 100 * from_min));
                      from_max = this.toFixed(from_max - (this.coords.p_handle / 100 * from_max));
                      from_min = from_min + (this.coords.p_handle / 2);
  
                      c.shad_single[0].style.display = "block";
                      c.shad_single[0].style.left = from_min + "%";
                      c.shad_single[0].style.width = from_max + "%";
                  } else {
                      c.shad_single[0].style.display = "none";
                  }
              } else {
                  if (o.from_shadow && (is_from_min || is_from_max)) {
                      from_min = this.convertToPercent(is_from_min ? o.from_min : o.min);
                      from_max = this.convertToPercent(is_from_max ? o.from_max : o.max) - from_min;
                      from_min = this.toFixed(from_min - (this.coords.p_handle / 100 * from_min));
                      from_max = this.toFixed(from_max - (this.coords.p_handle / 100 * from_max));
                      from_min = from_min + (this.coords.p_handle / 2);
  
                      c.shad_from[0].style.display = "block";
                      c.shad_from[0].style.left = from_min + "%";
                      c.shad_from[0].style.width = from_max + "%";
                  } else {
                      c.shad_from[0].style.display = "none";
                  }
  
                  if (o.to_shadow && (is_to_min || is_to_max)) {
                      to_min = this.convertToPercent(is_to_min ? o.to_min : o.min);
                      to_max = this.convertToPercent(is_to_max ? o.to_max : o.max) - to_min;
                      to_min = this.toFixed(to_min - (this.coords.p_handle / 100 * to_min));
                      to_max = this.toFixed(to_max - (this.coords.p_handle / 100 * to_max));
                      to_min = to_min + (this.coords.p_handle / 2);
  
                      c.shad_to[0].style.display = "block";
                      c.shad_to[0].style.left = to_min + "%";
                      c.shad_to[0].style.width = to_max + "%";
                  } else {
                      c.shad_to[0].style.display = "none";
                  }
              }
          },
  
  
  
          /**
           * Write values to input element
           */
          writeToInput: function () {
              if (this.options.type === "single") {
                  if (this.options.values.length) {
                      this.$cache.input.prop("value", this.result.from_value);
                  } else {
                      this.$cache.input.prop("value", this.result.from);
                  }
                  this.$cache.input.data("from", this.result.from);
              } else {
                  if (this.options.values.length) {
                      this.$cache.input.prop("value", this.result.from_value + this.options.input_values_separator + this.result.to_value);
                  } else {
                      this.$cache.input.prop("value", this.result.from + this.options.input_values_separator + this.result.to);
                  }
                  this.$cache.input.data("from", this.result.from);
                  this.$cache.input.data("to", this.result.to);
              }
          },
  
  
  
          // =============================================================================================================
          // Callbacks
  
          callOnStart: function () {
              this.writeToInput();
  
              if (this.options.onStart && typeof this.options.onStart === "function") {
                  if (this.options.scope) {
                      this.options.onStart.call(this.options.scope, this.result);
                  } else {
                      this.options.onStart(this.result);
                  }
              }
          },
          callOnChange: function () {
              this.writeToInput();
  
              if (this.options.onChange && typeof this.options.onChange === "function") {
                  if (this.options.scope) {
                      this.options.onChange.call(this.options.scope, this.result);
                  } else {
                      this.options.onChange(this.result);
                  }
              }
          },
          callOnFinish: function () {
              this.writeToInput();
  
              if (this.options.onFinish && typeof this.options.onFinish === "function") {
                  if (this.options.scope) {
                      this.options.onFinish.call(this.options.scope, this.result);
                  } else {
                      this.options.onFinish(this.result);
                  }
              }
          },
          callOnUpdate: function () {
              this.writeToInput();
  
              if (this.options.onUpdate && typeof this.options.onUpdate === "function") {
                  if (this.options.scope) {
                      this.options.onUpdate.call(this.options.scope, this.result);
                  } else {
                      this.options.onUpdate(this.result);
                  }
              }
          },
  
  
  
  
          // =============================================================================================================
          // Service methods
  
          toggleInput: function () {
              this.$cache.input.toggleClass("irs-hidden-input");
  
              if (this.has_tab_index) {
                  this.$cache.input.prop("tabindex", -1);
              } else {
                  this.$cache.input.removeProp("tabindex");
              }
  
              this.has_tab_index = !this.has_tab_index;
          },
  
          /**
           * Convert real value to percent
           *
           * @param value {Number} X in real
           * @param no_min {boolean=} don't use min value
           * @returns {Number} X in percent
           */
          convertToPercent: function (value, no_min) {
              var diapason = this.options.max - this.options.min,
                  one_percent = diapason / 100,
                  val, percent;
  
              if (!diapason) {
                  this.no_diapason = true;
                  return 0;
              }
  
              if (no_min) {
                  val = value;
              } else {
                  val = value - this.options.min;
              }
  
              percent = val / one_percent;
  
              return this.toFixed(percent);
          },
  
          /**
           * Convert percent to real values
           *
           * @param percent {Number} X in percent
           * @returns {Number} X in real
           */
          convertToValue: function (percent) {
              var min = this.options.min,
                  max = this.options.max,
                  min_decimals = min.toString().split(".")[1],
                  max_decimals = max.toString().split(".")[1],
                  min_length, max_length,
                  avg_decimals = 0,
                  abs = 0;
  
              if (percent === 0) {
                  return this.options.min;
              }
              if (percent === 100) {
                  return this.options.max;
              }
  
  
              if (min_decimals) {
                  min_length = min_decimals.length;
                  avg_decimals = min_length;
              }
              if (max_decimals) {
                  max_length = max_decimals.length;
                  avg_decimals = max_length;
              }
              if (min_length && max_length) {
                  avg_decimals = (min_length >= max_length) ? min_length : max_length;
              }
  
              if (min < 0) {
                  abs = Math.abs(min);
                  min = +(min + abs).toFixed(avg_decimals);
                  max = +(max + abs).toFixed(avg_decimals);
              }
  
              var number = ((max - min) / 100 * percent) + min,
                  string = this.options.step.toString().split(".")[1],
                  result;
  
              if (string) {
                  number = +number.toFixed(string.length);
              } else {
                  number = number / this.options.step;
                  number = number * this.options.step;
  
                  number = +number.toFixed(0);
              }
  
              if (abs) {
                  number -= abs;
              }
  
              if (string) {
                  result = +number.toFixed(string.length);
              } else {
                  result = this.toFixed(number);
              }
  
              if (result < this.options.min) {
                  result = this.options.min;
              } else if (result > this.options.max) {
                  result = this.options.max;
              }
  
              return result;
          },
  
          /**
           * Round percent value with step
           *
           * @param percent {Number}
           * @returns percent {Number} rounded
           */
          calcWithStep: function (percent) {
              var rounded = Math.round(percent / this.coords.p_step) * this.coords.p_step;
  
              if (rounded > 100) {
                  rounded = 100;
              }
              if (percent === 100) {
                  rounded = 100;
              }
  
              return this.toFixed(rounded);
          },
  
          checkMinInterval: function (p_current, p_next, type) {
              var o = this.options,
                  current,
                  next;
  
              if (!o.min_interval) {
                  return p_current;
              }
  
              current = this.convertToValue(p_current);
              next = this.convertToValue(p_next);
  
              if (type === "from") {
  
                  if (next - current < o.min_interval) {
                      current = next - o.min_interval;
                  }
  
              } else {
  
                  if (current - next < o.min_interval) {
                      current = next + o.min_interval;
                  }
  
              }
  
              return this.convertToPercent(current);
          },
  
          checkMaxInterval: function (p_current, p_next, type) {
              var o = this.options,
                  current,
                  next;
  
              if (!o.max_interval) {
                  return p_current;
              }
  
              current = this.convertToValue(p_current);
              next = this.convertToValue(p_next);
  
              if (type === "from") {
  
                  if (next - current > o.max_interval) {
                      current = next - o.max_interval;
                  }
  
              } else {
  
                  if (current - next > o.max_interval) {
                      current = next + o.max_interval;
                  }
  
              }
  
              return this.convertToPercent(current);
          },
  
          checkDiapason: function (p_num, min, max) {
              var num = this.convertToValue(p_num),
                  o = this.options;
  
              if (typeof min !== "number") {
                  min = o.min;
              }
  
              if (typeof max !== "number") {
                  max = o.max;
              }
  
              if (num < min) {
                  num = min;
              }
  
              if (num > max) {
                  num = max;
              }
  
              return this.convertToPercent(num);
          },
  
          toFixed: function (num) {
              num = num.toFixed(20);
              return +num;
          },
  
          _prettify: function (num) {
              if (!this.options.prettify_enabled) {
                  return num;
              }
  
              if (this.options.prettify && typeof this.options.prettify === "function") {
                  return this.options.prettify(num);
              } else {
                  return this.prettify(num);
              }
          },
  
          prettify: function (num) {
              var n = num.toString();
              return n.replace(/(\d{1,3}(?=(?:\d\d\d)+(?!\d)))/g, "$1" + this.options.prettify_separator);
          },
  
          checkEdges: function (left, width) {
              if (!this.options.force_edges) {
                  return this.toFixed(left);
              }
  
              if (left < 0) {
                  left = 0;
              } else if (left > 100 - width) {
                  left = 100 - width;
              }
  
              return this.toFixed(left);
          },
  
          validate: function () {
              var o = this.options,
                  r = this.result,
                  v = o.values,
                  vl = v.length,
                  value,
                  i;
  
              if (typeof o.min === "string") o.min = +o.min;
              if (typeof o.max === "string") o.max = +o.max;
              if (typeof o.from === "string") o.from = +o.from;
              if (typeof o.to === "string") o.to = +o.to;
              if (typeof o.step === "string") o.step = +o.step;
  
              if (typeof o.from_min === "string") o.from_min = +o.from_min;
              if (typeof o.from_max === "string") o.from_max = +o.from_max;
              if (typeof o.to_min === "string") o.to_min = +o.to_min;
              if (typeof o.to_max === "string") o.to_max = +o.to_max;
  
              if (typeof o.grid_num === "string") o.grid_num = +o.grid_num;
  
              if (o.max < o.min) {
                  o.max = o.min;
              }
  
              if (vl) {
                  o.p_values = [];
                  o.min = 0;
                  o.max = vl - 1;
                  o.step = 1;
                  o.grid_num = o.max;
                  o.grid_snap = true;
  
                  for (i = 0; i < vl; i++) {
                      value = +v[i];
  
                      if (!isNaN(value)) {
                          v[i] = value;
                          value = this._prettify(value);
                      } else {
                          value = v[i];
                      }
  
                      o.p_values.push(value);
                  }
              }
  
              if (typeof o.from !== "number" || isNaN(o.from)) {
                  o.from = o.min;
              }
  
              if (typeof o.to !== "number" || isNaN(o.to)) {
                  o.to = o.max;
              }
  
              if (o.type === "single") {
  
                  if (o.from < o.min) o.from = o.min;
                  if (o.from > o.max) o.from = o.max;
  
              } else {
  
                  if (o.from < o.min) o.from = o.min;
                  if (o.from > o.max) o.from = o.max;
  
                  if (o.to < o.min) o.to = o.min;
                  if (o.to > o.max) o.to = o.max;
  
                  if (this.update_check.from) {
  
                      if (this.update_check.from !== o.from) {
                          if (o.from > o.to) o.from = o.to;
                      }
                      if (this.update_check.to !== o.to) {
                          if (o.to < o.from) o.to = o.from;
                      }
  
                  }
  
                  if (o.from > o.to) o.from = o.to;
                  if (o.to < o.from) o.to = o.from;
  
              }
  
              if (typeof o.step !== "number" || isNaN(o.step) || !o.step || o.step < 0) {
                  o.step = 1;
              }
  
              if (typeof o.from_min === "number" && o.from < o.from_min) {
                  o.from = o.from_min;
              }
  
              if (typeof o.from_max === "number" && o.from > o.from_max) {
                  o.from = o.from_max;
              }
  
              if (typeof o.to_min === "number" && o.to < o.to_min) {
                  o.to = o.to_min;
              }
  
              if (typeof o.to_max === "number" && o.from > o.to_max) {
                  o.to = o.to_max;
              }
  
              if (r) {
                  if (r.min !== o.min) {
                      r.min = o.min;
                  }
  
                  if (r.max !== o.max) {
                      r.max = o.max;
                  }
  
                  if (r.from < r.min || r.from > r.max) {
                      r.from = o.from;
                  }
  
                  if (r.to < r.min || r.to > r.max) {
                      r.to = o.to;
                  }
              }
  
              if (typeof o.min_interval !== "number" || isNaN(o.min_interval) || !o.min_interval || o.min_interval < 0) {
                  o.min_interval = 0;
              }
  
              if (typeof o.max_interval !== "number" || isNaN(o.max_interval) || !o.max_interval || o.max_interval < 0) {
                  o.max_interval = 0;
              }
  
              if (o.min_interval && o.min_interval > o.max - o.min) {
                  o.min_interval = o.max - o.min;
              }
  
              if (o.max_interval && o.max_interval > o.max - o.min) {
                  o.max_interval = o.max - o.min;
              }
          },
  
          decorate: function (num, original) {
              var decorated = "",
                  o = this.options;
  
              if (o.prefix) {
                  decorated += o.prefix;
              }
  
              decorated += num;
  
              if (o.max_postfix) {
                  if (o.values.length && num === o.p_values[o.max]) {
                      decorated += o.max_postfix;
                      if (o.postfix) {
                          decorated += " ";
                      }
                  } else if (original === o.max) {
                      decorated += o.max_postfix;
                      if (o.postfix) {
                          decorated += " ";
                      }
                  }
              }
  
              if (o.postfix) {
                  decorated += o.postfix;
              }
  
              return decorated;
          },
  
          updateFrom: function () {
              this.result.from = this.options.from;
              this.result.from_percent = this.convertToPercent(this.result.from);
              this.result.from_pretty = this._prettify(this.result.from);
              if (this.options.values) {
                  this.result.from_value = this.options.values[this.result.from];
              }
          },
  
          updateTo: function () {
              this.result.to = this.options.to;
              this.result.to_percent = this.convertToPercent(this.result.to);
              this.result.to_pretty = this._prettify(this.result.to);
              if (this.options.values) {
                  this.result.to_value = this.options.values[this.result.to];
              }
          },
  
          updateResult: function () {
              this.result.min = this.options.min;
              this.result.max = this.options.max;
              this.updateFrom();
              this.updateTo();
          },
  
  
          // =============================================================================================================
          // Grid
  
          appendGrid: function () {
              if (!this.options.grid) {
                  return;
              }
  
              var o = this.options,
                  i, z,
  
                  total = o.max - o.min,
                  big_num = o.grid_num,
                  big_p = 0,
                  big_w = 0,
  
                  small_max = 4,
                  local_small_max,
                  small_p,
                  small_w = 0,
  
                  result,
                  html = '';
  
  
  
              this.calcGridMargin();
  
              if (o.grid_snap) {
  
                  if (total > 50) {
                      big_num = 50 / o.step;
                      big_p = this.toFixed(o.step / 0.5);
                  } else {
                      big_num = total / o.step;
                      big_p = this.toFixed(o.step / (total / 100));
                  }
  
              } else {
                  big_p = this.toFixed(100 / big_num);
              }
  
              if (big_num > 4) {
                  small_max = 3;
              }
              if (big_num > 7) {
                  small_max = 2;
              }
              if (big_num > 14) {
                  small_max = 1;
              }
              if (big_num > 28) {
                  small_max = 0;
              }
  
              for (i = 0; i < big_num + 1; i++) {
                  local_small_max = small_max;
  
                  big_w = this.toFixed(big_p * i);
  
                  if (big_w > 100) {
                      big_w = 100;
                  }
                  this.coords.big[i] = big_w;
  
                  small_p = (big_w - (big_p * (i - 1))) / (local_small_max + 1);
  
                  for (z = 1; z <= local_small_max; z++) {
                      if (big_w === 0) {
                          break;
                      }
  
                      small_w = this.toFixed(big_w - (small_p * z));
  
                      html += '<span class="irs-grid-pol small" style="left: ' + small_w + '%"></span>';
                  }
  
                  html += '<span class="irs-grid-pol" style="left: ' + big_w + '%"></span>';
  
                  result = this.convertToValue(big_w);
                  if (o.values.length) {
                      result = o.p_values[result];
                  } else {
                      result = this._prettify(result);
                  }
  
                  html += '<span class="irs-grid-text js-grid-text-' + i + '" style="left: ' + big_w + '%">' + result + '</span>';
              }
              this.coords.big_num = Math.ceil(big_num + 1);
  
  
  
              this.$cache.cont.addClass("irs-with-grid");
              this.$cache.grid.html(html);
              this.cacheGridLabels();
          },
  
          cacheGridLabels: function () {
              var $label, i,
                  num = this.coords.big_num;
  
              for (i = 0; i < num; i++) {
                  $label = this.$cache.grid.find(".js-grid-text-" + i);
                  this.$cache.grid_labels.push($label);
              }
  
              this.calcGridLabels();
          },
  
          calcGridLabels: function () {
              var i, label, start = [], finish = [],
                  num = this.coords.big_num;
  
              for (i = 0; i < num; i++) {
                  this.coords.big_w[i] = this.$cache.grid_labels[i].outerWidth(false);
                  this.coords.big_p[i] = this.toFixed(this.coords.big_w[i] / this.coords.w_rs * 100);
                  this.coords.big_x[i] = this.toFixed(this.coords.big_p[i] / 2);
  
                  start[i] = this.toFixed(this.coords.big[i] - this.coords.big_x[i]);
                  finish[i] = this.toFixed(start[i] + this.coords.big_p[i]);
              }
  
              if (this.options.force_edges) {
                  if (start[0] < -this.coords.grid_gap) {
                      start[0] = -this.coords.grid_gap;
                      finish[0] = this.toFixed(start[0] + this.coords.big_p[0]);
  
                      this.coords.big_x[0] = this.coords.grid_gap;
                  }
  
                  if (finish[num - 1] > 100 + this.coords.grid_gap) {
                      finish[num - 1] = 100 + this.coords.grid_gap;
                      start[num - 1] = this.toFixed(finish[num - 1] - this.coords.big_p[num - 1]);
  
                      this.coords.big_x[num - 1] = this.toFixed(this.coords.big_p[num - 1] - this.coords.grid_gap);
                  }
              }
  
              this.calcGridCollision(2, start, finish);
              this.calcGridCollision(4, start, finish);
  
              for (i = 0; i < num; i++) {
                  label = this.$cache.grid_labels[i][0];
  
                  if (this.coords.big_x[i] !== Number.POSITIVE_INFINITY) {
                      label.style.marginLeft = -this.coords.big_x[i] + "%";
                  }
              }
          },
  
          // Collisions Calc Beta
          // TODO: Refactor then have plenty of time
          calcGridCollision: function (step, start, finish) {
              var i, next_i, label,
                  num = this.coords.big_num;
  
              for (i = 0; i < num; i += step) {
                  next_i = i + (step / 2);
                  if (next_i >= num) {
                      break;
                  }
  
                  label = this.$cache.grid_labels[next_i][0];
  
                  if (finish[i] <= start[next_i]) {
                      label.style.visibility = "visible";
                  } else {
                      label.style.visibility = "hidden";
                  }
              }
          },
  
          calcGridMargin: function () {
              if (!this.options.grid_margin) {
                  return;
              }
  
              this.coords.w_rs = this.$cache.rs.outerWidth(false);
              if (!this.coords.w_rs) {
                  return;
              }
  
              if (this.options.type === "single") {
                  this.coords.w_handle = this.$cache.s_single.outerWidth(false);
              } else {
                  this.coords.w_handle = this.$cache.s_from.outerWidth(false);
              }
              this.coords.p_handle = this.toFixed(this.coords.w_handle  / this.coords.w_rs * 100);
              this.coords.grid_gap = this.toFixed((this.coords.p_handle / 2) - 0.1);
  
              this.$cache.grid[0].style.width = this.toFixed(100 - this.coords.p_handle) + "%";
              this.$cache.grid[0].style.left = this.coords.grid_gap + "%";
          },
  
  
  
          // =============================================================================================================
          // Public methods
  
          update: function (options) {
              if (!this.input) {
                  return;
              }
  
              this.is_update = true;
  
              this.options.from = this.result.from;
              this.options.to = this.result.to;
              this.update_check.from = this.result.from;
              this.update_check.to = this.result.to;
  
              this.options = $.extend(this.options, options);
              this.validate();
              this.updateResult(options);
  
              this.toggleInput();
              this.remove();
              this.init(true);
          },
  
          reset: function () {
              if (!this.input) {
                  return;
              }
  
              this.updateResult();
              this.update();
          },
  
          destroy: function () {
              if (!this.input) {
                  return;
              }
  
              this.toggleInput();
              this.$cache.input.prop("readonly", false);
              $.data(this.input, "ionRangeSlider", null);
  
              this.remove();
              this.input = null;
              this.options = null;
          }
      };
  
      $.fn.ionRangeSlider = function (options) {
          return this.each(function() {
              if (!$.data(this, "ionRangeSlider")) {
                  $.data(this, "ionRangeSlider", new IonRangeSlider(this, options, plugin_count++));
              }
          });
      };
  
  
  
      // =================================================================================================================
      // http://paulirish.com/2011/requestanimationframe-for-smart-animating/
      // http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
  
      // requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel
  
      // MIT license
  
      (function() {
          var lastTime = 0;
          var vendors = ['ms', 'moz', 'webkit', 'o'];
          for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
              window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
              window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame']
                  || window[vendors[x]+'CancelRequestAnimationFrame'];
          }
  
          if (!window.requestAnimationFrame)
              window.requestAnimationFrame = function(callback, element) {
                  var currTime = new Date().getTime();
                  var timeToCall = Math.max(0, 16 - (currTime - lastTime));
                  var id = window.setTimeout(function() { callback(currTime + timeToCall); },
                      timeToCall);
                  lastTime = currTime + timeToCall;
                  return id;
              };
  
          if (!window.cancelAnimationFrame)
              window.cancelAnimationFrame = function(id) {
                  clearTimeout(id);
              };
      }());
  
  }));
  
  /* ====================================================================================================
    footer-reveal.js
  ==================================================================================================== */
  /**
   * footer-reveal.js
   * 
   * Licensed under the MIT license.
   * http://www.opensource.org/licenses/mit-license.php
   * 
   * Copyright 2014 Iain Andrew
   * https://github.com/IainAndrew
   */
  
  (function($) {
  
    $.fn.footerReveal = function(options) {
  
      var $this = $(this),
          $prev = $this.prev(),
          $win = $(window),
  
          defaults = $.extend ({
            shadow : true,
            shadowOpacity: 0.8,
            zIndex : -100
          }, options ),
  
          settings = $.extend(true, {}, defaults, options);
  
      if ($this.outerHeight() <= $win.outerHeight()) {
        $this.css({
          'z-index' : defaults.zIndex,
          position : 'fixed',
          bottom : 0
        });
  
        if (defaults.shadow) {
          $prev.css ({
            '-moz-box-shadow' : '0 20px 30px -20px rgba(0,0,0,' + defaults.shadowOpacity + ')',
            '-webkit-box-shadow' : '0 20px 30px -20px rgba(0,0,0,' + defaults.shadowOpacity +')',
            'box-shadow' : '0 20px 30px -20px rgba(0,0,0,' + defaults.shadowOpacity + ')'
          });
        }
  
        $win.on('load resize', function() {
          $this.css({
            'width' : $prev.outerWidth()
          });
          $prev.css({
            'margin-bottom' : $this.outerHeight()
          });
        });
      }
  
      return this;
  
    };
  
  }) (jQuery);
  
  /* ====================================================================================================
    Bootstrap Notify
  ==================================================================================================== */
  /*
  * Project: Bootstrap Notify = v3.1.5
  * Description: Turns standard Bootstrap alerts into "Growl-like" notifications.
  * Author: Mouse0270 aka Robert McIntosh
  * License: MIT License
  * Website: https://github.com/mouse0270/bootstrap-growl
  */
  
  /* global define:false, require: false, jQuery:false */
  
  (function (factory) {
  	if (typeof define === 'function' && define.amd) {
  		// AMD. Register as an anonymous module.
  		define(['jquery'], factory);
  	} else if (typeof exports === 'object') {
  		// Node/CommonJS
  		factory(require('jquery'));
  	} else {
  		// Browser globals
  		factory(jQuery);
  	}
  }(function ($) {
  	// Create the defaults once
  	var defaults = {
  		element: 'body',
  		position: null,
  		type: "info",
  		allow_dismiss: true,
  		allow_duplicates: true,
  		newest_on_top: false,
  		showProgressbar: false,
  		placement: {
  			from: "top",
  			align: "right"
  		},
  		offset: 20,
  		spacing: 10,
  		z_index: 1031,
  		delay: 5000,
  		timer: 1000,
  		url_target: '_blank',
  		mouse_over: null,
  		animate: {
  			enter: 'animated fadeInDown',
  			exit: 'animated fadeOutUp'
  		},
  		onShow: null,
  		onShown: null,
  		onClose: null,
  		onClosed: null,
          onClick: null,
  		icon_type: 'class',
  		template: '<div data-notify="container" class="customized_notify alert alert-{0}" role="alert"><button type="button" aria-hidden="true" class="close" data-notify="dismiss">&times;</button><i><span data-notify="icon"></span></i> <span data-notify="title">{1}</span> <span data-notify="message">{2}</span><div class="progress" data-notify="progressbar"><div class="progress-bar progress-bar-{0}" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%;"></div></div><a href="{3}" target="{4}" data-notify="url"></a></div>'
  	};
  
  	String.format = function () {
  		var args = arguments;
          var str = arguments[0];
          return str.replace(/(\{\{\d\}\}|\{\d\})/g, function (str) {
              if (str.substring(0, 2) === "{{") return str;
              var num = parseInt(str.match(/\d/)[0]);
              return args[num + 1];
          });
  	};
  
  	function isDuplicateNotification(notification) {
  		var isDupe = false;
  
  		$('[data-notify="container"]').each(function (i, el) {
  			var $el = $(el);
  			var title = $el.find('[data-notify="title"]').html().trim();
  			var message = $el.find('[data-notify="message"]').html().trim();
  
  			// The input string might be different than the actual parsed HTML string!
  			// (<br> vs <br /> for example)
  			// So we have to force-parse this as HTML here!
  			var isSameTitle = title === $("<div>" + notification.settings.content.title + "</div>").html().trim();
  			var isSameMsg = message === $("<div>" + notification.settings.content.message + "</div>").html().trim();
  			var isSameType = $el.hasClass('alert-' + notification.settings.type);
  
  			if (isSameTitle && isSameMsg && isSameType) {
  				//we found the dupe. Set the var and stop checking.
  				isDupe = true;
  			}
  			return !isDupe;
  		});
  
  		return isDupe;
  	}
  
  	function Notify(element, content, options) {
  		// Setup Content of Notify
  		var contentObj = {
  			content: {
  				message: typeof content === 'object' ? content.message : content,
  				title: content.title ? content.title : '',
  				icon: content.icon ? content.icon : '',
  				url: content.url ? content.url : '#',
  				target: content.target ? content.target : '-'
  			}
  		};
  
  		options = $.extend(true, {}, contentObj, options);
  		this.settings = $.extend(true, {}, defaults, options);
  		this._defaults = defaults;
  		if (this.settings.content.target === "-") {
  			this.settings.content.target = this.settings.url_target;
  		}
  		this.animations = {
  			start: 'webkitAnimationStart oanimationstart MSAnimationStart animationstart',
  			end: 'webkitAnimationEnd oanimationend MSAnimationEnd animationend'
  		};
  
  		if (typeof this.settings.offset === 'number') {
  			this.settings.offset = {
  				x: this.settings.offset,
  				y: this.settings.offset
  			};
  		}
  
  		//if duplicate messages are not allowed, then only continue if this new message is not a duplicate of one that it already showing
  		if (this.settings.allow_duplicates || (!this.settings.allow_duplicates && !isDuplicateNotification(this))) {
  			this.init();
  		}
  	}
  
  	$.extend(Notify.prototype, {
  		init: function () {
  			var self = this;
  
  			this.buildNotify();
  			if (this.settings.content.icon) {
  				this.setIcon();
  			}
  			if (this.settings.content.url != "#") {
  				this.styleURL();
  			}
  			this.styleDismiss();
  			this.placement();
  			this.bind();
  
  			this.notify = {
  				$ele: this.$ele,
  				update: function (command, update) {
  					var commands = {};
  					if (typeof command === "string") {
  						commands[command] = update;
  					} else {
  						commands = command;
  					}
  					for (var cmd in commands) {
  						switch (cmd) {
  							case "type":
  								this.$ele.removeClass('alert-' + self.settings.type);
  								this.$ele.find('[data-notify="progressbar"] > .progress-bar').removeClass('progress-bar-' + self.settings.type);
  								self.settings.type = commands[cmd];
  								this.$ele.addClass('alert-' + commands[cmd]).find('[data-notify="progressbar"] > .progress-bar').addClass('progress-bar-' + commands[cmd]);
  								break;
  							case "icon":
  								var $icon = this.$ele.find('[data-notify="icon"]');
  								if (self.settings.icon_type.toLowerCase() === 'class') {
  									$icon.removeClass(self.settings.content.icon).addClass(commands[cmd]);
  								} else {
  									if (!$icon.is('img')) {
  										$icon.find('img');
  									}
  									$icon.attr('src', commands[cmd]);
  								}
  								self.settings.content.icon = commands[command];
  								break;
  							case "progress":
  								var newDelay = self.settings.delay - (self.settings.delay * (commands[cmd] / 100));
  								this.$ele.data('notify-delay', newDelay);
  								this.$ele.find('[data-notify="progressbar"] > div').attr('aria-valuenow', commands[cmd]).css('width', commands[cmd] + '%');
  								break;
  							case "url":
  								this.$ele.find('[data-notify="url"]').attr('href', commands[cmd]);
  								break;
  							case "target":
  								this.$ele.find('[data-notify="url"]').attr('target', commands[cmd]);
  								break;
  							default:
  								this.$ele.find('[data-notify="' + cmd + '"]').html(commands[cmd]);
  						}
  					}
  					var posX = this.$ele.outerHeight() + parseInt(self.settings.spacing) + parseInt(self.settings.offset.y);
  					self.reposition(posX);
  				},
  				close: function () {
  					self.close();
  				}
  			};
  
  		},
  		buildNotify: function () {
  			var content = this.settings.content;
  			this.$ele = $(String.format(this.settings.template, this.settings.type, content.title, content.message, content.url, content.target));
  			this.$ele.attr('data-notify-position', this.settings.placement.from + '-' + this.settings.placement.align);
  			if (!this.settings.allow_dismiss) {
  				this.$ele.find('[data-notify="dismiss"]').css('display', 'none');
  			}
  			if ((this.settings.delay <= 0 && !this.settings.showProgressbar) || !this.settings.showProgressbar) {
  				this.$ele.find('[data-notify="progressbar"]').remove();
  			}
  		},
  		setIcon: function () {
  			if (this.settings.icon_type.toLowerCase() === 'class') {
  				this.$ele.find('[data-notify="icon"]').addClass(this.settings.content.icon);
  			} else {
  				if (this.$ele.find('[data-notify="icon"]').is('img')) {
  					this.$ele.find('[data-notify="icon"]').attr('src', this.settings.content.icon);
  				} else {
  					this.$ele.find('[data-notify="icon"]').append('<img src="' + this.settings.content.icon + '" alt="Notify Icon" />');
  				}
  			}
  		},
  		styleDismiss: function () {
  			this.$ele.find('[data-notify="dismiss"]').css({
  				position: 'absolute',
  				right: '10px',
  				top: '5px',
  				zIndex: this.settings.z_index + 2
  			});
  		},
  		styleURL: function () {
  			this.$ele.find('[data-notify="url"]').css({
  				backgroundImage: 'url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)',
  				height: '100%',
  				left: 0,
  				position: 'absolute',
  				top: 0,
  				width: '100%',
  				zIndex: this.settings.z_index + 1
  			});
  		},
  		placement: function () {
  			var self = this,
  				offsetAmt = this.settings.offset.y,
  				css = {
  					display: 'inline-block',
  					margin: '0px auto',
  					position: this.settings.position ? this.settings.position : (this.settings.element === 'body' ? 'fixed' : 'absolute'),
  					transition: 'all .5s ease-in-out',
  					zIndex: this.settings.z_index
  				},
  				hasAnimation = false,
  				settings = this.settings;
  
  			$('[data-notify-position="' + this.settings.placement.from + '-' + this.settings.placement.align + '"]:not([data-closing="true"])').each(function () {
  				offsetAmt = Math.max(offsetAmt, parseInt($(this).css(settings.placement.from)) + parseInt($(this).outerHeight()) + parseInt(settings.spacing));
  			});
  			if (this.settings.newest_on_top === true) {
  				offsetAmt = this.settings.offset.y;
  			}
  			css[this.settings.placement.from] = offsetAmt + 'px';
  
  			switch (this.settings.placement.align) {
  				case "left":
  				case "right":
  					css[this.settings.placement.align] = this.settings.offset.x + 'px';
  					break;
  				case "center":
  					css.left = 0;
  					css.right = 0;
  					break;
  			}
  			this.$ele.css(css).addClass(this.settings.animate.enter);
  			$.each(Array('webkit-', 'moz-', 'o-', 'ms-', ''), function (index, prefix) {
  				self.$ele[0].style[prefix + 'AnimationIterationCount'] = 1;
  			});
  
  			$(this.settings.element).append(this.$ele);
  
  			if (this.settings.newest_on_top === true) {
  				offsetAmt = (parseInt(offsetAmt) + parseInt(this.settings.spacing)) + this.$ele.outerHeight();
  				this.reposition(offsetAmt);
  			}
  
  			if ($.isFunction(self.settings.onShow)) {
  				self.settings.onShow.call(this.$ele);
  			}
  
  			this.$ele.one(this.animations.start, function () {
  				hasAnimation = true;
  			}).one(this.animations.end, function () {
  				self.$ele.removeClass(self.settings.animate.enter);
  				if ($.isFunction(self.settings.onShown)) {
  					self.settings.onShown.call(this);
  				}
  			});
  
  			setTimeout(function () {
  				if (!hasAnimation) {
  					if ($.isFunction(self.settings.onShown)) {
  						self.settings.onShown.call(this);
  					}
  				}
  			}, 600);
  		},
  		bind: function () {
  			var self = this;
  
  			this.$ele.find('[data-notify="dismiss"]').on('click', function () {
  				self.close();
  			});
  
  			if ($.isFunction(self.settings.onClick)) {
  			    this.$ele.on('click', function (event) {
  			        if (event.target != self.$ele.find('[data-notify="dismiss"]')[0]) {
  			            self.settings.onClick.call(this, event);
  			        }
  			    });
  			}
  
  			this.$ele.mouseover(function () {
  				$(this).data('data-hover', "true");
  			}).mouseout(function () {
  				$(this).data('data-hover', "false");
  			});
  			this.$ele.data('data-hover', "false");
  
  			if (this.settings.delay > 0) {
  				self.$ele.data('notify-delay', self.settings.delay);
  				var timer = setInterval(function () {
  					var delay = parseInt(self.$ele.data('notify-delay')) - self.settings.timer;
  					if ((self.$ele.data('data-hover') === 'false' && self.settings.mouse_over === "pause") || self.settings.mouse_over != "pause") {
  						var percent = ((self.settings.delay - delay) / self.settings.delay) * 100;
  						self.$ele.data('notify-delay', delay);
  						self.$ele.find('[data-notify="progressbar"] > div').attr('aria-valuenow', percent).css('width', percent + '%');
  					}
  					if (delay <= -(self.settings.timer)) {
  						clearInterval(timer);
  						self.close();
  					}
  				}, self.settings.timer);
  			}
  		},
  		close: function () {
  			var self = this,
  				posX = parseInt(this.$ele.css(this.settings.placement.from)),
  				hasAnimation = false;
  
  			this.$ele.attr('data-closing', 'true').addClass(this.settings.animate.exit);
  			self.reposition(posX);
  
  			if ($.isFunction(self.settings.onClose)) {
  				self.settings.onClose.call(this.$ele);
  			}
  
  			this.$ele.one(this.animations.start, function () {
  				hasAnimation = true;
  			}).one(this.animations.end, function () {
  				$(this).remove();
  				if ($.isFunction(self.settings.onClosed)) {
  					self.settings.onClosed.call(this);
  				}
  			});
  
  			setTimeout(function () {
  				if (!hasAnimation) {
  					self.$ele.remove();
  					if (self.settings.onClosed) {
  						self.settings.onClosed(self.$ele);
  					}
  				}
  			}, 600);
  		},
  		reposition: function (posX) {
  			var self = this,
  				notifies = '[data-notify-position="' + this.settings.placement.from + '-' + this.settings.placement.align + '"]:not([data-closing="true"])',
  				$elements = this.$ele.nextAll(notifies);
  			if (this.settings.newest_on_top === true) {
  				$elements = this.$ele.prevAll(notifies);
  			}
  			$elements.each(function () {
  				$(this).css(self.settings.placement.from, posX);
  				posX = (parseInt(posX) + parseInt(self.settings.spacing)) + $(this).outerHeight();
  			});
  		}
  	});
  
  	$.notify = function (content, options) {
  		var plugin = new Notify(this, content, options);
  		return plugin.notify;
  	};
  	$.notifyDefaults = function (options) {
  		defaults = $.extend(true, {}, defaults, options);
  		return defaults;
  	};
  
  	$.notifyClose = function (selector) {
  
  		if (typeof selector === "undefined" || selector === "all") {
  			$('[data-notify]').find('[data-notify="dismiss"]').trigger('click');
  		}else if(selector === 'success' || selector === 'info' || selector === 'warning' || selector === 'danger'){
  			$('.alert-' + selector + '[data-notify]').find('[data-notify="dismiss"]').trigger('click');
  		} else if(selector){
  			$(selector + '[data-notify]').find('[data-notify="dismiss"]').trigger('click');
  		}
  		else {
  			$('[data-notify-position="' + selector + '"]').find('[data-notify="dismiss"]').trigger('click');
  		}
  	};
  
  	$.notifyCloseExcept = function (selector) {
  
  		if(selector === 'success' || selector === 'info' || selector === 'warning' || selector === 'danger'){
  			$('[data-notify]').not('.alert-' + selector).find('[data-notify="dismiss"]').trigger('click');
  		} else{
  			$('[data-notify]').not(selector).find('[data-notify="dismiss"]').trigger('click');
  		}
  	};
  }));
  
  /* ====================================================================================================
    Date Dropper V3
  ==================================================================================================== */
  
  (function($) {
  	var
  		// CSS EVENT DETECT
  		csse = {
  			t : 'transitionend webkitTransitionEnd oTransitionEnd otransitionend MSTransitionEnd',
  			a : 'webkitAnimationEnd mozAnimationEnd oAnimationEnd oanimationend animationend'
  		},
  		// I18N
  		i18n = {
  			'en' : {
  				name : 'English',
  				gregorian : false,
  				months : {
  					short: [
  						'Jan',
  						'Feb',
  						'Mar',
  						'Apr',
  						'May',
  						'June',
  						'July',
  						'Aug',
  						'Sept',
  						'Oct',
  						'Nov',
  						'Dec'
  					],
  					full : [
  						'January',
  						'February',
  						'March',
  						'April',
  						'May',
  						'June',
  						'July',
  						'August',
  						'September',
  						'October',
  						'November',
  						'December'
  					]
  				},
  				weekdays : {
  					short : [
  						'S',
  						'M',
  						'T',
  						'W',
  						'T',
  						'F',
  						'S'
  					],
  					full : [
  						'Sunday',
  						'Monday',
  						'Tuesday',
  						'Wednesday',
  						'Thursday',
  						'Friday',
  						'Saturday'
  					]
  				}
  			},
  			'ka' : {
  				name : 'Georgian',
  				gregorian : false,
  				months : {
  					short: [
  						'იან',
  						'თებ',
  						'მარტ',
  						'აპრ',
  						'მაი',
  						'ივნ',
  						'ივლ',
  						'აგვ',
  						'სექტ',
  						'ოქტ',
  						'ნოემბ',
  						'დეკ'
  					],
  					full : [
  						'იანვარი',
  						'თებერვალი',
  						'მარტი',
  						'აპრილი',
  						'მაისი',
  						'ივნისი',
  						'ივლისი',
  						'აგვისტო',
  						'სექტემბერი',
  						'ოქტომბერი',
  						'ნოემბერი',
  						'დეკემბერი'
  					]
  				},
  				weekdays : {
  					short : [
  						'კვ',
  						'ორ',
  						'სამ',
  						'ოთხ',
  						'ხუთ',
  						'პარ',
  						'შაბ'
  					],
  					full : [
  						'კვირა',
  						'ორშაბათი',
  						'სამშაბათი',
  						'ოთხშაბათი',
  						'ხუთშაბათი',
  						'პარასკევი',
  						'შაბათი'
  					]
  				}
  			},//
  			'it' : {
  				name : 'Italiano',
  				gregorian : true,
  				months : {
  					short: [
  						'Gen',
  						'Feb',
  						'Mar',
  						'Apr',
  						'Mag',
  						'Giu',
  						'Lug',
  						'Ago',
  						'Set',
  						'Ott',
  						'Nov',
  						'Dic'
  					],
  					full : [
  						'Gennaio',
  						'Febbraio',
  						'Marzo',
  						'Aprile',
  						'Maggio',
  						'Giugno',
  						'Luglio',
  						'Agosto',
  						'Settembre',
  						'Ottobre',
  						'Novembre',
  						'Dicembre'
  					]
  				},
  				weekdays : {
  					short : [
  						'D',
  						'L',
  						'M',
  						'M',
  						'G',
  						'V',
  						'S'
  					],
  					full : [
  						'Domenica',
  						'Lunedì',
  						'Martedì',
  						'Mercoledì',
  						'Giovedì',
  						'Venerdì',
  						'Sabato'
  					]
  				}
  			},
  			'fr' : {
  				name : 'Français',
  				gregorian : true,
  				months : {
  					short: [
  						'Jan',
  						'Fév',
  						'Mar',
  						'Avr',
  						'Mai',
  						'Jui',
  						'Jui',
  						'Aoû',
  						'Sep',
  						'Oct',
  						'Nov',
  						'Déc'
  					],
  					full : [
  						'Janvier',
  						'Février',
  						'Mars',
  						'Avril',
  						'Mai',
  						'Juin',
  						'Juillet',
  						'Août',
  						'Septembre',
  						'Octobre',
  						'Novembre',
  						'Décembre'
  					]
  				},
  				weekdays : {
  					short : [
  						'D',
  						'L',
  						'M',
  						'M',
  						'J',
  						'V',
  						'S'
  					],
  					full : [
  						'Dimanche',
  						'Lundi',
  						'Mardi',
  						'Mercredi',
  						'Jeudi',
  						'Vendredi',
  						'Samedi'
  					]
  				}
  			},
  			'zh' : {
  				name : '中文',
  				gregorian : true,
  				months : {
  					short: [
  						'一月',
  						'二月',
  						'三月',
  						'四月',
  						'五月',
  						'六月',
  						'七月',
  						'八月',
  						'九月',
  						'十月',
  						'十一月',
  						'十二月'
  					],
  					full : [
  						'一月',
  						'二月',
  						'三月',
  						'四月',
  						'五月',
  						'六月',
  						'七月',
  						'八月',
  						'九月',
  						'十月',
  						'十一月',
  						'十二月'
  					]
  				},
  				weekdays : {
  					short : [
  						'天',
  						'一',
  						'二',
  						'三',
  						'四',
  						'五',
  						'六'
  					],
  					full : [
  						'星期天',
  						'星期一',
  						'星期二',
  						'星期三',
  						'星期四',
  						'星期五',
  						'星期六'
  					]
  				}
  			},
  			'ar' : {
  				name : 'العَرَبِيَّة',
  				gregorian : false,
  				months : {
  					short: [
  						'جانفي',
  						'فيفري',
  						'مارس',
  						'أفريل',
  						'ماي',
  						'جوان',
  						'جويلية',
  						'أوت',
  						'سبتمبر',
  						'أكتوبر',
  						'نوفمبر',
  						'ديسمبر'
  					],
  					full : [
  						'جانفي',
  						'فيفري',
  						'مارس',
  						'أفريل',
  						'ماي',
  						'جوان',
  						'جويلية',
  						'أوت',
  						'سبتمبر',
  						'أكتوبر',
  						'نوفمبر',
  						'ديسمبر'
  					]
  				},
  				weekdays : {
  					short : [
  						'S',
  						'M',
  						'T',
  						'W',
  						'T',
  						'F',
  						'S'
  					],
  					full : [
  						'الأحد',
  						'الإثنين',
  						'الثلثاء',
  						'الأربعاء',
  						'الخميس',
  						'الجمعة',
  						'السبت'
  					]
  				}
  			},
  			'fa' : {
  				name : 'فارسی',
  				gregorian : false,
  				months : {
  					short: [
  						'ژانویه',
  						'فووریه',
  						'مارچ',
  						'آپریل',
  						'می',
  						'جون',
  						'جولای',
  						'آگوست',
  						'سپتامبر',
  						'اکتبر',
  						'نوامبر',
  						'دسامبر'
  					],
  					full : [
  						'ژانویه',
  						'فووریه',
  						'مارچ',
  						'آپریل',
  						'می',
  						'جون',
  						'جولای',
  						'آگوست',
  						'سپتامبر',
  						'اکتبر',
  						'نوامبر',
  						'دسامبر'
  					]
  				},
  				weekdays : {
  					short : [
  						'S',
  						'M',
  						'T',
  						'W',
  						'T',
  						'F',
  						'S'
  					],
  					full : [
  						'یکشنبه',
  						'دوشنبه',
  						'سه شنبه',
  						'چهارشنبه',
  						'پنج شنبه',
  						'جمعه',
  						'شنبه'
  					]
  				}
  			},
  			'hu' : {
  				name : 'Hungarian',
  				gregorian : true,
  				months : {
  					short: [
  						"jan",
  						"feb",
  						"már",
  						"ápr",
  						"máj",
  						"jún",
  						"júl",
  						"aug",
  						"sze",
  						"okt",
  						"nov",
  						"dec"
  					],
  					full : [
  						"január",
  						"február",
  						"március",
  						"április",
  						"május",
  						"június",
  						"július",
  						"augusztus",
  						"szeptember",
  						"október",
  						"november",
  						"december"
  					]
  				},
  				weekdays : {
  					short : [
  						'v',
  						'h',
  						'k',
  						's',
  						'c',
  						'p',
  						's'
  					],
  					full : [
  						'vasárnap',
  						'hétfő',
  						'kedd',
  						'szerda',
  						'csütörtök',
  						'péntek',
  						'szombat'
  					]
  				}
  			},
  			'gr' : {
  				name : 'Ελληνικά',
  				gregorian : true,
  				months : {
  					short: [
  						"Ιαν",
  						"Φεβ",
  						"Μάρ",
  						"Απρ",
  						"Μάι",
  						"Ιούν",
  						"Ιούλ",
  						"Αύγ",
  						"Σεπ",
  						"Οκτ",
  						"Νοέ",
  						"Δεκ"
  					],
  					full : [
  						"Ιανουάριος",
  						"Φεβρουάριος",
  						"Μάρτιος",
  						"Απρίλιος",
  						"Μάιος",
  						"Ιούνιος",
  						"Ιούλιος",
  						"Αύγουστος",
  						"Σεπτέμβριος",
  						"Οκτώβριος",
  						"Νοέμβριος",
  						"Δεκέμβριος"
  					]
  				},
  				weekdays : {
  					short : [
  						'Κ',
  						'Δ',
  						'Τ',
  						'Τ',
  						'Π',
  						'Π',
  						'Σ'
  					],
  					full : [
  						'Κυριακή',
  						'Δευτέρα',
  						'Τρίτη',
  						'Τετάρτη',
  						'Πέμπτη',
  						'Παρασκευή',
  						'Σάββατο'
  					]
  				}
  			},
  			'es' : {
  				name : 'Español',
  				gregorian : true,
  				months : {
  					short: [
  						"Ene",
  						"Feb",
  						"Mar",
  						"Abr",
  						"May",
  						"Jun",
  						"Jul",
  						"Ago",
  						"Sep",
  						"Oct",
  						"Nov",
  						"Dic"
  					],
  					full : [
  						"Enero",
  						"Febrero",
  						"Marzo",
  						"Abril",
  						"Mayo",
  						"Junio",
  						"Julio",
  						"Agosto",
  						"Septiembre",
  						"Octubre",
  						"Noviembre",
  						"Diciembre"
  					]
  				},
  				weekdays : {
  					short : [
  						'D',
  						'L',
  						'M',
  						'X',
  						'J',
  						'V',
  						'S'
  					],
  					full : [
  						'Domingo',
  						'Lunes',
  						'Martes',
  						'Miércoles',
  						'Jueves',
  						'Viernes',
  						'Sábado'
  					]
  				}
  			},
  			'da' : {
  				name : 'Dansk',
  				gregorian : true,
  				months : {
  					short: [
  						"jan",
  						"feb",
  						"mar",
  						"apr",
  						"maj",
  						"jun",
  						"jul",
  						"aug",
  						"sep",
  						"okt",
  						"nov",
  						"dec"
  					],
  					full : [
  						"januar",
  						"februar",
  						"marts",
  						"april",
  						"maj",
  						"juni",
  						"juli",
  						"august",
  						"september",
  						"oktober",
  						"november",
  						"december"
  					]
  				},
  				weekdays : {
  					short : [
  						's',
  						'm',
  						't',
  						'o',
  						't',
  						'f',
  						'l'
  					],
  					full : [
  						'søndag',
  						'mandag',
  						'tirsdag',
  						'onsdag',
  						'torsdag',
  						'fredag',
  						'lørdag'
  					]
  				}
  			},
  			'de' : {
  				name : 'Deutsch',
  				gregorian : true,
  				months : {
  					short: [
  						"Jan",
  						"Feb",
  						"Mär",
  						"Apr",
  						"Mai",
  						"Jun",
  						"Jul",
  						"Aug",
  						"Sep",
  						"Okt",
  						"Nov",
  						"Dez"
  					],
  					full : [
  						"Januar",
  						"Februar",
  						"März",
  						"April",
  						"Mai",
  						"Juni",
  						"Juli",
  						"August",
  						"September",
  						"Oktober",
  						"November",
  						"Dezember"
  					]
  				},
  				weekdays : {
  					short : [
  						'S',
  						'M',
  						'D',
  						'M',
  						'D',
  						'F',
  						'S'
  					],
  					full : [
  						'Sonntag',
  						'Montag',
  						'Dienstag',
  						'Mittwoch',
  						'Donnerstag',
  						'Freitag',
  						'Samstag'
  					]
  				}
  			},
  			'nl' : {
  				name : 'Nederlands',
  				gregorian : true,
  				months : {
  					short: [
  						"jan",
  						"feb",
  						"maa",
  						"apr",
  						"mei",
  						"jun",
  						"jul",
  						"aug",
  						"sep",
  						"okt",
  						"nov",
  						"dec"
  					],
  					full : [
  						"januari",
  						"februari",
  						"maart",
  						"april",
  						"mei",
  						"juni",
  						"juli",
  						"augustus",
  						"september",
  						"oktober",
  						"november",
  						"december"
  					]
  				},
  				weekdays : {
  					short : [
  						'z',
  						'm',
  						'd',
  						'w',
  						'd',
  						'v',
  						'z'
  					],
  					full : [
  						'zondag',
  						'maandag',
  						'dinsdag',
  						'woensdag',
  						'donderdag',
  						'vrijdag',
  						'zaterdag'
  					]
  				}
  			},
  			'pl' : {
  				name : 'język polski',
  				gregorian : true,
  				months : {
  					short: [
  						"sty",
  						"lut",
  						"mar",
  						"kwi",
  						"maj",
  						"cze",
  						"lip",
  						"sie",
  						"wrz",
  						"paź",
  						"lis",
  						"gru"
  					],
  					full : [
  						"styczeń",
  						"luty",
  						"marzec",
  						"kwiecień",
  						"maj",
  						"czerwiec",
  						"lipiec",
  						"sierpień",
  						"wrzesień",
  						"październik",
  						"listopad",
  						"grudzień"
  					]
  				},
  				weekdays : {
  					short : [
  						'n',
  						'p',
  						'w',
  						'ś',
  						'c',
  						'p',
  						's'
  					],
  					full : [
  						'niedziela',
  						'poniedziałek',
  						'wtorek',
  						'środa',
  						'czwartek',
  						'piątek',
  						'sobota'
  					]
  				}
  			},
  			'pt' : {
  				name : 'Português',
  				gregorian : true,
  				months : {
  					short: [
  						"Janeiro",
  						"Fevereiro",
  						"Março",
  						"Abril",
  						"Maio",
  						"Junho",
  						"Julho",
  						"Agosto",
  						"Setembro",
  						"Outubro",
  						"Novembro",
  						"Dezembro"
  					],
  					full : [
  						"Janeiro",
  						"Fevereiro",
  						"Março",
  						"Abril",
  						"Maio",
  						"Junho",
  						"Julho",
  						"Agosto",
  						"Setembro",
  						"Outubro",
  						"Novembro",
  						"Dezembro"
  					]
  				},
  				weekdays : {
  					short : [
  						"D",
  						"S",
  						"T",
  						"Q",
  						"Q",
  						"S",
  						"S"
  					],
  					full : [
  						"Domingo",
  						"Segunda",
  						"Terça",
  						"Quarta",
  						"Quinta",
  						"Sexta",
  						"Sábado"
  					]
  				}
  			},
  			'si' : {
  				name : 'Slovenščina',
  				gregorian : true,
  				months : {
  					short: [
  						"jan",
  						"feb",
  						"mar",
  						"apr",
  						"maj",
  						"jun",
  						"jul",
  						"avg",
  						"sep",
  						"okt",
  						"nov",
  						"dec"
  					],
  					full : [
  						"januar",
  						"februar",
  						"marec",
  						"april",
  						"maj",
  						"junij",
  						"julij",
  						"avgust",
  						"september",
  						"oktober",
  						"november",
  						"december"
  					]
  				},
  				weekdays : {
  					short : [
  						'n',
  						'p',
  						't',
  						's',
  						'č',
  						'p',
  						's'
  					],
  					full : [
  						'nedelja',
  						'ponedeljek',
  						'torek',
  						'sreda',
  						'četrtek',
  						'petek',
  						'sobota'
  					]
  				}
  			},
  			'uk' : {
  				name : 'українська мова',
  				gregorian : true,
  				months : {
  					short: [
  						"січень",
  						"лютий",
  						"березень",
  						"квітень",
  						"травень",
  						"червень",
  						"липень",
  						"серпень",
  						"вересень",
  						"жовтень",
  						"листопад",
  						"грудень"
  					],
  					full : [
  						"січень",
  						"лютий",
  						"березень",
  						"квітень",
  						"травень",
  						"червень",
  						"липень",
  						"серпень",
  						"вересень",
  						"жовтень",
  						"листопад",
  						"грудень"
  					]
  				},
  				weekdays : {
  					short : [
  						'н',
  						'п',
  						'в',
  						'с',
  						'ч',
  						'п',
  						'с'
  					],
  					full : [
  						'неділя',
  						'понеділок',
  						'вівторок',
  						'середа',
  						'четвер',
  						'п\'ятниця',
  						'субота'
  					]
  				}
  			},
  			'ru' : {
  				name : 'русский язык',
  				gregorian : true,
  				months : {
  					short: [
  						"январь",
  						"февраль",
  						"март",
  						"апрель",
  						"май",
  						"июнь",
  						"июль",
  						"август",
  						"сентябрь",
  						"октябрь",
  						"ноябрь",
  						"декабрь"
  					],
  					full : [
  						"январь",
  						"февраль",
  						"март",
  						"апрель",
  						"май",
  						"июнь",
  						"июль",
  						"август",
  						"сентябрь",
  						"октябрь",
  						"ноябрь",
  						"декабрь"
  					]
  				},
  				weekdays : {
  					short : [
  						'в',
  						'п',
  						'в',
  						'с',
  						'ч',
  						'п',
  						'с'
  					],
  					full : [
  						'воскресенье',
  						'понедельник',
  						'вторник',
  						'среда',
  						'четверг',
  						'пятница',
  						'суббота'
  					]
  				}
  			},
  			'tr' : {
  				name : 'Türkçe',
  				gregorian : true,
  				months : {
  					short: [
  						"Oca",
  						"Şub",
  						"Mar",
  						"Nis",
  						"May",
  						"Haz",
  						"Tem",
  						"Ağu",
  						"Eyl",
  						"Eki",
  						"Kas",
  						"Ara"
  					],
  					full : [
  						"Ocak",
  						"Şubat",
  						"Mart",
  						"Nisan",
  						"Mayıs",
  						"Haziran",
  						"Temmuz",
  						"Ağustos",
  						"Eylül",
  						"Ekim",
  						"Kasım",
  						"Aralık"
  					]
  				},
  				weekdays : {
  					short : [
  						'P',
  						'P',
  						'S',
  						'Ç',
  						'P',
  						'C',
  						'C'
  					],
  					full : [
  						'Pazar',
  						'Pazartesi',
  						'Sali',
  						'Çarşamba',
  						'Perşembe',
  						'Cuma',
  						'Cumartesi'
  					]
  				}
  			},
  			'ko' : {
  				name : '조선말',
  				gregorian : true,
  				months : {
  					short: [
  						"1월",
  						"2월",
  						"3월",
  						"4월",
  						"5월",
  						"6월",
  						"7월",
  						"8월",
  						"9월",
  						"10월",
  						"11월",
  						"12월"
  					],
  					full : [
  						"1월",
  						"2월",
  						"3월",
  						"4월",
  						"5월",
  						"6월",
  						"7월",
  						"8월",
  						"9월",
  						"10월",
  						"11월",
  						"12월"
  					]
  				},
  				weekdays : {
  					short : [
  						'일',
  						'월',
  						'화',
  						'수',
  						'목',
  						'금',
  						'토'
  					],
  					full : [
  						'일요일',
  						'월요일',
  						'화요일',
  						'수요일',
  						'목요일',
  						'금요일',
  						'토요일'
  					]
  				}
  			},
  			'fi' : {
  				name : 'suomen kieli',
  				gregorian : true,
  				months : {
  					short: [
  						"Tam",
  						"Hel",
  						"Maa",
  						"Huh",
  						"Tou",
  						"Kes",
  						"Hei",
  						"Elo",
  						"Syy",
  						"Lok",
  						"Mar",
  						"Jou"
  					],
  					full : [
  						"Tammikuu",
  						"Helmikuu",
  						"Maaliskuu",
  						"Huhtikuu",
  						"Toukokuu",
  						"Kesäkuu",
  						"Heinäkuu",
  						"Elokuu",
  						"Syyskuu",
  						"Lokakuu",
  						"Marraskuu",
  						"Joulukuu"
  					]
  				},
  				weekdays : {
  					short : [
  						'S',
  						'M',
  						'T',
  						'K',
  						'T',
  						'P',
  						'L'
  					],
  					full : [
  						'Sunnuntai',
  						'Maanantai',
  						'Tiistai',
  						'Keskiviikko',
  						'Torstai',
  						'Perjantai',
  						'Lauantai'
  					]
  				}
  			},
  			'vi':{
  				name:'Tiếng việt',
  				gregorian:false,
  				months:{
  					short:[
  						'Th.01',
  						'Th.02',
  						'Th.03',
  						'Th.04',
  						'Th.05',
  						'Th.06',
  						'Th.07',
  						'Th.08',
  						'Th.09',
  						'Th.10',
  						'Th.11',
  						'Th.12'
  					],
  					full:[
  						'Tháng 01',
  						'Tháng 02',
  						'Tháng 03',
  						'Tháng 04',
  						'Tháng 05',
  						'Tháng 06',
  						'Tháng 07',
  						'Tháng 08',
  						'Tháng 09',
  						'Tháng 10',
  						'Tháng 11',
  						'Tháng 12'
  					]
  				},
  				weekdays:{
  					short:[
  						'CN',
  						'T2',
  						'T3',
  						'T4',
  						'T5',
  						'T6',
  						'T7'
  					],
  					full:[
  						'Chủ nhật',
  						'Thứ hai',
  						'Thứ ba',
  						'Thứ tư',
  						'Thứ năm',
  						'Thứ sáu',
  						'Thứ bảy'
  					]
  				}
  			}
  		},
  
  		// MAIN VARS
  
  		pickers = {},
  		picker = null,
  		picker_ctrl = false,
  		pick_dragged = null,
  		pick_drag_offset = null,
  		pick_drag_temp = null,
  
  		// CHECK FUNCTIONS
  
  		is_click = false,
  		is_ie = function() {
  			var
  				n = navigator.userAgent.toLowerCase();
  			return (n.indexOf('msie') != -1) ? parseInt(n.split('msie')[1]) : false;
  		},
  		is_touch = function() {
  			if(/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent))
  				return true;
  			else
  				return false;
  		},
  		is_fx_mobile = function() {
  			if(picker&&pickers[picker.id].fx&&!pickers[picker.id].fxmobile) {
  				if($(window).width()<480)
  					picker.element.removeClass('picker-fxs');
  				else
  					picker.element.addClass('picker-fxs')
  			}
  		},
  		is_jumpable = function() {
  			if( pickers[picker.id].jump >= pickers[picker.id].key.y.max - pickers[picker.id].key.y.min )
  				return false;
  			else
  				return true;
  		},
  		is_locked = function() {
  			var
  				unix_current = get_unix(get_current_full()),
  				unix_today = get_unix(get_today_full());
  
  			if(pickers[picker.id].lock) {
  				if(pickers[picker.id].lock=='from') {
  					if(unix_current<unix_today) {
  						picker_alrt();
  						picker.element.addClass('picker-lkd');
  						return true;
  					}
  					else {
  						picker.element.removeClass('picker-lkd');
  						return false;
  					}
  				}
  				if(pickers[picker.id].lock=='to') {
  					if(unix_current>unix_today) {
  						picker_alrt();
  						picker.element.addClass('picker-lkd');
  						return true;
  					}
  					else {
  						picker.element.removeClass('picker-lkd');
  						return false;
  					}
  				}
  			}
  
  			if(pickers[picker.id].disabledays) {
  				if(pickers[picker.id].disabledays.indexOf(unix_current) != -1) {
  					picker_alrt();
  					picker.element.addClass('picker-lkd');
  					return true;
  				}
  				else {
  					picker.element.removeClass('picker-lkd');
  					return false;
  				}
  			}
  		},
  		is_int = function(n) {
  			return n % 1 === 0;
  		},
  		is_date = function(value) {
  			var
  				format = /(^\d{1,4}[\.|\\/|-]\d{1,2}[\.|\\/|-]\d{1,4})(\s*(?:0?[1-9]:[0-5]|1(?=[012])\d:[0-5])\d\s*[ap]m)?$/;
  			return format.test(value);
  		},
  
  		// REST FUNCTIONS
  
  		get_current = function(k){
  			return parseInt(pickers[picker.id].key[k].current);
  		},
  		get_today = function(k){
  			return parseInt(pickers[picker.id].key[k].today);
  		},
  		get_today_full = function() {
  			return get_today('m')+'/'+get_today('d')+'/'+get_today('y');
  		},
  		get_current_full = function() {
  			return get_current('m')+'/'+get_current('d')+'/'+get_current('y');
  		},
  		get_jumped = function(k,val) {
  			var
  				a = [],
  				key_values = pickers[picker.id].key[k];
  			for (var i = key_values.min; i <= key_values.max; i++)
  				if (i%val == 0)
  					a.push(i);
  			return a;
  		},
  		get_closest_jumped = function(int,arr) {
  			var c = arr[0];
  			var d = Math.abs (int - c);
  			for (var i = 0; i < arr.length; i++) {
  				var n = Math.abs (int - arr[i]);
  				if (n < d) {
  					d = n;
  					c = arr[i];
  				}
  			}
  			return c;
  		},
  		get_clear = function(k,n){
  			var
  				key_values = pickers[picker.id].key[k];
  			if( n > key_values.max )
  				return get_clear( k , (n-key_values.max)+(key_values.min-1) );
  			else if( n < key_values.min )
  				return get_clear( k , (n+1) + (key_values.max - key_values.min));
  			else
  				return n;
  		},
  		get_days_array = function() {
  			if(i18n[pickers[picker.id].lang].gregorian)
  				return [1,2,3,4,5,6,0];
  			else
  				return [0,1,2,3,4,5,6];
  		},
  		get_ul = function(k) {
  			return get_picker_els('ul.pick[data-k="'+k+'"]');
  		},
  		get_eq = function(k,d) {
  			ul = get_ul(k);
  			var
  				o = [];
  
  			ul.find('li').each(function(){
  				o.push($(this).attr('value'));
  			});
  
  			if(d=='last')
  				return o[o.length-1];
  			else
  				return o[0];
  
  		},
  		get_picker_els = function(el) {
  			if(picker)
  				return picker.element.find(el);
  		},
  		get_unix = function(d) {
  			return Date.parse(d) / 1000;
  		},
  
  		// RENDER FUNCTIONS
  
  		picker_large_onoff = function() {
  			if(pickers[picker.id].large) {
  				picker.element.toggleClass('picker-lg');
  				picker_render_calendar();
  			}
  		},
  		picker_translate_onoff = function() {
  			get_picker_els('ul.pick.pick-l').toggleClass('visible');
  		},
  		picker_offset = function(){
  			if(!picker.element.hasClass('picker-modal')){
  				var
  					input = picker.input,
  					left = input.offset().left + input.outerWidth()/2,
  					top = input.offset().top + input.outerHeight();
  				picker.element.css({
  					'left' : left,
  					'top' : top
  				});
  			}
  		},
  		picker_translate = function(v) {
  			pickers[picker.id].lang = Object.keys(i18n)[v];
  			picker_set_lang();
  			picker_set();
  		},
  		picker_set_lang = function() {
  			var
  				picker_day_offset = get_days_array();
  			get_picker_els('.pick-lg .pick-lg-h li').each(function(i){
  				$(this).html(i18n[pickers[picker.id].lang].weekdays.short[picker_day_offset[i]]);
  			});
  			get_picker_els('ul.pick.pick-m li').each(function(){
  				$(this).html(i18n[pickers[picker.id].lang].months.short[$(this).attr('value')-1]);
  			});
  		},
  		picker_show = function() {
  			picker.element.addClass('picker-focus');
  		},
  		picker_hide = function() {
  			if(!is_locked()) {
  				picker.element.removeClass('picker-focus');
  				if(picker.element.hasClass('picker-modal'))
  					$('.picker-modal-overlay').addClass('tohide');
  				picker = null;
  			}
  			picker_ctrl = false;
  		},
  		picker_render_ul = function(k){
  			var
  				ul = get_ul(k),
  				key_values = pickers[picker.id].key[k];
  
  			//CURRENT VALUE
  			pickers[picker.id].key[k].current = key_values.today < key_values.min && key_values.min || key_values.today;
  
  			for (i = key_values.min; i <= key_values.max; i++) {
  				var
  					html = i;
  
  				if(k=='m')
  					html = i18n[pickers[picker.id].lang].months.short[i-1];
  				if(k=='l')
  					html = i18n[Object.keys(i18n)[i]].name;
  
  				html += k=='d' ? '<span></span>' : '';
  
  				$('<li>', {
  					value: i,
  					html: html
  				})
  				.appendTo(ul)
  			}
  
  			//PREV BUTTON
  			$('<div>', {
  				class: 'pick-arw pick-arw-s1 pick-arw-l',
  				html: $('<i>', {
  					class: 'pick-i-l'
  				})
  			})
  			.appendTo(ul);
  
  			//NEXT BUTTON
  			$('<div>', {
  				class: 'pick-arw pick-arw-s1 pick-arw-r',
  				html: $('<i>', {
  					class: 'pick-i-r'
  				})
  			})
  			.appendTo(ul);
  
  			if(k=='y') {
  
  				//PREV BUTTON
  				$('<div>', {
  					class: 'pick-arw pick-arw-s2 pick-arw-l',
  					html: $('<i>', {
  						class: 'pick-i-l'
  					})
  				})
  				.appendTo(ul);
  
  				//NEXT BUTTON
  				$('<div>', {
  					class: 'pick-arw pick-arw-s2 pick-arw-r',
  					html: $('<i>', {
  						class: 'pick-i-r'
  					})
  				})
  				.appendTo(ul);
  
  			}
  
  			picker_ul_transition(k,get_current(k));
  
  		},
  		picker_render_calendar = function() {
  
  			var
  				index = 0,
  				w = get_picker_els('.pick-lg-b');
  
  			w.find('li')
  			.empty()
  			.removeClass('pick-n pick-b pick-a pick-v pick-lk pick-sl pick-h')
  			.attr('data-value','');
  
  			var
  				_C = new Date(get_current_full()),
  				_S = new Date(get_current_full()),
  				_L = new Date(get_current_full()),
  				_NUM = function(d){
  					var
  						m = d.getMonth(),
  						y = d.getFullYear();
  					var l = ((y % 4) == 0 && ((y % 100) != 0 || (y % 400) == 0));
  					return [31, (l ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][m];
  				};
  
  			_L.setMonth(_L.getMonth()-1);
  			_S.setDate(1);
  
  			var
  				o = _S.getDay()-1;
  				if(o<0)
  					o = 6;
  				if(i18n[pickers[picker.id].lang].gregorian) {
  					o--;
  					if(o<0)
  						o=6;
  				}
  
  			//before
  			for(var i = _NUM(_L)-o ; i <= _NUM(_L) ; i++) {
  				w.find('li').eq(index)
  				.html(i)
  				.addClass('pick-b pick-n pick-h');
  				index++;
  			}
  			//current
  			for(var i = 1 ; i <= _NUM(_S) ; i++) {
  				w.find('li').eq(index)
  				.html(i)
  				.addClass('pick-n pick-v')
  				.attr('data-value',i);
  				index++;
  			}
  			//after
  			if(w.find('li.pick-n').length < 42) {
  				var
  					e = 42 - w.find('li.pick-n').length;
  				for(var i = 1 ; i <= e; i++) {
  					w.find('li').eq(index).html(i)
  					.addClass('pick-a pick-n pick-h');
  					index++;
  				}
  			}
  			if(pickers[picker.id].lock) {
  				if(pickers[picker.id].lock==='from') {
  					if(get_current('y')<=get_today('y')) {
  						if(get_current('m')==get_today('m')) {
  							get_picker_els('.pick-lg .pick-lg-b li.pick-v[data-value="'+get_today('d')+'"]')
  							.prevAll('li')
  							.addClass('pick-lk')
  						}
  						else {
  							if(get_current('m')<get_today('m')) {
  								get_picker_els('.pick-lg .pick-lg-b li')
  								.addClass('pick-lk')
  							}
  							else if(get_current('m')>get_today('m')&&get_current('y')<get_today('y')) {
  								get_picker_els('.pick-lg .pick-lg-b li')
  								.addClass('pick-lk')
  							}
  						}
  					}
  				}
  				else {
  					if(get_current('y')>=get_today('y')) {
  						if(get_current('m')==get_today('m')) {
  							get_picker_els('.pick-lg .pick-lg-b li.pick-v[data-value="'+get_today('d')+'"]')
  							.nextAll('li')
  							.addClass('pick-lk')
  						}
  						else {
  							if(get_current('m')>get_today('m')) {
  								get_picker_els('.pick-lg .pick-lg-b li')
  								.addClass('pick-lk')
  							}
  							else if(get_current('m')<get_today('m')&&get_current('y')>get_today('y')) {
  								get_picker_els('.pick-lg .pick-lg-b li')
  								.addClass('pick-lk')
  							}
  						}
  					}
  				}
  			}
  			if(pickers[picker.id].disabledays) {
  				$.each(pickers[picker.id].disabledays, function( i, v ) {
  					if(v&&is_date(v)) {
  						var
  							d = new Date(v*1000);
  						if(d.getMonth()+1==get_current('m')&&d.getFullYear()==get_current('y'))
  							get_picker_els('.pick-lg .pick-lg-b li.pick-v[data-value="'+d.getDate()+'"]')
  							.addClass('pick-lk');
  					}
  				});
  			}
  
  			get_picker_els('.pick-lg-b li.pick-v[data-value='+get_current('d')+']').addClass('pick-sl');
  
  		},
  		picker_fills = function() {
  
  			var
  				m = get_current('m'),
  				y = get_current('y'),
  				l = ((y % 4) == 0 && ((y % 100) != 0 || (y % 400) == 0));
  
  			pickers[picker.id].key['d'].max =  [31, (l ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][m-1];
  
  			if(get_current('d')>pickers[picker.id].key['d'].max) {
  				pickers[picker.id].key['d'].current = pickers[picker.id].key['d'].max;
  				picker_ul_transition('d',get_current('d'));
  			}
  
  			get_picker_els('.pick-d li')
  			.removeClass('pick-wke')
  			.each(function() {
  				var
  					d = new Date(m+"/"+$(this).attr('value')+"/"+y).getDay();
  
  				$(this)
  				.find('span')
  				.html(i18n[pickers[picker.id].lang].weekdays.full[d]);
  
  				if(d==0||d==6)
  					$(this).addClass('pick-wke');
  
  			});
  
  			if(picker.element.hasClass('picker-lg')) {
  				get_picker_els('.pick-lg-b li').removeClass('pick-wke');
  				get_picker_els('.pick-lg-b li.pick-v')
  				.each(function() {
  					var
  						d = new Date(m+"/"+$(this).attr('data-value')+"/"+y).getDay();
  					if(d==0||d==6)
  						$(this).addClass('pick-wke');
  
  				});
  			}
  
  		},
  		picker_set = function() {
  			if(picker.element.hasClass('picker-lg'))
  				picker_render_calendar();
  			picker_fills();
  			input_change_value();
  		},
  
  		// ACTION FUNCTIONS
  
  		picker_ul_transition = function(k,i) {
  
  			var
  				ul = get_ul(k);
  
  			ul.find('li').removeClass('pick-sl pick-bfr pick-afr');
  
  			if(i==get_eq(k,'last')) {
  				var li = ul.find('li[value="'+get_eq(k,'first')+'"]');
  				li.clone().insertAfter(ul.find('li[value='+i+']'));
  				li.remove();
  			}
  			if(i==get_eq(k,'first')) {
  				var li = ul.find('li[value="'+get_eq(k,'last')+'"]');
  				li.clone().insertBefore(ul.find('li[value='+i+']'));
  				li.remove();
  			}
  
  			ul.find('li[value='+i+']').addClass('pick-sl');
  			ul.find('li.pick-sl').nextAll('li').addClass('pick-afr');
  			ul.find('li.pick-sl').prevAll('li').addClass('pick-bfr');
  
  		},
  		picker_values_increase = function(k,v) {
  
  			var
  				key_values = pickers[picker.id].key[k];
  
  			if(v>key_values.max) {
  				if(k=='d')
  					picker_ul_turn('m','right');
  				if(k=='m')
  					picker_ul_turn('y','right');
  				v = key_values.min;
  			}
  			if(v<key_values.min) {
  				if(k=='d')
  					picker_ul_turn('m','left');
  				if(k=='m')
  					picker_ul_turn('y','left');
  				v = key_values.max;
  			}
  			pickers[picker.id].key[k].current = v;
  			picker_ul_transition(k,v);
  
  		},
  		picker_ul_turn = function(k,d) {
  			var
  				v = get_current(k);
  			if(d=='right')
  				v++;
  			else
  				v--;
  			picker_values_increase(k,v);
  		},
  		picker_alrt = function() {
  			picker.element
  			.addClass('picker-rmbl');
  		},
  
  		/* INPUT FUNCTIONS */
  
  		input_fill = function(n) {
  			return n < 10 ? '0' + n : n
  		},
  		input_ordinal_suffix = function(n) {
  			var
  				s=["th","st","nd","rd"],
  				v=n%100;
  			return n+(s[(v-20)%10]||s[v]||s[0]);
  		},
  		input_change_value = function() {
  
  			if(!is_locked()&&picker_ctrl) {
  
  				var
  					d = get_current('d'),
  					m = get_current('m'),
  					y = get_current('y'),
  					get_day = new Date(m+"/"+d+"/"+y).getDay(),
  
  					str =
  					pickers[picker.id].format
  					.replace(/\b(d)\b/g, input_fill(d))
  					.replace(/\b(m)\b/g, input_fill(m))
  					.replace(/\b(S)\b/g, input_ordinal_suffix(d)) //new
  					.replace(/\b(Y)\b/g, y)
  					.replace(/\b(U)\b/g, get_unix(get_current_full())) //new
  					.replace(/\b(D)\b/g, i18n[pickers[picker.id].lang].weekdays.short[get_day])
  					.replace(/\b(l)\b/g, i18n[pickers[picker.id].lang].weekdays.full[get_day])
  					.replace(/\b(F)\b/g, i18n[pickers[picker.id].lang].months.full[m-1])
  					.replace(/\b(M)\b/g, i18n[pickers[picker.id].lang].months.short[m-1])
  					.replace(/\b(n)\b/g, m)
  					.replace(/\b(j)\b/g, d);
  
  				picker
  				.input
  				.val(str)
  				.change();
  
  				picker_ctrl = false;
  
  			}
  
  		};
  
  	// GET UI EVENT
  
  	if(is_touch())
  		var
  			ui_event = {
  				i : 'touchstart',
  				m	: 'touchmove',
  				e : 'touchend'
  			}
  	else
  		var
  			ui_event = {
  				i : 'mousedown',
  				m	: 'mousemove',
  				e : 'mouseup'
  			}
  
  
  	var
  		picker_node_el = 'div.datedropper.picker-focus';
  
  	$(document)
  
  
  	//CLOSE PICKER
  	.on('click',function(e) {
  		if(picker) {
  			if(!picker.input.is(e.target) && !picker.element.is(e.target) && picker.element.has(e.target).length === 0) {
  				picker_hide();
  				pick_dragged = null;
  			}
  		}
  	})
  
  	//LOCK ANIMATION
  	.on(csse.a,picker_node_el + '.picker-rmbl',function(){
  		if(picker.element.hasClass('picker-rmbl'))
  			$(this).removeClass('picker-rmbl');
  	})
  
  	//HIDE MODAL OVERLAY
  	.on(csse.t,'.picker-modal-overlay',function(){
  		$(this).remove();
  	})
  
  
  	//LARGE-MODE DAY CLICK
  	.on(ui_event.i,picker_node_el+' .pick-lg li.pick-v',function(){
  		get_picker_els('.pick-lg-b li').removeClass('pick-sl');
  		$(this).addClass('pick-sl');
  		pickers[picker.id].key['d'].current = $(this).attr('data-value');
  		picker_ul_transition('d',$(this).attr('data-value'));
  		picker_ctrl = true;
  	})
  
  	//BUTTON LARGE-MODE
  	.on('click',picker_node_el+' .pick-btn-sz',function(){
  		picker_large_onoff();
  	})
  
  	//BUTTON TRANSLATE-MODE
  	.on('click',picker_node_el+' .pick-btn-lng',function(){
  		picker_translate_onoff();
  	})
  
  	//JUMP
  	.on(ui_event.i,picker_node_el+' .pick-arw.pick-arw-s2',function(e){
  
  		e.preventDefault();
  		pick_dragged = null;
  
  		var
  			i,
  			k = $(this).closest('ul').data('k'),
  			jump = pickers[picker.id].jump;
  
  		if($(this).hasClass('pick-arw-r'))
  			i = get_current('y') + jump;
  		else
  			i = get_current('y') - jump;
  
  		var
  			jumped_array = get_jumped('y',jump);
  
  		if(i>jumped_array[jumped_array.length-1])
  			i = jumped_array[0];
  		if(i<jumped_array[0])
  			i = jumped_array[jumped_array.length-1];
  
  		pickers[picker.id].key['y'].current = i;
  		picker_ul_transition('y',get_current('y'));
  
  		picker_ctrl = true;
  
  	})
  
  	//DEFAULT ARROW
  	.on(ui_event.i,picker_node_el+' .pick-arw.pick-arw-s1',function(e){
  		e.preventDefault();
  		pick_dragged = null;
  		var
  			k = $(this).closest('ul').data('k');
  		if($(this).hasClass('pick-arw-r'))
  			picker_ul_turn(k,'right');
  		else
  			picker_ul_turn(k,'left');
  
  		picker_ctrl = true;
  
  	})
  
  	// JUMP
  	.on(ui_event.i,picker_node_el+' ul.pick.pick-y li',function(){
  		is_click = true;
  	})
  	.on(ui_event.e,picker_node_el+' ul.pick.pick-y li',function(){
  		if(is_click&&is_jumpable()) {
  			$(this).closest('ul').toggleClass('pick-jump');
  			var
  				jumped = get_closest_jumped(get_current('y'),get_jumped('y',pickers[picker.id].jump));
  			pickers[picker.id].key['y'].current = jumped;
  			picker_ul_transition('y',get_current('y'));
  			is_click = false;
  		}
  	})
  
  	//TOGGLE CALENDAR
  	.on(ui_event.i,picker_node_el+' ul.pick.pick-d li',function(){
  		is_click = true;
  	})
  	.on(ui_event.e,picker_node_el+' ul.pick.pick-d li',function(){
  		if(is_click) {
  			picker_large_onoff();
  			is_click = false;
  		}
  	})
  
  	//TOGGLE TRANSLATE MODE
  	.on(ui_event.i,picker_node_el+' ul.pick.pick-l li',function(){
  		is_click = true;
  	})
  	.on(ui_event.e,picker_node_el+' ul.pick.pick-l li',function(){
  		if(is_click) {
  			picker_translate_onoff();
  			picker_translate($(this).val());
  			is_click = false;
  		}
  	})
  
  	//MOUSEDOWN ON UL
  	.on(ui_event.i,picker_node_el+' ul.pick',function(e){
  		pick_dragged = $(this);
  		if(pick_dragged) {
  			var
  				k = pick_dragged.data('k');
  			pick_drag_offset = is_touch() ? e.originalEvent.touches[0].pageY : e.pageY;
  			pick_drag_temp = get_current(k);
  		}
  	})
  
  	//MOUSEMOVE ON UL
  	.on(ui_event.m,function(e){
  
  		is_click = false;
  
  		if(pick_dragged) {
  			e.preventDefault();
  			var
  				k = pick_dragged.data('k');
  				o = is_touch() ? e.originalEvent.touches[0].pageY : e.pageY;
  			o = pick_drag_offset - o;
  			o = Math.round(o * .026);
  			i = pick_drag_temp + o;
  			var
  				int = get_clear(k,i);
  			if(int!=pickers[picker.id].key[k].current)
  				picker_values_increase(k,int);
  
  			picker_ctrl = true;
  		}
  	})
  
  	//MOUSEUP ON UL
  	.on(ui_event.e,function(e){
  		if( pick_dragged )
  			pick_dragged = null,
  			pick_drag_offset = null,
  			pick_drag_temp = null;
  		if(picker)
  			picker_set();
  	})
  
  	//CLICK SUBMIT
  	.on(ui_event.i,picker_node_el+' .pick-submit',function(){
  		picker_hide();
  	});
  
  	$(window).resize(function(){
  		if(picker) {
  			picker_offset();
  			is_fx_mobile();
  		}
  	});
  
  	$.fn.dateDropper = function(options) {
  		return $(this).each(function(){
  			if($(this).is('input')&&!$(this).hasClass('picker-input')) {
  
  				var
  					input = $(this),
  					id = 'datedropper-' + Object.keys(pickers).length;
  
  				input
  				.attr('data-id',id)
  				.addClass('picker-input')
  				.prop({
  					'type':'text',
  					'readonly' : true
  				});
  
  				var
  					picker_default_date = (input.data('default-date')&&is_date(input.data('default-date'))) ? input.data('default-date') : null,
  					picker_disabled_days = (input.data('disabled-days')) ? input.data('disabled-days').split(',') : null,
  					picker_format = input.data('format') || 'm/d/Y',
  					picker_fx = (input.data('fx')===false) ? input.data('fx') : true,
  					picker_fx_class = (input.data('fx')===false) ? '' : 'picker-fxs',
  					picker_fx_mobile = (input.data('fx-mobile')===false) ? input.data('fx-mobile') : true,
  					picker_init_set = (input.data('init-set')===false) ? false : true,
  					picker_lang = (input.data('lang')&&(input.data('lang') in i18n)) ? input.data('lang') : 'en',
  					picker_large = (input.data('large-mode')===true) ? true : false,
  					picker_large_class = (input.data('large-default')===true && picker_large===true) ? 'picker-lg' : '',
  					picker_lock = (input.data('lock')=='from'||input.data('lock')=='to') ? input.data('lock') : false,
  					picker_jump = (input.data('jump')&&is_int(input.data('jump'))) ? input.data('jump') : 10,
  					picker_max_year = (input.data('max-year')&&is_int(input.data('max-year'))) ? input.data('max-year') : new Date().getFullYear(),
  					picker_min_year = (input.data('min-year')&&is_int(input.data('min-year'))) ? input.data('min-year') : 1970,
  
  					picker_modal = (input.data('modal')===true) ? 'picker-modal' : '',
  					picker_theme = input.data('theme') || 'primary',
  					picker_translate_mode = (input.data('translate-mode')===true) ? true : false;
  
  				if(picker_disabled_days) {
  					$.each(picker_disabled_days, function( index, value ) {
  						if(value&&is_date(value))
  							picker_disabled_days[index] = get_unix(value);
  					});
  				}
  
  				pickers[id] = {
  					disabledays : picker_disabled_days,
  					format : picker_format,
  					fx : picker_fx,
  					fxmobile : picker_fx_mobile,
  					lang : picker_lang,
  					large : picker_large,
  					lock : picker_lock,
  					jump : picker_jump,
  					key : {
  						m : {
  							min : 1,
  							max : 12,
  							current : 1,
  							today : (new Date().getMonth()+1)
  						},
  						d : {
  							min : 1,
  							max : 31,
  							current : 1,
  							today : new Date().getDate()
  						},
  						y : {
  							min : picker_min_year,
  							max : picker_max_year,
  							current : picker_min_year,
  							today : new Date().getFullYear()
  						},
  						l : {
  							min : 0,
  							max : Object.keys(i18n).length-1,
  							current : 0,
  							today : 0
  						}
  					},
  					translate : picker_translate_mode
  				};
  
  				if(picker_default_date) {
  
  					var regex = /\d+/g;
  					var string = picker_default_date;
  					var matches = string.match(regex);
  
  					$.each(matches, function( index, value ) {
  						matches[index] = parseInt(value);
  					});
  
  					pickers[id].key.m.today = (matches[0]&&matches[0]<=12) ? matches[0] : pickers[id].key.m.today;
  					pickers[id].key.d.today = (matches[1]&&matches[1]<=31) ? matches[1] : pickers[id].key.d.today;
  					pickers[id].key.y.today = (matches[2]) ? matches[2] : pickers[id].key.y.today;
  
  					if(pickers[id].key.y.today>pickers[id].key.y.max)
  						pickers[id].key.y.max = pickers[id].key.y.today;
  					if(pickers[id].key.y.today<pickers[id].key.y.min)
  						pickers[id].key.y.min = pickers[id].key.y.today;
  
  				}
  
  				$('<div>', {
  					class: 'datedropper ' + picker_modal + ' ' + picker_theme + ' ' + picker_fx_class + ' ' + picker_large_class,
  					id: id,
  					html: $('<div>', {
  						class: 'picker'
  					})
  				})
  				.appendTo('body');
  
  				picker = {
  					id : id,
  					input : input,
  					element : $('#' + id)
  				};
  
  				for( var k in pickers[id].key ) {
  					$('<ul>', {
  						class: 'pick pick-' + k,
  						'data-k' : k
  					})
  					.appendTo(get_picker_els('.picker'));
  					picker_render_ul(k);
  				}
  
  				if(pickers[id].large) {
  
  					//calendar
  					$('<div>', {
  						class: 'pick-lg'
  					})
  					.insertBefore(get_picker_els('.pick-d'));
  
  					$('<ul class="pick-lg-h"></ul><ul class="pick-lg-b"></ul>')
  					.appendTo(get_picker_els('.pick-lg'));
  
  					var
  						picker_day_offset = get_days_array();
  
  					for(var i = 0; i < 7 ; i++) {
  						$('<li>', {
  							html: i18n[pickers[picker.id].lang].weekdays.short[picker_day_offset[i]]
  						})
  						.appendTo(get_picker_els('.pick-lg .pick-lg-h'))
  					}
  					for(var i = 0; i < 42 ; i++) {
  						$('<li>')
  						.appendTo(get_picker_els('.pick-lg .pick-lg-b'))
  					}
  				}
  
  				//buttons
  				$('<div>', {
  					class: 'pick-btns'
  				})
  				.appendTo(get_picker_els('.picker'));
  
  				$('<div>', {
  					class: 'pick-submit'
  				})
  				.appendTo(get_picker_els('.pick-btns'));
  
  				if(pickers[picker.id].translate) {
  					$('<div>', {
  						class: 'pick-btn pick-btn-lng'
  					})
  					.appendTo(get_picker_els('.pick-btns'));
  				}
  				if(pickers[picker.id].large) {
  					$('<div>', {
  						class: 'pick-btn pick-btn-sz'
  					})
  					.appendTo(get_picker_els('.pick-btns'));
  				}
  
  				if(picker_format=='Y'||picker_format=='m') {
  					get_picker_els('.pick-d,.pick-btn-sz').hide();
  					picker.element.addClass('picker-tiny');
  					if(picker_format=='Y')
  						get_picker_els('.pick-m,.pick-btn-lng').hide();
  					if(picker_format=='m')
  						get_picker_els('.pick-y').hide();
  				}
  
  				if(picker_init_set) {
  					picker_ctrl = true;
  					input_change_value();
  				}
  
  				picker = null;
  
  			}
  
  		})
  		.focus(function(e){
  
  			e.preventDefault();
  			$(this).blur();
  
  			if(picker)
  				picker_hide();
  
  			picker = {
  				id : $(this).data('id'),
  				input : $(this),
  				element : $('#'+$(this).data('id'))
  			};
  
  			is_fx_mobile();
  			picker_offset();
  			picker_set();
  			picker_show();
  
  			if(picker.element.hasClass('picker-modal'))
  				$('body').append('<div class="picker-modal-overlay"></div>')
  
  		});
  	};
  }(jQuery));
  
  /* ====================================================================================================
    Time Dropper V1.0
  ==================================================================================================== */
  (function($) {
      $.fn.timeDropper = function(options, callbackFnk) {
          return $(this).each(function() {
  
              var
                  _td_input = $(this),
                  _td_input_on = false,
                  _td_mobile = false,
                  _td_num = function(n) {
                      return n < 10 ? '0' + n : n
                  },
                  _td_id = $('.td-clock').length,
                  _td_alert,
                  _td_event = null,
                  _td_options = $.extend({
  
                      format: 'h:mm a',
                      autoswitch: false,
                      meridians: false,
                      mousewheel: false,
                      setCurrentTime: true,
                      init_animation: "fadein",
                      primaryColor: "#1977CC",
                      borderColor: "#1977CC",
                      backgroundColor: "#FFF",
                      textColor: '#555'
  
                  }, options);
  
              var _td_color = function(col, amt) {
  
                  var usePound = false;
  
                  if (col[0] == "#") {
                      col = col.slice(1);
                      usePound = true;
                  }
  
                  var num = parseInt(col, 16);
  
                  var r = (num >> 16) + amt;
  
                  if (r > 255) r = 255;
                  else if (r < 0) r = 0;
  
                  var b = ((num >> 8) & 0x00FF) + amt;
  
                  if (b > 255) b = 255;
                  else if (b < 0) b = 0;
  
                  var g = (num & 0x0000FF) + amt;
  
                  if (g > 255) g = 255;
                  else if (g < 0) g = 0;
  
                  return (usePound ? "#" : "") + (g | (b << 8) | (r << 16)).toString(16);
  
              };
  
              _td_input.prop({
                  'readonly': true
              }).addClass('td-input');
  
              $('body').append('<div class="td-wrap td-n2" id="td-clock-' + _td_id + '"><div class="td-overlay"></div><div class="td-clock td-init"><div class="td-deg td-n"><div class="td-select"><svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 100 35.4" enable-background="new 0 0 100 35.4" xml:space="preserve"><g><path fill="none" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M98.1,33C85.4,21.5,68.5,14.5,50,14.5S14.6,21.5,1.9,33"/><line fill="none" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="1.9" y1="33" x2="1.9" y2="28.6"/><line fill="none" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="1.9" y1="33" x2="6.3" y2="33"/><line fill="none" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="98.1" y1="33" x2="93.7" y2="33"/><line fill="none" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" x1="98.1" y1="33" x2="98.1" y2="28.6"/></g></svg></div></div><div class="td-medirian"><span class="td-icon-am td-n">AM</span><span class="td-icon-pm td-n">PM</span></div><div class="td-lancette"><div></div><div></div></div><div class="td-time"><span class="on"></span>:<span></span></div></div></div>');
  
              $('head').append('<style>#td-clock-' + _td_id + ' .td-clock {color:' + _td_options.textColor + ';background: ' + _td_options.backgroundColor + '; box-shadow: 0 0 0 1px ' + _td_options.borderColor + ',0 0 0 8px rgba(0, 0, 0, 0.05); } #td-clock-' + _td_id + ' .td-clock .td-time span.on { color:' + _td_options.primaryColor + '} #td-clock-' + _td_id + ' .td-clock:before { border-color: ' + _td_options.borderColor + '} #td-clock-' + _td_id + ' .td-select:after { box-shadow: 0 0 0 1px ' + _td_options.borderColor + ' } #td-clock-' + _td_id + ' .td-clock:before,#td-clock-' + _td_id + ' .td-select:after {background: ' + _td_options.backgroundColor + ';} #td-clock-' + _td_id + ' .td-lancette {border: 2px solid ' + _td_options.primaryColor + '; opacity:0.1}#td-clock-' + _td_id + ' .td-lancette div:after { background: ' + _td_options.primaryColor + ';} #td-clock-' + _td_id + ' .td-bulletpoint div:after { background:' + _td_options.primaryColor + '; opacity:0.1}</style>');
  
  
  
              var
                  _td_container = $('#td-clock-' + _td_id),
                  _td_overlay = _td_container.find('.td-overlay'),
                  _td_c = _td_container.find('.td-clock');
  
  
              _td_c.find('svg').attr('style', "stroke:" + _td_options.borderColor);
  
  
              var
                  _td_init_deg = -1,
                  _td_event_deg = 0,
                  _td_wheel_deg = 0,
                  _td_h,
                  _td_m,
                  _td_define_deg = function() {
  
                      var
                          o = _td_c.find('.td-time span.on'),
                          v = parseInt(o.attr('data-id'));
  
                      if (o.index() == 0) deg = Math.round((v * 360 / 23));
                      else deg = Math.round((v * 360 / 59));
  
                      _td_init_deg = -1;
                      _td_event_deg = deg;
                      _td_wheel_deg = deg;
  
                  },
                  _td_rotation = function(deg) {
  
                      var t = _td_c.find('.td-time span.on');
  
                      var value = t.attr('data-id');
  
                      if (!value) value = 0;
  
                      var h = Math.round((deg * 23 / 360));
                      var m = Math.round((deg * 59 / 360));
  
                      if (t.index() == 0) {
  
                          t.attr('data-id', _td_num(h));
  
                          if (_td_options.meridians) {
  
                              if (h >= 12 && h < 24) {
                                  _td_c.find('.td-icon-pm').addClass('td-on');
                                  _td_c.find('.td-icon-am').removeClass('td-on');
                              } else {
  
                                  _td_c.find('.td-icon-am').addClass('td-on');
                                  _td_c.find('.td-icon-pm').removeClass('td-on');
                              }
  
                              if (h > 12) h = h - 12;
                              if (h == 0) h = 12;
  
                          }
  
                          t.text(_td_num(h));
  
                      } else {
                          t.attr('data-id', _td_num(m)).text(_td_num(m));
                      }
  
                      _td_wheel_deg = deg;
                      _td_c.find('.td-deg').css('transform', 'rotate(' + (deg) + 'deg)');
  
                      if (t.index() == 0) {
                          var c = Math.round((h * 360 / 12));
                          _td_c.find('.td-lancette div:last').css('transform', 'rotate(' + (c) + 'deg)');
                      } else {
                          _td_c.find('.td-lancette div:first').css('transform', 'rotate(' + (deg) + 'deg)');
                      }
  
                      var
                          _td_h = _td_c.find('.td-time span:first').attr('data-id'),
                          _td_m = _td_c.find('.td-time span:last').attr('data-id');
  
                      if (Math.round(_td_h) >= 12 && Math.round(_td_h) < 24) {
                          var
                              h = Math.round(_td_h) - 12,
                              a = 'pm',
                              A = 'PM';
                      } else {
                          var
                              h = Math.round(_td_h),
                              a = 'am',
                              A = 'AM';
                      }
  
                      if (h == 0) h = 12;
  
                      var
                          str =
                          _td_options.format
                          .replace(/\b(H)\b/g, Math.round(_td_h))
                          .replace(/\b(h)\b/g, Math.round(h))
                          .replace(/\b(m)\b/g, Math.round(_td_m))
                          .replace(/\b(HH)\b/g, _td_num(Math.round(_td_h)))
                          .replace(/\b(hh)\b/g, _td_num(Math.round(h)))
                          .replace(/\b(mm)\b/g, _td_num(Math.round(_td_m)))
                          .replace(/\b(a)\b/g, a)
                          .replace(/\b(A)\b/g, A);
  
                      _td_input.val(str);
  
  
                  };
  
  
              if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
                  _td_mobile = true;
              }
  
              _td_c.find('.td-time span').on('click', function(e) {
  
                  var o = $(this);
  
                  _td_c.find('.td-time span').removeClass('on');
                  o.addClass('on');
  
                  var v = parseInt(o.attr('data-id'));
  
                  if (o.index() == 0) deg = Math.round((v * 360 / 23));
                  else deg = Math.round((v * 360 / 59));
  
                  _td_init_deg = -1;
                  _td_event_deg = deg;
                  _td_wheel_deg = deg;
                  _td_rotation(deg);
  
              });
  
              _td_c.find('.td-deg').on('touchstart mousedown', function(e) {
  
                  _td_define_deg();
  
                  e.preventDefault();
  
                  clearInterval(_td_alert);
  
                  _td_c.find('.td-deg').removeClass('td-n');
                  _td_c.find('.td-select').removeClass('td-rubber');
  
                  _td_input_on = true;
  
                  var offset = _td_c.offset();
                  var center = {
                      y: offset.top + _td_c.height() / 2,
                      x: offset.left + _td_c.width() / 2
                  };
  
                  var a, b, deg, tmp, rad2deg = 180 / Math.PI;
  
                  _td_c.removeClass('td-rubber');
  
                  $(window).on('touchmove mousemove', function(e) {
  
                      if (_td_input_on == true) {
  
                          if (_td_mobile) move = e.originalEvent.touches[0];
                          else move = e;
  
                          a = center.y - move.pageY;
                          b = center.x - move.pageX;
                          deg = Math.atan2(a, b) * rad2deg;
  
                          if (deg < 0)
                              deg = 360 + deg;
  
                          if (_td_init_deg == -1)
                              _td_init_deg = deg;
  
                          tmp = Math.floor((deg - _td_init_deg) + _td_event_deg);
  
                          if (tmp < 0) tmp = 360 + tmp;
                          else if (tmp > 360) tmp = tmp % 360;
  
                          _td_rotation(tmp);
  
                      }
  
                  });
  
              });
  
              if (_td_options.mousewheel) {
  
                  _td_c.on('mousewheel', function(e) {
  
                      e.preventDefault();
  
                      _td_c.find('.td-deg').removeClass('td-n');
  
                      if (e.originalEvent.wheelDelta > 0) {
                          if (_td_wheel_deg <= 360) {
                              if (e.originalEvent.wheelDelta <= 120) _td_wheel_deg++
                                  else if (e.originalEvent.wheelDelta > 120) _td_wheel_deg = _td_wheel_deg + 20;
                              if (_td_wheel_deg > 360) _td_wheel_deg = 0;
                          }
                      } else {
                          if (_td_wheel_deg >= 0) {
                              if (e.originalEvent.wheelDelta >= -120) _td_wheel_deg--
                                  else if (e.originalEvent.wheelDelta < -120) _td_wheel_deg = _td_wheel_deg - 20;
                              if (_td_wheel_deg < 0) _td_wheel_deg = 360;
                          }
                      }
  
                      _td_init_deg = -1;
                      _td_event_deg = _td_wheel_deg;
                      _td_rotation(_td_wheel_deg);
  
                  });
  
              }
  
              $(document).on('touchend mouseup', function() {
  
                  if (_td_input_on) {
  
                      _td_input_on = false;
  
                      if (_td_options.autoswitch) {
                          _td_c.find('.td-time span').toggleClass('on');
                          _td_c.find('.td-time span.on').click();
                      }
  
                      _td_c.find('.td-deg').addClass('td-n');
                      _td_c.find('.td-select').addClass('td-rubber');
  
                  }
  
              });
  
              var _td_init = function(value) {
  
                  var
                      d = new Date(),
                      _td_span_h = _td_c.find('.td-time span:first'),
                      _td_span_m = _td_c.find('.td-time span:last'),
                      h,
                      m;
  
                  if (_td_input.val().length && !_td_options.setCurrentTime) {
  
                      var reg = /\d+/g,
                          am;
                      var st = _td_input.val().split(':');
  
                      if (st) {
  
                          h = st[0].match(reg);
                          m = st[1].match(reg);
                          if (_td_input.val().indexOf("am") != -1 || _td_input.val().indexOf("AM") != -1 || _td_input.val().indexOf("pm") != -1 || _td_input.val().indexOf("PM") != -1) {
                              if (_td_input.val().indexOf("am") != -1 || _td_input.val().indexOf("AM") != -1) am = true;
                              else am = false;
  
                              if (!am) {
                                  if (h < 13) {
                                      h = parseInt(h) + 12;
                                      if (h == 24) h = 0;
                                  }
                              } else if (h == 12) h = 0;
                          } else if (h == 24) h = 0;
                      } else {
  
                          if (!parseInt(_td_span_h.text())) h = _td_num(d.getHours());
                          else h = _td_num(_td_span_h.text());
                          if (!parseInt(_td_span_m.text())) m = _td_num(d.getMinutes());
                          else m = _td_num(_td_span_m.text());
  
                      }
  
                  } else {
  
                      if (!parseInt(_td_span_h.text())) h = _td_num(d.getHours());
                      else h = _td_num(_td_span_h.text());
                      if (!parseInt(_td_span_m.text())) m = _td_num(d.getMinutes());
                      else m = _td_num(_td_span_m.text());
  
                  }
  
                  _td_span_h.attr('data-id', h).text(h);
                  _td_span_m.attr('data-id', m).text(m);
  
                  _td_event_deg = Math.round((h * 360 / 23));
  
                  _td_c.find('.td-lancette div:first').css('transform', 'rotate(' + Math.round((m * 360 / 59)) + 'deg)');
  
                  _td_rotation(_td_event_deg);
                  _td_wheel_deg = _td_event_deg;
                  _td_init_deg = -1;
  
  
              }
  
              _td_init();
  
              _td_input.focus(function(e) {
                  e.preventDefault();
                  _td_input.blur();
              });
  
              _td_input.click(function(e) {
  
                  clearInterval(_td_event);
  
                  _td_container.removeClass('td-fadeout');
                  _td_container.addClass('td-show').addClass('td-' + _td_options.init_animation);
                  _td_c.css({
                      'top': (_td_input.offset().top + (_td_input.outerHeight() - 8)),
                      'left': (_td_input.offset().left + (_td_input.outerWidth() / 2)) - (_td_c.outerWidth() / 2)
                  });
  
                  if (_td_c.hasClass('td-init')) {
  
                      _td_alert = setInterval(function() {
                          _td_c.find('.td-select').addClass('td-alert');
                          setTimeout(function() {
                              _td_c.find('.td-select').removeClass('td-alert');
                          }, 1000);
                      }, 2000);
  
                      _td_c.removeClass('td-init');
  
                  }
  
              });
              _td_overlay.click(function() {
  
                  _td_container.addClass('td-fadeout').removeClass('td-' + _td_options.init_animation);
                  _td_event = setTimeout(function() {
                      _td_container.removeClass('td-show')
                  }, 300);
  
              });
              $(window).on('resize', function() {
  
                  _td_define_deg();
                  _td_c.css({
                      'top': (_td_input.offset().top + (_td_input.outerHeight() - 8)),
                      'left': (_td_input.offset().left + (_td_input.outerWidth() / 2)) - (_td_c.outerWidth() / 2)
                  });
              });
  
          });
      };
  }(jQuery));
  
  /* ====================================================================================================
    Owl Carousel
  ==================================================================================================== */
  /**
   * Owl Carousel v2.3.4
   * Copyright 2013-2018 David Deutsch
   * Licensed under: SEE LICENSE IN https://github.com/OwlCarousel2/OwlCarousel2/blob/master/LICENSE
   */
  /**
   * Owl carousel
   * @version 2.3.4
   * @author Bartosz Wojciechowski
   * @author David Deutsch
   * @license The MIT License (MIT)
   * @todo Lazy Load Icon
   * @todo prevent animationend bubling
   * @todo itemsScaleUp
   * @todo Test Zepto
   * @todo stagePadding calculate wrong active classes
   */
  ;(function($, window, document, undefined) {
  
    /**
     * Creates a carousel.
     * @class The Owl Carousel.
     * @public
     * @param {HTMLElement|jQuery} element - The element to create the carousel for.
     * @param {Object} [options] - The options
     */
    function Owl(element, options) {
  
      /**
       * Current settings for the carousel.
       * @public
       */
      this.settings = null;
  
      /**
       * Current options set by the caller including defaults.
       * @public
       */
      this.options = $.extend({}, Owl.Defaults, options);
  
      /**
       * Plugin element.
       * @public
       */
      this.$element = $(element);
  
      /**
       * Proxied event handlers.
       * @protected
       */
      this._handlers = {};
  
      /**
       * References to the running plugins of this carousel.
       * @protected
       */
      this._plugins = {};
  
      /**
       * Currently suppressed events to prevent them from being retriggered.
       * @protected
       */
      this._supress = {};
  
      /**
       * Absolute current position.
       * @protected
       */
      this._current = null;
  
      /**
       * Animation speed in milliseconds.
       * @protected
       */
      this._speed = null;
  
      /**
       * Coordinates of all items in pixel.
       * @todo The name of this member is missleading.
       * @protected
       */
      this._coordinates = [];
  
      /**
       * Current breakpoint.
       * @todo Real media queries would be nice.
       * @protected
       */
      this._breakpoint = null;
  
      /**
       * Current width of the plugin element.
       */
      this._width = null;
  
      /**
       * All real items.
       * @protected
       */
      this._items = [];
  
      /**
       * All cloned items.
       * @protected
       */
      this._clones = [];
  
      /**
       * Merge values of all items.
       * @todo Maybe this could be part of a plugin.
       * @protected
       */
      this._mergers = [];
  
      /**
       * Widths of all items.
       */
      this._widths = [];
  
      /**
       * Invalidated parts within the update process.
       * @protected
       */
      this._invalidated = {};
  
      /**
       * Ordered list of workers for the update process.
       * @protected
       */
      this._pipe = [];
  
      /**
       * Current state information for the drag operation.
       * @todo #261
       * @protected
       */
      this._drag = {
        time: null,
        target: null,
        pointer: null,
        stage: {
          start: null,
          current: null
        },
        direction: null
      };
  
      /**
       * Current state information and their tags.
       * @type {Object}
       * @protected
       */
      this._states = {
        current: {},
        tags: {
          'initializing': [ 'busy' ],
          'animating': [ 'busy' ],
          'dragging': [ 'interacting' ]
        }
      };
  
      $.each([ 'onResize', 'onThrottledResize' ], $.proxy(function(i, handler) {
        this._handlers[handler] = $.proxy(this[handler], this);
      }, this));
  
      $.each(Owl.Plugins, $.proxy(function(key, plugin) {
        this._plugins[key.charAt(0).toLowerCase() + key.slice(1)]
          = new plugin(this);
      }, this));
  
      $.each(Owl.Workers, $.proxy(function(priority, worker) {
        this._pipe.push({
          'filter': worker.filter,
          'run': $.proxy(worker.run, this)
        });
      }, this));
  
      this.setup();
      this.initialize();
    }
  
    /**
     * Default options for the carousel.
     * @public
     */
    Owl.Defaults = {
      items: 3,
      loop: false,
      center: false,
      rewind: false,
      checkVisibility: true,
  
      mouseDrag: true,
      touchDrag: true,
      pullDrag: true,
      freeDrag: false,
  
      margin: 0,
      stagePadding: 0,
  
      merge: false,
      mergeFit: true,
      autoWidth: false,
  
      startPosition: 0,
      rtl: false,
  
      smartSpeed: 250,
      fluidSpeed: false,
      dragEndSpeed: false,
  
      responsive: {},
      responsiveRefreshRate: 200,
      responsiveBaseElement: window,
  
      fallbackEasing: 'swing',
      slideTransition: '',
  
      info: false,
  
      nestedItemSelector: false,
      itemElement: 'div',
      stageElement: 'div',
  
      refreshClass: 'owl-refresh',
      loadedClass: 'owl-loaded',
      loadingClass: 'owl-loading',
      rtlClass: 'owl-rtl',
      responsiveClass: 'owl-responsive',
      dragClass: 'owl-drag',
      itemClass: 'owl-item',
      stageClass: 'owl-stage',
      stageOuterClass: 'owl-stage-outer',
      grabClass: 'owl-grab'
    };
  
    /**
     * Enumeration for width.
     * @public
     * @readonly
     * @enum {String}
     */
    Owl.Width = {
      Default: 'default',
      Inner: 'inner',
      Outer: 'outer'
    };
  
    /**
     * Enumeration for types.
     * @public
     * @readonly
     * @enum {String}
     */
    Owl.Type = {
      Event: 'event',
      State: 'state'
    };
  
    /**
     * Contains all registered plugins.
     * @public
     */
    Owl.Plugins = {};
  
    /**
     * List of workers involved in the update process.
     */
    Owl.Workers = [ {
      filter: [ 'width', 'settings' ],
      run: function() {
        this._width = this.$element.width();
      }
    }, {
      filter: [ 'width', 'items', 'settings' ],
      run: function(cache) {
        cache.current = this._items && this._items[this.relative(this._current)];
      }
    }, {
      filter: [ 'items', 'settings' ],
      run: function() {
        this.$stage.children('.cloned').remove();
      }
    }, {
      filter: [ 'width', 'items', 'settings' ],
      run: function(cache) {
        var margin = this.settings.margin || '',
          grid = !this.settings.autoWidth,
          rtl = this.settings.rtl,
          css = {
            'width': 'auto',
            'margin-left': rtl ? margin : '',
            'margin-right': rtl ? '' : margin
          };
  
        !grid && this.$stage.children().css(css);
  
        cache.css = css;
      }
    }, {
      filter: [ 'width', 'items', 'settings' ],
      run: function(cache) {
        var width = (this.width() / this.settings.items).toFixed(3) - this.settings.margin,
          merge = null,
          iterator = this._items.length,
          grid = !this.settings.autoWidth,
          widths = [];
  
        cache.items = {
          merge: false,
          width: width
        };
  
        while (iterator--) {
          merge = this._mergers[iterator];
          merge = this.settings.mergeFit && Math.min(merge, this.settings.items) || merge;
  
          cache.items.merge = merge > 1 || cache.items.merge;
  
          widths[iterator] = !grid ? this._items[iterator].width() : width * merge;
        }
  
        this._widths = widths;
      }
    }, {
      filter: [ 'items', 'settings' ],
      run: function() {
        var clones = [],
          items = this._items,
          settings = this.settings,
          // TODO: Should be computed from number of min width items in stage
          view = Math.max(settings.items * 2, 4),
          size = Math.ceil(items.length / 2) * 2,
          repeat = settings.loop && items.length ? settings.rewind ? view : Math.max(view, size) : 0,
          append = '',
          prepend = '';
  
        repeat /= 2;
  
        while (repeat > 0) {
          // Switch to only using appended clones
          clones.push(this.normalize(clones.length / 2, true));
          append = append + items[clones[clones.length - 1]][0].outerHTML;
          clones.push(this.normalize(items.length - 1 - (clones.length - 1) / 2, true));
          prepend = items[clones[clones.length - 1]][0].outerHTML + prepend;
          repeat -= 1;
        }
  
        this._clones = clones;
  
        $(append).addClass('cloned').appendTo(this.$stage);
        $(prepend).addClass('cloned').prependTo(this.$stage);
      }
    }, {
      filter: [ 'width', 'items', 'settings' ],
      run: function() {
        var rtl = this.settings.rtl ? 1 : -1,
          size = this._clones.length + this._items.length,
          iterator = -1,
          previous = 0,
          current = 0,
          coordinates = [];
  
        while (++iterator < size) {
          previous = coordinates[iterator - 1] || 0;
          current = this._widths[this.relative(iterator)] + this.settings.margin;
          coordinates.push(previous + current * rtl);
        }
  
        this._coordinates = coordinates;
      }
    }, {
      filter: [ 'width', 'items', 'settings' ],
      run: function() {
        var padding = this.settings.stagePadding,
          coordinates = this._coordinates,
          css = {
            'width': Math.ceil(Math.abs(coordinates[coordinates.length - 1])) + padding * 2,
            'padding-left': padding || '',
            'padding-right': padding || ''
          };
  
        this.$stage.css(css);
      }
    }, {
      filter: [ 'width', 'items', 'settings' ],
      run: function(cache) {
        var iterator = this._coordinates.length,
          grid = !this.settings.autoWidth,
          items = this.$stage.children();
  
        if (grid && cache.items.merge) {
          while (iterator--) {
            cache.css.width = this._widths[this.relative(iterator)];
            items.eq(iterator).css(cache.css);
          }
        } else if (grid) {
          cache.css.width = cache.items.width;
          items.css(cache.css);
        }
      }
    }, {
      filter: [ 'items' ],
      run: function() {
        this._coordinates.length < 1 && this.$stage.removeAttr('style');
      }
    }, {
      filter: [ 'width', 'items', 'settings' ],
      run: function(cache) {
        cache.current = cache.current ? this.$stage.children().index(cache.current) : 0;
        cache.current = Math.max(this.minimum(), Math.min(this.maximum(), cache.current));
        this.reset(cache.current);
      }
    }, {
      filter: [ 'position' ],
      run: function() {
        this.animate(this.coordinates(this._current));
      }
    }, {
      filter: [ 'width', 'position', 'items', 'settings' ],
      run: function() {
        var rtl = this.settings.rtl ? 1 : -1,
          padding = this.settings.stagePadding * 2,
          begin = this.coordinates(this.current()) + padding,
          end = begin + this.width() * rtl,
          inner, outer, matches = [], i, n;
  
        for (i = 0, n = this._coordinates.length; i < n; i++) {
          inner = this._coordinates[i - 1] || 0;
          outer = Math.abs(this._coordinates[i]) + padding * rtl;
  
          if ((this.op(inner, '<=', begin) && (this.op(inner, '>', end)))
            || (this.op(outer, '<', begin) && this.op(outer, '>', end))) {
            matches.push(i);
          }
        }
  
        this.$stage.children('.active').removeClass('active');
        this.$stage.children(':eq(' + matches.join('), :eq(') + ')').addClass('active');
  
        this.$stage.children('.center').removeClass('center');
        if (this.settings.center) {
          this.$stage.children().eq(this.current()).addClass('center');
        }
      }
    } ];
  
    /**
     * Create the stage DOM element
     */
    Owl.prototype.initializeStage = function() {
      this.$stage = this.$element.find('.' + this.settings.stageClass);
  
      // if the stage is already in the DOM, grab it and skip stage initialization
      if (this.$stage.length) {
        return;
      }
  
      this.$element.addClass(this.options.loadingClass);
  
      // create stage
      this.$stage = $('<' + this.settings.stageElement + '>', {
        "class": this.settings.stageClass
      }).wrap( $( '<div/>', {
        "class": this.settings.stageOuterClass
      }));
  
      // append stage
      this.$element.append(this.$stage.parent());
    };
  
    /**
     * Create item DOM elements
     */
    Owl.prototype.initializeItems = function() {
      var $items = this.$element.find('.owl-item');
  
      // if the items are already in the DOM, grab them and skip item initialization
      if ($items.length) {
        this._items = $items.get().map(function(item) {
          return $(item);
        });
  
        this._mergers = this._items.map(function() {
          return 1;
        });
  
        this.refresh();
  
        return;
      }
  
      // append content
      this.replace(this.$element.children().not(this.$stage.parent()));
  
      // check visibility
      if (this.isVisible()) {
        // update view
        this.refresh();
      } else {
        // invalidate width
        this.invalidate('width');
      }
  
      this.$element
        .removeClass(this.options.loadingClass)
        .addClass(this.options.loadedClass);
    };
  
    /**
     * Initializes the carousel.
     * @protected
     */
    Owl.prototype.initialize = function() {
      this.enter('initializing');
      this.trigger('initialize');
  
      this.$element.toggleClass(this.settings.rtlClass, this.settings.rtl);
  
      if (this.settings.autoWidth && !this.is('pre-loading')) {
        var imgs, nestedSelector, width;
        imgs = this.$element.find('img');
        nestedSelector = this.settings.nestedItemSelector ? '.' + this.settings.nestedItemSelector : undefined;
        width = this.$element.children(nestedSelector).width();
  
        if (imgs.length && width <= 0) {
          this.preloadAutoWidthImages(imgs);
        }
      }
  
      this.initializeStage();
      this.initializeItems();
  
      // register event handlers
      this.registerEventHandlers();
  
      this.leave('initializing');
      this.trigger('initialized');
    };
  
    /**
     * @returns {Boolean} visibility of $element
     *                    if you know the carousel will always be visible you can set `checkVisibility` to `false` to
     *                    prevent the expensive browser layout forced reflow the $element.is(':visible') does
     */
    Owl.prototype.isVisible = function() {
      return this.settings.checkVisibility
        ? this.$element.is(':visible')
        : true;
    };
  
    /**
     * Setups the current settings.
     * @todo Remove responsive classes. Why should adaptive designs be brought into IE8?
     * @todo Support for media queries by using `matchMedia` would be nice.
     * @public
     */
    Owl.prototype.setup = function() {
      var viewport = this.viewport(),
        overwrites = this.options.responsive,
        match = -1,
        settings = null;
  
      if (!overwrites) {
        settings = $.extend({}, this.options);
      } else {
        $.each(overwrites, function(breakpoint) {
          if (breakpoint <= viewport && breakpoint > match) {
            match = Number(breakpoint);
          }
        });
  
        settings = $.extend({}, this.options, overwrites[match]);
        if (typeof settings.stagePadding === 'function') {
          settings.stagePadding = settings.stagePadding();
        }
        delete settings.responsive;
  
        // responsive class
        if (settings.responsiveClass) {
          this.$element.attr('class',
            this.$element.attr('class').replace(new RegExp('(' + this.options.responsiveClass + '-)\\S+\\s', 'g'), '$1' + match)
          );
        }
      }
  
      this.trigger('change', { property: { name: 'settings', value: settings } });
      this._breakpoint = match;
      this.settings = settings;
      this.invalidate('settings');
      this.trigger('changed', { property: { name: 'settings', value: this.settings } });
    };
  
    /**
     * Updates option logic if necessery.
     * @protected
     */
    Owl.prototype.optionsLogic = function() {
      if (this.settings.autoWidth) {
        this.settings.stagePadding = false;
        this.settings.merge = false;
      }
    };
  
    /**
     * Prepares an item before add.
     * @todo Rename event parameter `content` to `item`.
     * @protected
     * @returns {jQuery|HTMLElement} - The item container.
     */
    Owl.prototype.prepare = function(item) {
      var event = this.trigger('prepare', { content: item });
  
      if (!event.data) {
        event.data = $('<' + this.settings.itemElement + '/>')
          .addClass(this.options.itemClass).append(item)
      }
  
      this.trigger('prepared', { content: event.data });
  
      return event.data;
    };
  
    /**
     * Updates the view.
     * @public
     */
    Owl.prototype.update = function() {
      var i = 0,
        n = this._pipe.length,
        filter = $.proxy(function(p) { return this[p] }, this._invalidated),
        cache = {};
  
      while (i < n) {
        if (this._invalidated.all || $.grep(this._pipe[i].filter, filter).length > 0) {
          this._pipe[i].run(cache);
        }
        i++;
      }
  
      this._invalidated = {};
  
      !this.is('valid') && this.enter('valid');
    };
  
    /**
     * Gets the width of the view.
     * @public
     * @param {Owl.Width} [dimension=Owl.Width.Default] - The dimension to return.
     * @returns {Number} - The width of the view in pixel.
     */
    Owl.prototype.width = function(dimension) {
      dimension = dimension || Owl.Width.Default;
      switch (dimension) {
        case Owl.Width.Inner:
        case Owl.Width.Outer:
          return this._width;
        default:
          return this._width - this.settings.stagePadding * 2 + this.settings.margin;
      }
    };
  
    /**
     * Refreshes the carousel primarily for adaptive purposes.
     * @public
     */
    Owl.prototype.refresh = function() {
      this.enter('refreshing');
      this.trigger('refresh');
  
      this.setup();
  
      this.optionsLogic();
  
      this.$element.addClass(this.options.refreshClass);
  
      this.update();
  
      this.$element.removeClass(this.options.refreshClass);
  
      this.leave('refreshing');
      this.trigger('refreshed');
    };
  
    /**
     * Checks window `resize` event.
     * @protected
     */
    Owl.prototype.onThrottledResize = function() {
      window.clearTimeout(this.resizeTimer);
      this.resizeTimer = window.setTimeout(this._handlers.onResize, this.settings.responsiveRefreshRate);
    };
  
    /**
     * Checks window `resize` event.
     * @protected
     */
    Owl.prototype.onResize = function() {
      if (!this._items.length) {
        return false;
      }
  
      if (this._width === this.$element.width()) {
        return false;
      }
  
      if (!this.isVisible()) {
        return false;
      }
  
      this.enter('resizing');
  
      if (this.trigger('resize').isDefaultPrevented()) {
        this.leave('resizing');
        return false;
      }
  
      this.invalidate('width');
  
      this.refresh();
  
      this.leave('resizing');
      this.trigger('resized');
    };
  
    /**
     * Registers event handlers.
     * @todo Check `msPointerEnabled`
     * @todo #261
     * @protected
     */
    Owl.prototype.registerEventHandlers = function() {
      if ($.support.transition) {
        this.$stage.on($.support.transition.end + '.owl.core', $.proxy(this.onTransitionEnd, this));
      }
  
      if (this.settings.responsive !== false) {
        this.on(window, 'resize', this._handlers.onThrottledResize);
      }
  
      if (this.settings.mouseDrag) {
        this.$element.addClass(this.options.dragClass);
        this.$stage.on('mousedown.owl.core', $.proxy(this.onDragStart, this));
        this.$stage.on('dragstart.owl.core selectstart.owl.core', function() { return false });
      }
  
      if (this.settings.touchDrag){
        this.$stage.on('touchstart.owl.core', $.proxy(this.onDragStart, this));
        this.$stage.on('touchcancel.owl.core', $.proxy(this.onDragEnd, this));
      }
    };
  
    /**
     * Handles `touchstart` and `mousedown` events.
     * @todo Horizontal swipe threshold as option
     * @todo #261
     * @protected
     * @param {Event} event - The event arguments.
     */
    Owl.prototype.onDragStart = function(event) {
      var stage = null;
  
      if (event.which === 3) {
        return;
      }
  
      if ($.support.transform) {
        stage = this.$stage.css('transform').replace(/.*\(|\)| /g, '').split(',');
        stage = {
          x: stage[stage.length === 16 ? 12 : 4],
          y: stage[stage.length === 16 ? 13 : 5]
        };
      } else {
        stage = this.$stage.position();
        stage = {
          x: this.settings.rtl ?
            stage.left + this.$stage.width() - this.width() + this.settings.margin :
            stage.left,
          y: stage.top
        };
      }
  
      if (this.is('animating')) {
        $.support.transform ? this.animate(stage.x) : this.$stage.stop()
        this.invalidate('position');
      }
  
      this.$element.toggleClass(this.options.grabClass, event.type === 'mousedown');
  
      this.speed(0);
  
      this._drag.time = new Date().getTime();
      this._drag.target = $(event.target);
      this._drag.stage.start = stage;
      this._drag.stage.current = stage;
      this._drag.pointer = this.pointer(event);
  
      $(document).on('mouseup.owl.core touchend.owl.core', $.proxy(this.onDragEnd, this));
  
      $(document).one('mousemove.owl.core touchmove.owl.core', $.proxy(function(event) {
        var delta = this.difference(this._drag.pointer, this.pointer(event));
  
        $(document).on('mousemove.owl.core touchmove.owl.core', $.proxy(this.onDragMove, this));
  
        if (Math.abs(delta.x) < Math.abs(delta.y) && this.is('valid')) {
          return;
        }
  
        event.preventDefault();
  
        this.enter('dragging');
        this.trigger('drag');
      }, this));
    };
  
    /**
     * Handles the `touchmove` and `mousemove` events.
     * @todo #261
     * @protected
     * @param {Event} event - The event arguments.
     */
    Owl.prototype.onDragMove = function(event) {
      var minimum = null,
        maximum = null,
        pull = null,
        delta = this.difference(this._drag.pointer, this.pointer(event)),
        stage = this.difference(this._drag.stage.start, delta);
  
      if (!this.is('dragging')) {
        return;
      }
  
      event.preventDefault();
  
      if (this.settings.loop) {
        minimum = this.coordinates(this.minimum());
        maximum = this.coordinates(this.maximum() + 1) - minimum;
        stage.x = (((stage.x - minimum) % maximum + maximum) % maximum) + minimum;
      } else {
        minimum = this.settings.rtl ? this.coordinates(this.maximum()) : this.coordinates(this.minimum());
        maximum = this.settings.rtl ? this.coordinates(this.minimum()) : this.coordinates(this.maximum());
        pull = this.settings.pullDrag ? -1 * delta.x / 5 : 0;
        stage.x = Math.max(Math.min(stage.x, minimum + pull), maximum + pull);
      }
  
      this._drag.stage.current = stage;
  
      this.animate(stage.x);
    };
  
    /**
     * Handles the `touchend` and `mouseup` events.
     * @todo #261
     * @todo Threshold for click event
     * @protected
     * @param {Event} event - The event arguments.
     */
    Owl.prototype.onDragEnd = function(event) {
      var delta = this.difference(this._drag.pointer, this.pointer(event)),
        stage = this._drag.stage.current,
        direction = delta.x > 0 ^ this.settings.rtl ? 'left' : 'right';
  
      $(document).off('.owl.core');
  
      this.$element.removeClass(this.options.grabClass);
  
      if (delta.x !== 0 && this.is('dragging') || !this.is('valid')) {
        this.speed(this.settings.dragEndSpeed || this.settings.smartSpeed);
        this.current(this.closest(stage.x, delta.x !== 0 ? direction : this._drag.direction));
        this.invalidate('position');
        this.update();
  
        this._drag.direction = direction;
  
        if (Math.abs(delta.x) > 3 || new Date().getTime() - this._drag.time > 300) {
          this._drag.target.one('click.owl.core', function() { return false; });
        }
      }
  
      if (!this.is('dragging')) {
        return;
      }
  
      this.leave('dragging');
      this.trigger('dragged');
    };
  
    /**
     * Gets absolute position of the closest item for a coordinate.
     * @todo Setting `freeDrag` makes `closest` not reusable. See #165.
     * @protected
     * @param {Number} coordinate - The coordinate in pixel.
     * @param {String} direction - The direction to check for the closest item. Ether `left` or `right`.
     * @return {Number} - The absolute position of the closest item.
     */
    Owl.prototype.closest = function(coordinate, direction) {
      var position = -1,
        pull = 30,
        width = this.width(),
        coordinates = this.coordinates();
  
      if (!this.settings.freeDrag) {
        // check closest item
        $.each(coordinates, $.proxy(function(index, value) {
          // on a left pull, check on current index
          if (direction === 'left' && coordinate > value - pull && coordinate < value + pull) {
            position = index;
          // on a right pull, check on previous index
          // to do so, subtract width from value and set position = index + 1
          } else if (direction === 'right' && coordinate > value - width - pull && coordinate < value - width + pull) {
            position = index + 1;
          } else if (this.op(coordinate, '<', value)
            && this.op(coordinate, '>', coordinates[index + 1] !== undefined ? coordinates[index + 1] : value - width)) {
            position = direction === 'left' ? index + 1 : index;
          }
          return position === -1;
        }, this));
      }
  
      if (!this.settings.loop) {
        // non loop boundries
        if (this.op(coordinate, '>', coordinates[this.minimum()])) {
          position = coordinate = this.minimum();
        } else if (this.op(coordinate, '<', coordinates[this.maximum()])) {
          position = coordinate = this.maximum();
        }
      }
  
      return position;
    };
  
    /**
     * Animates the stage.
     * @todo #270
     * @public
     * @param {Number} coordinate - The coordinate in pixels.
     */
    Owl.prototype.animate = function(coordinate) {
      var animate = this.speed() > 0;
  
      this.is('animating') && this.onTransitionEnd();
  
      if (animate) {
        this.enter('animating');
        this.trigger('translate');
      }
  
      if ($.support.transform3d && $.support.transition) {
        this.$stage.css({
          transform: 'translate3d(' + coordinate + 'px,0px,0px)',
          transition: (this.speed() / 1000) + 's' + (
            this.settings.slideTransition ? ' ' + this.settings.slideTransition : ''
          )
        });
      } else if (animate) {
        this.$stage.animate({
          left: coordinate + 'px'
        }, this.speed(), this.settings.fallbackEasing, $.proxy(this.onTransitionEnd, this));
      } else {
        this.$stage.css({
          left: coordinate + 'px'
        });
      }
    };
  
    /**
     * Checks whether the carousel is in a specific state or not.
     * @param {String} state - The state to check.
     * @returns {Boolean} - The flag which indicates if the carousel is busy.
     */
    Owl.prototype.is = function(state) {
      return this._states.current[state] && this._states.current[state] > 0;
    };
  
    /**
     * Sets the absolute position of the current item.
     * @public
     * @param {Number} [position] - The new absolute position or nothing to leave it unchanged.
     * @returns {Number} - The absolute position of the current item.
     */
    Owl.prototype.current = function(position) {
      if (position === undefined) {
        return this._current;
      }
  
      if (this._items.length === 0) {
        return undefined;
      }
  
      position = this.normalize(position);
  
      if (this._current !== position) {
        var event = this.trigger('change', { property: { name: 'position', value: position } });
  
        if (event.data !== undefined) {
          position = this.normalize(event.data);
        }
  
        this._current = position;
  
        this.invalidate('position');
  
        this.trigger('changed', { property: { name: 'position', value: this._current } });
      }
  
      return this._current;
    };
  
    /**
     * Invalidates the given part of the update routine.
     * @param {String} [part] - The part to invalidate.
     * @returns {Array.<String>} - The invalidated parts.
     */
    Owl.prototype.invalidate = function(part) {
      if ($.type(part) === 'string') {
        this._invalidated[part] = true;
        this.is('valid') && this.leave('valid');
      }
      return $.map(this._invalidated, function(v, i) { return i });
    };
  
    /**
     * Resets the absolute position of the current item.
     * @public
     * @param {Number} position - The absolute position of the new item.
     */
    Owl.prototype.reset = function(position) {
      position = this.normalize(position);
  
      if (position === undefined) {
        return;
      }
  
      this._speed = 0;
      this._current = position;
  
      this.suppress([ 'translate', 'translated' ]);
  
      this.animate(this.coordinates(position));
  
      this.release([ 'translate', 'translated' ]);
    };
  
    /**
     * Normalizes an absolute or a relative position of an item.
     * @public
     * @param {Number} position - The absolute or relative position to normalize.
     * @param {Boolean} [relative=false] - Whether the given position is relative or not.
     * @returns {Number} - The normalized position.
     */
    Owl.prototype.normalize = function(position, relative) {
      var n = this._items.length,
        m = relative ? 0 : this._clones.length;
  
      if (!this.isNumeric(position) || n < 1) {
        position = undefined;
      } else if (position < 0 || position >= n + m) {
        position = ((position - m / 2) % n + n) % n + m / 2;
      }
  
      return position;
    };
  
    /**
     * Converts an absolute position of an item into a relative one.
     * @public
     * @param {Number} position - The absolute position to convert.
     * @returns {Number} - The converted position.
     */
    Owl.prototype.relative = function(position) {
      position -= this._clones.length / 2;
      return this.normalize(position, true);
    };
  
    /**
     * Gets the maximum position for the current item.
     * @public
     * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
     * @returns {Number}
     */
    Owl.prototype.maximum = function(relative) {
      var settings = this.settings,
        maximum = this._coordinates.length,
        iterator,
        reciprocalItemsWidth,
        elementWidth;
  
      if (settings.loop) {
        maximum = this._clones.length / 2 + this._items.length - 1;
      } else if (settings.autoWidth || settings.merge) {
        iterator = this._items.length;
        if (iterator) {
          reciprocalItemsWidth = this._items[--iterator].width();
          elementWidth = this.$element.width();
          while (iterator--) {
            reciprocalItemsWidth += this._items[iterator].width() + this.settings.margin;
            if (reciprocalItemsWidth > elementWidth) {
              break;
            }
          }
        }
        maximum = iterator + 1;
      } else if (settings.center) {
        maximum = this._items.length - 1;
      } else {
        maximum = this._items.length - settings.items;
      }
  
      if (relative) {
        maximum -= this._clones.length / 2;
      }
  
      return Math.max(maximum, 0);
    };
  
    /**
     * Gets the minimum position for the current item.
     * @public
     * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
     * @returns {Number}
     */
    Owl.prototype.minimum = function(relative) {
      return relative ? 0 : this._clones.length / 2;
    };
  
    /**
     * Gets an item at the specified relative position.
     * @public
     * @param {Number} [position] - The relative position of the item.
     * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given.
     */
    Owl.prototype.items = function(position) {
      if (position === undefined) {
        return this._items.slice();
      }
  
      position = this.normalize(position, true);
      return this._items[position];
    };
  
    /**
     * Gets an item at the specified relative position.
     * @public
     * @param {Number} [position] - The relative position of the item.
     * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given.
     */
    Owl.prototype.mergers = function(position) {
      if (position === undefined) {
        return this._mergers.slice();
      }
  
      position = this.normalize(position, true);
      return this._mergers[position];
    };
  
    /**
     * Gets the absolute positions of clones for an item.
     * @public
     * @param {Number} [position] - The relative position of the item.
     * @returns {Array.<Number>} - The absolute positions of clones for the item or all if no position was given.
     */
    Owl.prototype.clones = function(position) {
      var odd = this._clones.length / 2,
        even = odd + this._items.length,
        map = function(index) { return index % 2 === 0 ? even + index / 2 : odd - (index + 1) / 2 };
  
      if (position === undefined) {
        return $.map(this._clones, function(v, i) { return map(i) });
      }
  
      return $.map(this._clones, function(v, i) { return v === position ? map(i) : null });
    };
  
    /**
     * Sets the current animation speed.
     * @public
     * @param {Number} [speed] - The animation speed in milliseconds or nothing to leave it unchanged.
     * @returns {Number} - The current animation speed in milliseconds.
     */
    Owl.prototype.speed = function(speed) {
      if (speed !== undefined) {
        this._speed = speed;
      }
  
      return this._speed;
    };
  
    /**
     * Gets the coordinate of an item.
     * @todo The name of this method is missleanding.
     * @public
     * @param {Number} position - The absolute position of the item within `minimum()` and `maximum()`.
     * @returns {Number|Array.<Number>} - The coordinate of the item in pixel or all coordinates.
     */
    Owl.prototype.coordinates = function(position) {
      var multiplier = 1,
        newPosition = position - 1,
        coordinate;
  
      if (position === undefined) {
        return $.map(this._coordinates, $.proxy(function(coordinate, index) {
          return this.coordinates(index);
        }, this));
      }
  
      if (this.settings.center) {
        if (this.settings.rtl) {
          multiplier = -1;
          newPosition = position + 1;
        }
  
        coordinate = this._coordinates[position];
        coordinate += (this.width() - coordinate + (this._coordinates[newPosition] || 0)) / 2 * multiplier;
      } else {
        coordinate = this._coordinates[newPosition] || 0;
      }
  
      coordinate = Math.ceil(coordinate);
  
      return coordinate;
    };
  
    /**
     * Calculates the speed for a translation.
     * @protected
     * @param {Number} from - The absolute position of the start item.
     * @param {Number} to - The absolute position of the target item.
     * @param {Number} [factor=undefined] - The time factor in milliseconds.
     * @returns {Number} - The time in milliseconds for the translation.
     */
    Owl.prototype.duration = function(from, to, factor) {
      if (factor === 0) {
        return 0;
      }
  
      return Math.min(Math.max(Math.abs(to - from), 1), 6) * Math.abs((factor || this.settings.smartSpeed));
    };
  
    /**
     * Slides to the specified item.
     * @public
     * @param {Number} position - The position of the item.
     * @param {Number} [speed] - The time in milliseconds for the transition.
     */
    Owl.prototype.to = function(position, speed) {
      var current = this.current(),
        revert = null,
        distance = position - this.relative(current),
        direction = (distance > 0) - (distance < 0),
        items = this._items.length,
        minimum = this.minimum(),
        maximum = this.maximum();
  
      if (this.settings.loop) {
        if (!this.settings.rewind && Math.abs(distance) > items / 2) {
          distance += direction * -1 * items;
        }
  
        position = current + distance;
        revert = ((position - minimum) % items + items) % items + minimum;
  
        if (revert !== position && revert - distance <= maximum && revert - distance > 0) {
          current = revert - distance;
          position = revert;
          this.reset(current);
        }
      } else if (this.settings.rewind) {
        maximum += 1;
        position = (position % maximum + maximum) % maximum;
      } else {
        position = Math.max(minimum, Math.min(maximum, position));
      }
  
      this.speed(this.duration(current, position, speed));
      this.current(position);
  
      if (this.isVisible()) {
        this.update();
      }
    };
  
    /**
     * Slides to the next item.
     * @public
     * @param {Number} [speed] - The time in milliseconds for the transition.
     */
    Owl.prototype.next = function(speed) {
      speed = speed || false;
      this.to(this.relative(this.current()) + 1, speed);
    };
  
    /**
     * Slides to the previous item.
     * @public
     * @param {Number} [speed] - The time in milliseconds for the transition.
     */
    Owl.prototype.prev = function(speed) {
      speed = speed || false;
      this.to(this.relative(this.current()) - 1, speed);
    };
  
    /**
     * Handles the end of an animation.
     * @protected
     * @param {Event} event - The event arguments.
     */
    Owl.prototype.onTransitionEnd = function(event) {
  
      // if css2 animation then event object is undefined
      if (event !== undefined) {
        event.stopPropagation();
  
        // Catch only owl-stage transitionEnd event
        if ((event.target || event.srcElement || event.originalTarget) !== this.$stage.get(0)) {
          return false;
        }
      }
  
      this.leave('animating');
      this.trigger('translated');
    };
  
    /**
     * Gets viewport width.
     * @protected
     * @return {Number} - The width in pixel.
     */
    Owl.prototype.viewport = function() {
      var width;
      if (this.options.responsiveBaseElement !== window) {
        width = $(this.options.responsiveBaseElement).width();
      } else if (window.innerWidth) {
        width = window.innerWidth;
      } else if (document.documentElement && document.documentElement.clientWidth) {
        width = document.documentElement.clientWidth;
      } else {
        console.warn('Can not detect viewport width.');
      }
      return width;
    };
  
    /**
     * Replaces the current content.
     * @public
     * @param {HTMLElement|jQuery|String} content - The new content.
     */
    Owl.prototype.replace = function(content) {
      this.$stage.empty();
      this._items = [];
  
      if (content) {
        content = (content instanceof jQuery) ? content : $(content);
      }
  
      if (this.settings.nestedItemSelector) {
        content = content.find('.' + this.settings.nestedItemSelector);
      }
  
      content.filter(function() {
        return this.nodeType === 1;
      }).each($.proxy(function(index, item) {
        item = this.prepare(item);
        this.$stage.append(item);
        this._items.push(item);
        this._mergers.push(item.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
      }, this));
  
      this.reset(this.isNumeric(this.settings.startPosition) ? this.settings.startPosition : 0);
  
      this.invalidate('items');
    };
  
    /**
     * Adds an item.
     * @todo Use `item` instead of `content` for the event arguments.
     * @public
     * @param {HTMLElement|jQuery|String} content - The item content to add.
     * @param {Number} [position] - The relative position at which to insert the item otherwise the item will be added to the end.
     */
    Owl.prototype.add = function(content, position) {
      var current = this.relative(this._current);
  
      position = position === undefined ? this._items.length : this.normalize(position, true);
      content = content instanceof jQuery ? content : $(content);
  
      this.trigger('add', { content: content, position: position });
  
      content = this.prepare(content);
  
      if (this._items.length === 0 || position === this._items.length) {
        this._items.length === 0 && this.$stage.append(content);
        this._items.length !== 0 && this._items[position - 1].after(content);
        this._items.push(content);
        this._mergers.push(content.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
      } else {
        this._items[position].before(content);
        this._items.splice(position, 0, content);
        this._mergers.splice(position, 0, content.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
      }
  
      this._items[current] && this.reset(this._items[current].index());
  
      this.invalidate('items');
  
      this.trigger('added', { content: content, position: position });
    };
  
    /**
     * Removes an item by its position.
     * @todo Use `item` instead of `content` for the event arguments.
     * @public
     * @param {Number} position - The relative position of the item to remove.
     */
    Owl.prototype.remove = function(position) {
      position = this.normalize(position, true);
  
      if (position === undefined) {
        return;
      }
  
      this.trigger('remove', { content: this._items[position], position: position });
  
      this._items[position].remove();
      this._items.splice(position, 1);
      this._mergers.splice(position, 1);
  
      this.invalidate('items');
  
      this.trigger('removed', { content: null, position: position });
    };
  
    /**
     * Preloads images with auto width.
     * @todo Replace by a more generic approach
     * @protected
     */
    Owl.prototype.preloadAutoWidthImages = function(images) {
      images.each($.proxy(function(i, element) {
        this.enter('pre-loading');
        element = $(element);
        $(new Image()).one('load', $.proxy(function(e) {
          element.attr('src', e.target.src);
          element.css('opacity', 1);
          this.leave('pre-loading');
          !this.is('pre-loading') && !this.is('initializing') && this.refresh();
        }, this)).attr('src', element.attr('src') || element.attr('data-src') || element.attr('data-src-retina'));
      }, this));
    };
  
    /**
     * Destroys the carousel.
     * @public
     */
    Owl.prototype.destroy = function() {
  
      this.$element.off('.owl.core');
      this.$stage.off('.owl.core');
      $(document).off('.owl.core');
  
      if (this.settings.responsive !== false) {
        window.clearTimeout(this.resizeTimer);
        this.off(window, 'resize', this._handlers.onThrottledResize);
      }
  
      for (var i in this._plugins) {
        this._plugins[i].destroy();
      }
  
      this.$stage.children('.cloned').remove();
  
      this.$stage.unwrap();
      this.$stage.children().contents().unwrap();
      this.$stage.children().unwrap();
      this.$stage.remove();
      this.$element
        .removeClass(this.options.refreshClass)
        .removeClass(this.options.loadingClass)
        .removeClass(this.options.loadedClass)
        .removeClass(this.options.rtlClass)
        .removeClass(this.options.dragClass)
        .removeClass(this.options.grabClass)
        .attr('class', this.$element.attr('class').replace(new RegExp(this.options.responsiveClass + '-\\S+\\s', 'g'), ''))
        .removeData('owl.carousel');
    };
  
    /**
     * Operators to calculate right-to-left and left-to-right.
     * @protected
     * @param {Number} [a] - The left side operand.
     * @param {String} [o] - The operator.
     * @param {Number} [b] - The right side operand.
     */
    Owl.prototype.op = function(a, o, b) {
      var rtl = this.settings.rtl;
      switch (o) {
        case '<':
          return rtl ? a > b : a < b;
        case '>':
          return rtl ? a < b : a > b;
        case '>=':
          return rtl ? a <= b : a >= b;
        case '<=':
          return rtl ? a >= b : a <= b;
        default:
          break;
      }
    };
  
    /**
     * Attaches to an internal event.
     * @protected
     * @param {HTMLElement} element - The event source.
     * @param {String} event - The event name.
     * @param {Function} listener - The event handler to attach.
     * @param {Boolean} capture - Wether the event should be handled at the capturing phase or not.
     */
    Owl.prototype.on = function(element, event, listener, capture) {
      if (element.addEventListener) {
        element.addEventListener(event, listener, capture);
      } else if (element.attachEvent) {
        element.attachEvent('on' + event, listener);
      }
    };
  
    /**
     * Detaches from an internal event.
     * @protected
     * @param {HTMLElement} element - The event source.
     * @param {String} event - The event name.
     * @param {Function} listener - The attached event handler to detach.
     * @param {Boolean} capture - Wether the attached event handler was registered as a capturing listener or not.
     */
    Owl.prototype.off = function(element, event, listener, capture) {
      if (element.removeEventListener) {
        element.removeEventListener(event, listener, capture);
      } else if (element.detachEvent) {
        element.detachEvent('on' + event, listener);
      }
    };
  
    /**
     * Triggers a public event.
     * @todo Remove `status`, `relatedTarget` should be used instead.
     * @protected
     * @param {String} name - The event name.
     * @param {*} [data=null] - The event data.
     * @param {String} [namespace=carousel] - The event namespace.
     * @param {String} [state] - The state which is associated with the event.
     * @param {Boolean} [enter=false] - Indicates if the call enters the specified state or not.
     * @returns {Event} - The event arguments.
     */
    Owl.prototype.trigger = function(name, data, namespace, state, enter) {
      var status = {
        item: { count: this._items.length, index: this.current() }
      }, handler = $.camelCase(
        $.grep([ 'on', name, namespace ], function(v) { return v })
          .join('-').toLowerCase()
      ), event = $.Event(
        [ name, 'owl', namespace || 'carousel' ].join('.').toLowerCase(),
        $.extend({ relatedTarget: this }, status, data)
      );
  
      if (!this._supress[name]) {
        $.each(this._plugins, function(name, plugin) {
          if (plugin.onTrigger) {
            plugin.onTrigger(event);
          }
        });
  
        this.register({ type: Owl.Type.Event, name: name });
        this.$element.trigger(event);
  
        if (this.settings && typeof this.settings[handler] === 'function') {
          this.settings[handler].call(this, event);
        }
      }
  
      return event;
    };
  
    /**
     * Enters a state.
     * @param name - The state name.
     */
    Owl.prototype.enter = function(name) {
      $.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) {
        if (this._states.current[name] === undefined) {
          this._states.current[name] = 0;
        }
  
        this._states.current[name]++;
      }, this));
    };
  
    /**
     * Leaves a state.
     * @param name - The state name.
     */
    Owl.prototype.leave = function(name) {
      $.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) {
        this._states.current[name]--;
      }, this));
    };
  
    /**
     * Registers an event or state.
     * @public
     * @param {Object} object - The event or state to register.
     */
    Owl.prototype.register = function(object) {
      if (object.type === Owl.Type.Event) {
        if (!$.event.special[object.name]) {
          $.event.special[object.name] = {};
        }
  
        if (!$.event.special[object.name].owl) {
          var _default = $.event.special[object.name]._default;
          $.event.special[object.name]._default = function(e) {
            if (_default && _default.apply && (!e.namespace || e.namespace.indexOf('owl') === -1)) {
              return _default.apply(this, arguments);
            }
            return e.namespace && e.namespace.indexOf('owl') > -1;
          };
          $.event.special[object.name].owl = true;
        }
      } else if (object.type === Owl.Type.State) {
        if (!this._states.tags[object.name]) {
          this._states.tags[object.name] = object.tags;
        } else {
          this._states.tags[object.name] = this._states.tags[object.name].concat(object.tags);
        }
  
        this._states.tags[object.name] = $.grep(this._states.tags[object.name], $.proxy(function(tag, i) {
          return $.inArray(tag, this._states.tags[object.name]) === i;
        }, this));
      }
    };
  
    /**
     * Suppresses events.
     * @protected
     * @param {Array.<String>} events - The events to suppress.
     */
    Owl.prototype.suppress = function(events) {
      $.each(events, $.proxy(function(index, event) {
        this._supress[event] = true;
      }, this));
    };
  
    /**
     * Releases suppressed events.
     * @protected
     * @param {Array.<String>} events - The events to release.
     */
    Owl.prototype.release = function(events) {
      $.each(events, $.proxy(function(index, event) {
        delete this._supress[event];
      }, this));
    };
  
    /**
     * Gets unified pointer coordinates from event.
     * @todo #261
     * @protected
     * @param {Event} - The `mousedown` or `touchstart` event.
     * @returns {Object} - Contains `x` and `y` coordinates of current pointer position.
     */
    Owl.prototype.pointer = function(event) {
      var result = { x: null, y: null };
  
      event = event.originalEvent || event || window.event;
  
      event = event.touches && event.touches.length ?
        event.touches[0] : event.changedTouches && event.changedTouches.length ?
          event.changedTouches[0] : event;
  
      if (event.pageX) {
        result.x = event.pageX;
        result.y = event.pageY;
      } else {
        result.x = event.clientX;
        result.y = event.clientY;
      }
  
      return result;
    };
  
    /**
     * Determines if the input is a Number or something that can be coerced to a Number
     * @protected
     * @param {Number|String|Object|Array|Boolean|RegExp|Function|Symbol} - The input to be tested
     * @returns {Boolean} - An indication if the input is a Number or can be coerced to a Number
     */
    Owl.prototype.isNumeric = function(number) {
      return !isNaN(parseFloat(number));
    };
  
    /**
     * Gets the difference of two vectors.
     * @todo #261
     * @protected
     * @param {Object} - The first vector.
     * @param {Object} - The second vector.
     * @returns {Object} - The difference.
     */
    Owl.prototype.difference = function(first, second) {
      return {
        x: first.x - second.x,
        y: first.y - second.y
      };
    };
  
    /**
     * The jQuery Plugin for the Owl Carousel
     * @todo Navigation plugin `next` and `prev`
     * @public
     */
    $.fn.owlCarousel = function(option) {
      var args = Array.prototype.slice.call(arguments, 1);
  
      return this.each(function() {
        var $this = $(this),
          data = $this.data('owl.carousel');
  
        if (!data) {
          data = new Owl(this, typeof option == 'object' && option);
          $this.data('owl.carousel', data);
  
          $.each([
            'next', 'prev', 'to', 'destroy', 'refresh', 'replace', 'add', 'remove'
          ], function(i, event) {
            data.register({ type: Owl.Type.Event, name: event });
            data.$element.on(event + '.owl.carousel.core', $.proxy(function(e) {
              if (e.namespace && e.relatedTarget !== this) {
                this.suppress([ event ]);
                data[event].apply(this, [].slice.call(arguments, 1));
                this.release([ event ]);
              }
            }, data));
          });
        }
  
        if (typeof option == 'string' && option.charAt(0) !== '_') {
          data[option].apply(data, args);
        }
      });
    };
  
    /**
     * The constructor for the jQuery Plugin
     * @public
     */
    $.fn.owlCarousel.Constructor = Owl;
  
  })(window.Zepto || window.jQuery, window, document);
  
  /**
   * AutoRefresh Plugin
   * @version 2.3.4
   * @author Artus Kolanowski
   * @author David Deutsch
   * @license The MIT License (MIT)
   */
  ;(function($, window, document, undefined) {
  
    /**
     * Creates the auto refresh plugin.
     * @class The Auto Refresh Plugin
     * @param {Owl} carousel - The Owl Carousel
     */
    var AutoRefresh = function(carousel) {
      /**
       * Reference to the core.
       * @protected
       * @type {Owl}
       */
      this._core = carousel;
  
      /**
       * Refresh interval.
       * @protected
       * @type {number}
       */
      this._interval = null;
  
      /**
       * Whether the element is currently visible or not.
       * @protected
       * @type {Boolean}
       */
      this._visible = null;
  
      /**
       * All event handlers.
       * @protected
       * @type {Object}
       */
      this._handlers = {
        'initialized.owl.carousel': $.proxy(function(e) {
          if (e.namespace && this._core.settings.autoRefresh) {
            this.watch();
          }
        }, this)
      };
  
      // set default options
      this._core.options = $.extend({}, AutoRefresh.Defaults, this._core.options);
  
      // register event handlers
      this._core.$element.on(this._handlers);
    };
  
    /**
     * Default options.
     * @public
     */
    AutoRefresh.Defaults = {
      autoRefresh: true,
      autoRefreshInterval: 500
    };
  
    /**
     * Watches the element.
     */
    AutoRefresh.prototype.watch = function() {
      if (this._interval) {
        return;
      }
  
      this._visible = this._core.isVisible();
      this._interval = window.setInterval($.proxy(this.refresh, this), this._core.settings.autoRefreshInterval);
    };
  
    /**
     * Refreshes the element.
     */
    AutoRefresh.prototype.refresh = function() {
      if (this._core.isVisible() === this._visible) {
        return;
      }
  
      this._visible = !this._visible;
  
      this._core.$element.toggleClass('owl-hidden', !this._visible);
  
      this._visible && (this._core.invalidate('width') && this._core.refresh());
    };
  
    /**
     * Destroys the plugin.
     */
    AutoRefresh.prototype.destroy = function() {
      var handler, property;
  
      window.clearInterval(this._interval);
  
      for (handler in this._handlers) {
        this._core.$element.off(handler, this._handlers[handler]);
      }
      for (property in Object.getOwnPropertyNames(this)) {
        typeof this[property] != 'function' && (this[property] = null);
      }
    };
  
    $.fn.owlCarousel.Constructor.Plugins.AutoRefresh = AutoRefresh;
  
  })(window.Zepto || window.jQuery, window, document);
  
  /**
   * Lazy Plugin
   * @version 2.3.4
   * @author Bartosz Wojciechowski
   * @author David Deutsch
   * @license The MIT License (MIT)
   */
  ;(function($, window, document, undefined) {
  
    /**
     * Creates the lazy plugin.
     * @class The Lazy Plugin
     * @param {Owl} carousel - The Owl Carousel
     */
    var Lazy = function(carousel) {
  
      /**
       * Reference to the core.
       * @protected
       * @type {Owl}
       */
      this._core = carousel;
  
      /**
       * Already loaded items.
       * @protected
       * @type {Array.<jQuery>}
       */
      this._loaded = [];
  
      /**
       * Event handlers.
       * @protected
       * @type {Object}
       */
      this._handlers = {
        'initialized.owl.carousel change.owl.carousel resized.owl.carousel': $.proxy(function(e) {
          if (!e.namespace) {
            return;
          }
  
          if (!this._core.settings || !this._core.settings.lazyLoad) {
            return;
          }
  
          if ((e.property && e.property.name == 'position') || e.type == 'initialized') {
            var settings = this._core.settings,
              n = (settings.center && Math.ceil(settings.items / 2) || settings.items),
              i = ((settings.center && n * -1) || 0),
              position = (e.property && e.property.value !== undefined ? e.property.value : this._core.current()) + i,
              clones = this._core.clones().length,
              load = $.proxy(function(i, v) { this.load(v) }, this);
            //TODO: Need documentation for this new option
            if (settings.lazyLoadEager > 0) {
              n += settings.lazyLoadEager;
              // If the carousel is looping also preload images that are to the "left"
              if (settings.loop) {
                position -= settings.lazyLoadEager;
                n++;
              }
            }
  
            while (i++ < n) {
              this.load(clones / 2 + this._core.relative(position));
              clones && $.each(this._core.clones(this._core.relative(position)), load);
              position++;
            }
          }
        }, this)
      };
  
      // set the default options
      this._core.options = $.extend({}, Lazy.Defaults, this._core.options);
  
      // register event handler
      this._core.$element.on(this._handlers);
    };
  
    /**
     * Default options.
     * @public
     */
    Lazy.Defaults = {
      lazyLoad: false,
      lazyLoadEager: 0
    };
  
    /**
     * Loads all resources of an item at the specified position.
     * @param {Number} position - The absolute position of the item.
     * @protected
     */
    Lazy.prototype.load = function(position) {
      var $item = this._core.$stage.children().eq(position),
        $elements = $item && $item.find('.owl-lazy');
  
      if (!$elements || $.inArray($item.get(0), this._loaded) > -1) {
        return;
      }
  
      $elements.each($.proxy(function(index, element) {
        var $element = $(element), image,
                  url = (window.devicePixelRatio > 1 && $element.attr('data-src-retina')) || $element.attr('data-src') || $element.attr('data-srcset');
  
        this._core.trigger('load', { element: $element, url: url }, 'lazy');
  
        if ($element.is('img')) {
          $element.one('load.owl.lazy', $.proxy(function() {
            $element.css('opacity', 1);
            this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
          }, this)).attr('src', url);
              } else if ($element.is('source')) {
                  $element.one('load.owl.lazy', $.proxy(function() {
                      this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
                  }, this)).attr('srcset', url);
        } else {
          image = new Image();
          image.onload = $.proxy(function() {
            $element.css({
              'background-image': 'url("' + url + '")',
              'opacity': '1'
            });
            this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
          }, this);
          image.src = url;
        }
      }, this));
  
      this._loaded.push($item.get(0));
    };
  
    /**
     * Destroys the plugin.
     * @public
     */
    Lazy.prototype.destroy = function() {
      var handler, property;
  
      for (handler in this.handlers) {
        this._core.$element.off(handler, this.handlers[handler]);
      }
      for (property in Object.getOwnPropertyNames(this)) {
        typeof this[property] != 'function' && (this[property] = null);
      }
    };
  
    $.fn.owlCarousel.Constructor.Plugins.Lazy = Lazy;
  
  })(window.Zepto || window.jQuery, window, document);
  
  /**
   * AutoHeight Plugin
   * @version 2.3.4
   * @author Bartosz Wojciechowski
   * @author David Deutsch
   * @license The MIT License (MIT)
   */
  ;(function($, window, document, undefined) {
  
    /**
     * Creates the auto height plugin.
     * @class The Auto Height Plugin
     * @param {Owl} carousel - The Owl Carousel
     */
    var AutoHeight = function(carousel) {
      /**
       * Reference to the core.
       * @protected
       * @type {Owl}
       */
      this._core = carousel;
  
      this._previousHeight = null;
  
      /**
       * All event handlers.
       * @protected
       * @type {Object}
       */
      this._handlers = {
        'initialized.owl.carousel refreshed.owl.carousel': $.proxy(function(e) {
          if (e.namespace && this._core.settings.autoHeight) {
            this.update();
          }
        }, this),
        'changed.owl.carousel': $.proxy(function(e) {
          if (e.namespace && this._core.settings.autoHeight && e.property.name === 'position'){
            this.update();
          }
        }, this),
        'loaded.owl.lazy': $.proxy(function(e) {
          if (e.namespace && this._core.settings.autoHeight
            && e.element.closest('.' + this._core.settings.itemClass).index() === this._core.current()) {
            this.update();
          }
        }, this)
      };
  
      // set default options
      this._core.options = $.extend({}, AutoHeight.Defaults, this._core.options);
  
      // register event handlers
      this._core.$element.on(this._handlers);
      this._intervalId = null;
      var refThis = this;
  
      // These changes have been taken from a PR by gavrochelegnou proposed in #1575
      // and have been made compatible with the latest jQuery version
      $(window).on('load', function() {
        if (refThis._core.settings.autoHeight) {
          refThis.update();
        }
      });
  
      // Autoresize the height of the carousel when window is resized
      // When carousel has images, the height is dependent on the width
      // and should also change on resize
      $(window).resize(function() {
        if (refThis._core.settings.autoHeight) {
          if (refThis._intervalId != null) {
            clearTimeout(refThis._intervalId);
          }
  
          refThis._intervalId = setTimeout(function() {
            refThis.update();
          }, 250);
        }
      });
  
    };
  
    /**
     * Default options.
     * @public
     */
    AutoHeight.Defaults = {
      autoHeight: false,
      autoHeightClass: 'owl-height'
    };
  
    /**
     * Updates the view.
     */
    AutoHeight.prototype.update = function() {
      var start = this._core._current,
        end = start + this._core.settings.items,
        lazyLoadEnabled = this._core.settings.lazyLoad,
        visible = this._core.$stage.children().toArray().slice(start, end),
        heights = [],
        maxheight = 0;
  
      $.each(visible, function(index, item) {
        heights.push($(item).height());
      });
  
      maxheight = Math.max.apply(null, heights);
  
      if (maxheight <= 1 && lazyLoadEnabled && this._previousHeight) {
        maxheight = this._previousHeight;
      }
  
      this._previousHeight = maxheight;
  
      this._core.$stage.parent()
        .height(maxheight)
        .addClass(this._core.settings.autoHeightClass);
    };
  
    AutoHeight.prototype.destroy = function() {
      var handler, property;
  
      for (handler in this._handlers) {
        this._core.$element.off(handler, this._handlers[handler]);
      }
      for (property in Object.getOwnPropertyNames(this)) {
        typeof this[property] !== 'function' && (this[property] = null);
      }
    };
  
    $.fn.owlCarousel.Constructor.Plugins.AutoHeight = AutoHeight;
  
  })(window.Zepto || window.jQuery, window, document);
  
  /**
   * Video Plugin
   * @version 2.3.4
   * @author Bartosz Wojciechowski
   * @author David Deutsch
   * @license The MIT License (MIT)
   */
  ;(function($, window, document, undefined) {
  
    /**
     * Creates the video plugin.
     * @class The Video Plugin
     * @param {Owl} carousel - The Owl Carousel
     */
    var Video = function(carousel) {
      /**
       * Reference to the core.
       * @protected
       * @type {Owl}
       */
      this._core = carousel;
  
      /**
       * Cache all video URLs.
       * @protected
       * @type {Object}
       */
      this._videos = {};
  
      /**
       * Current playing item.
       * @protected
       * @type {jQuery}
       */
      this._playing = null;
  
      /**
       * All event handlers.
       * @todo The cloned content removale is too late
       * @protected
       * @type {Object}
       */
      this._handlers = {
        'initialized.owl.carousel': $.proxy(function(e) {
          if (e.namespace) {
            this._core.register({ type: 'state', name: 'playing', tags: [ 'interacting' ] });
          }
        }, this),
        'resize.owl.carousel': $.proxy(function(e) {
          if (e.namespace && this._core.settings.video && this.isInFullScreen()) {
            e.preventDefault();
          }
        }, this),
        'refreshed.owl.carousel': $.proxy(function(e) {
          if (e.namespace && this._core.is('resizing')) {
            this._core.$stage.find('.cloned .owl-video-frame').remove();
          }
        }, this),
        'changed.owl.carousel': $.proxy(function(e) {
          if (e.namespace && e.property.name === 'position' && this._playing) {
            this.stop();
          }
        }, this),
        'prepared.owl.carousel': $.proxy(function(e) {
          if (!e.namespace) {
            return;
          }
  
          var $element = $(e.content).find('.owl-video');
  
          if ($element.length) {
            $element.css('display', 'none');
            this.fetch($element, $(e.content));
          }
        }, this)
      };
  
      // set default options
      this._core.options = $.extend({}, Video.Defaults, this._core.options);
  
      // register event handlers
      this._core.$element.on(this._handlers);
  
      this._core.$element.on('click.owl.video', '.owl-video-play-icon', $.proxy(function(e) {
        this.play(e);
      }, this));
    };
  
    /**
     * Default options.
     * @public
     */
    Video.Defaults = {
      video: false,
      videoHeight: false,
      videoWidth: false
    };
  
    /**
     * Gets the video ID and the type (YouTube/Vimeo/vzaar only).
     * @protected
     * @param {jQuery} target - The target containing the video data.
     * @param {jQuery} item - The item containing the video.
     */
    Video.prototype.fetch = function(target, item) {
        var type = (function() {
            if (target.attr('data-vimeo-id')) {
              return 'vimeo';
            } else if (target.attr('data-vzaar-id')) {
              return 'vzaar'
            } else {
              return 'youtube';
            }
          })(),
          id = target.attr('data-vimeo-id') || target.attr('data-youtube-id') || target.attr('data-vzaar-id'),
          width = target.attr('data-width') || this._core.settings.videoWidth,
          height = target.attr('data-height') || this._core.settings.videoHeight,
          url = target.attr('href');
  
      if (url) {
  
        /*
            Parses the id's out of the following urls (and probably more):
            https://www.youtube.com/watch?v=:id
            https://youtu.be/:id
            https://vimeo.com/:id
            https://vimeo.com/channels/:channel/:id
            https://vimeo.com/groups/:group/videos/:id
            https://app.vzaar.com/videos/:id
  
            Visual example: https://regexper.com/#(http%3A%7Chttps%3A%7C)%5C%2F%5C%2F(player.%7Cwww.%7Capp.)%3F(vimeo%5C.com%7Cyoutu(be%5C.com%7C%5C.be%7Cbe%5C.googleapis%5C.com)%7Cvzaar%5C.com)%5C%2F(video%5C%2F%7Cvideos%5C%2F%7Cembed%5C%2F%7Cchannels%5C%2F.%2B%5C%2F%7Cgroups%5C%2F.%2B%5C%2F%7Cwatch%5C%3Fv%3D%7Cv%5C%2F)%3F(%5BA-Za-z0-9._%25-%5D*)(%5C%26%5CS%2B)%3F
        */
  
        id = url.match(/(http:|https:|)\/\/(player.|www.|app.)?(vimeo\.com|youtu(be\.com|\.be|be\.googleapis\.com|be\-nocookie\.com)|vzaar\.com)\/(video\/|videos\/|embed\/|channels\/.+\/|groups\/.+\/|watch\?v=|v\/)?([A-Za-z0-9._%-]*)(\&\S+)?/);
  
        if (id[3].indexOf('youtu') > -1) {
          type = 'youtube';
        } else if (id[3].indexOf('vimeo') > -1) {
          type = 'vimeo';
        } else if (id[3].indexOf('vzaar') > -1) {
          type = 'vzaar';
        } else {
          throw new Error('Video URL not supported.');
        }
        id = id[6];
      } else {
        throw new Error('Missing video URL.');
      }
  
      this._videos[url] = {
        type: type,
        id: id,
        width: width,
        height: height
      };
  
      item.attr('data-video', url);
  
      this.thumbnail(target, this._videos[url]);
    };
  
    /**
     * Creates video thumbnail.
     * @protected
     * @param {jQuery} target - The target containing the video data.
     * @param {Object} info - The video info object.
     * @see `fetch`
     */
    Video.prototype.thumbnail = function(target, video) {
      var tnLink,
        icon,
        path,
        dimensions = video.width && video.height ? 'width:' + video.width + 'px;height:' + video.height + 'px;' : '',
        customTn = target.find('img'),
        srcType = 'src',
        lazyClass = '',
        settings = this._core.settings,
        create = function(path) {
          icon = '<div class="owl-video-play-icon"></div>';
  
          if (settings.lazyLoad) {
            tnLink = $('<div/>',{
              "class": 'owl-video-tn ' + lazyClass,
              "srcType": path
            });
          } else {
            tnLink = $( '<div/>', {
              "class": "owl-video-tn",
              "style": 'opacity:1;background-image:url(' + path + ')'
            });
          }
          target.after(tnLink);
          target.after(icon);
        };
  
      // wrap video content into owl-video-wrapper div
      target.wrap( $( '<div/>', {
        "class": "owl-video-wrapper",
        "style": dimensions
      }));
  
      if (this._core.settings.lazyLoad) {
        srcType = 'data-src';
        lazyClass = 'owl-lazy';
      }
  
      // custom thumbnail
      if (customTn.length) {
        create(customTn.attr(srcType));
        customTn.remove();
        return false;
      }
  
      if (video.type === 'youtube') {
        path = "//img.youtube.com/vi/" + video.id + "/hqdefault.jpg";
        create(path);
      } else if (video.type === 'vimeo') {
        $.ajax({
          type: 'GET',
          url: '//vimeo.com/api/v2/video/' + video.id + '.json',
          jsonp: 'callback',
          dataType: 'jsonp',
          success: function(data) {
            path = data[0].thumbnail_large;
            create(path);
          }
        });
      } else if (video.type === 'vzaar') {
        $.ajax({
          type: 'GET',
          url: '//vzaar.com/api/videos/' + video.id + '.json',
          jsonp: 'callback',
          dataType: 'jsonp',
          success: function(data) {
            path = data.framegrab_url;
            create(path);
          }
        });
      }
    };
  
    /**
     * Stops the current video.
     * @public
     */
    Video.prototype.stop = function() {
      this._core.trigger('stop', null, 'video');
      this._playing.find('.owl-video-frame').remove();
      this._playing.removeClass('owl-video-playing');
      this._playing = null;
      this._core.leave('playing');
      this._core.trigger('stopped', null, 'video');
    };
  
    /**
     * Starts the current video.
     * @public
     * @param {Event} event - The event arguments.
     */
    Video.prototype.play = function(event) {
      var target = $(event.target),
        item = target.closest('.' + this._core.settings.itemClass),
        video = this._videos[item.attr('data-video')],
        width = video.width || '100%',
        height = video.height || this._core.$stage.height(),
        html,
        iframe;
  
      if (this._playing) {
        return;
      }
  
      this._core.enter('playing');
      this._core.trigger('play', null, 'video');
  
      item = this._core.items(this._core.relative(item.index()));
  
      this._core.reset(item.index());
  
      html = $( '<iframe frameborder="0" allowfullscreen mozallowfullscreen webkitAllowFullScreen ></iframe>' );
      html.attr( 'height', height );
      html.attr( 'width', width );
      if (video.type === 'youtube') {
        html.attr( 'src', '//www.youtube.com/embed/' + video.id + '?autoplay=1&rel=0&v=' + video.id );
      } else if (video.type === 'vimeo') {
        html.attr( 'src', '//player.vimeo.com/video/' + video.id + '?autoplay=1' );
      } else if (video.type === 'vzaar') {
        html.attr( 'src', '//view.vzaar.com/' + video.id + '/player?autoplay=true' );
      }
  
      iframe = $(html).wrap( '<div class="owl-video-frame" />' ).insertAfter(item.find('.owl-video'));
  
      this._playing = item.addClass('owl-video-playing');
    };
  
    /**
     * Checks whether an video is currently in full screen mode or not.
     * @todo Bad style because looks like a readonly method but changes members.
     * @protected
     * @returns {Boolean}
     */
    Video.prototype.isInFullScreen = function() {
      var element = document.fullscreenElement || document.mozFullScreenElement ||
          document.webkitFullscreenElement;
  
      return element && $(element).parent().hasClass('owl-video-frame');
    };
  
    /**
     * Destroys the plugin.
     */
    Video.prototype.destroy = function() {
      var handler, property;
  
      this._core.$element.off('click.owl.video');
  
      for (handler in this._handlers) {
        this._core.$element.off(handler, this._handlers[handler]);
      }
      for (property in Object.getOwnPropertyNames(this)) {
        typeof this[property] != 'function' && (this[property] = null);
      }
    };
  
    $.fn.owlCarousel.Constructor.Plugins.Video = Video;
  
  })(window.Zepto || window.jQuery, window, document);
  
  /**
   * Animate Plugin
   * @version 2.3.4
   * @author Bartosz Wojciechowski
   * @author David Deutsch
   * @license The MIT License (MIT)
   */
  ;(function($, window, document, undefined) {
  
    /**
     * Creates the animate plugin.
     * @class The Navigation Plugin
     * @param {Owl} scope - The Owl Carousel
     */
    var Animate = function(scope) {
      this.core = scope;
      this.core.options = $.extend({}, Animate.Defaults, this.core.options);
      this.swapping = true;
      this.previous = undefined;
      this.next = undefined;
  
      this.handlers = {
        'change.owl.carousel': $.proxy(function(e) {
          if (e.namespace && e.property.name == 'position') {
            this.previous = this.core.current();
            this.next = e.property.value;
          }
        }, this),
        'drag.owl.carousel dragged.owl.carousel translated.owl.carousel': $.proxy(function(e) {
          if (e.namespace) {
            this.swapping = e.type == 'translated';
          }
        }, this),
        'translate.owl.carousel': $.proxy(function(e) {
          if (e.namespace && this.swapping && (this.core.options.animateOut || this.core.options.animateIn)) {
            this.swap();
          }
        }, this)
      };
  
      this.core.$element.on(this.handlers);
    };
  
    /**
     * Default options.
     * @public
     */
    Animate.Defaults = {
      animateOut: false,
      animateIn: false
    };
  
    /**
     * Toggles the animation classes whenever an translations starts.
     * @protected
     * @returns {Boolean|undefined}
     */
    Animate.prototype.swap = function() {
  
      if (this.core.settings.items !== 1) {
        return;
      }
  
      if (!$.support.animation || !$.support.transition) {
        return;
      }
  
      this.core.speed(0);
  
      var left,
        clear = $.proxy(this.clear, this),
        previous = this.core.$stage.children().eq(this.previous),
        next = this.core.$stage.children().eq(this.next),
        incoming = this.core.settings.animateIn,
        outgoing = this.core.settings.animateOut;
  
      if (this.core.current() === this.previous) {
        return;
      }
  
      if (outgoing) {
        left = this.core.coordinates(this.previous) - this.core.coordinates(this.next);
        previous.one($.support.animation.end, clear)
          .css( { 'left': left + 'px' } )
          .addClass('animated owl-animated-out')
          .addClass(outgoing);
      }
  
      if (incoming) {
        next.one($.support.animation.end, clear)
          .addClass('animated owl-animated-in')
          .addClass(incoming);
      }
    };
  
    Animate.prototype.clear = function(e) {
      $(e.target).css( { 'left': '' } )
        .removeClass('animated owl-animated-out owl-animated-in')
        .removeClass(this.core.settings.animateIn)
        .removeClass(this.core.settings.animateOut);
      this.core.onTransitionEnd();
    };
  
    /**
     * Destroys the plugin.
     * @public
     */
    Animate.prototype.destroy = function() {
      var handler, property;
  
      for (handler in this.handlers) {
        this.core.$element.off(handler, this.handlers[handler]);
      }
      for (property in Object.getOwnPropertyNames(this)) {
        typeof this[property] != 'function' && (this[property] = null);
      }
    };
  
    $.fn.owlCarousel.Constructor.Plugins.Animate = Animate;
  
  })(window.Zepto || window.jQuery, window, document);
  
  /**
   * Autoplay Plugin
   * @version 2.3.4
   * @author Bartosz Wojciechowski
   * @author Artus Kolanowski
   * @author David Deutsch
   * @author Tom De Caluwé
   * @license The MIT License (MIT)
   */
  ;(function($, window, document, undefined) {
  
    /**
     * Creates the autoplay plugin.
     * @class The Autoplay Plugin
     * @param {Owl} scope - The Owl Carousel
     */
    var Autoplay = function(carousel) {
      /**
       * Reference to the core.
       * @protected
       * @type {Owl}
       */
      this._core = carousel;
  
      /**
       * The autoplay timeout id.
       * @type {Number}
       */
      this._call = null;
  
      /**
       * Depending on the state of the plugin, this variable contains either
       * the start time of the timer or the current timer value if it's
       * paused. Since we start in a paused state we initialize the timer
       * value.
       * @type {Number}
       */
      this._time = 0;
  
      /**
       * Stores the timeout currently used.
       * @type {Number}
       */
      this._timeout = 0;
  
      /**
       * Indicates whenever the autoplay is paused.
       * @type {Boolean}
       */
      this._paused = true;
  
      /**
       * All event handlers.
       * @protected
       * @type {Object}
       */
      this._handlers = {
        'changed.owl.carousel': $.proxy(function(e) {
          if (e.namespace && e.property.name === 'settings') {
            if (this._core.settings.autoplay) {
              this.play();
            } else {
              this.stop();
            }
          } else if (e.namespace && e.property.name === 'position' && this._paused) {
            // Reset the timer. This code is triggered when the position
            // of the carousel was changed through user interaction.
            this._time = 0;
          }
        }, this),
        'initialized.owl.carousel': $.proxy(function(e) {
          if (e.namespace && this._core.settings.autoplay) {
            this.play();
          }
        }, this),
        'play.owl.autoplay': $.proxy(function(e, t, s) {
          if (e.namespace) {
            this.play(t, s);
          }
        }, this),
        'stop.owl.autoplay': $.proxy(function(e) {
          if (e.namespace) {
            this.stop();
          }
        }, this),
        'mouseover.owl.autoplay': $.proxy(function() {
          if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
            this.pause();
          }
        }, this),
        'mouseleave.owl.autoplay': $.proxy(function() {
          if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
            this.play();
          }
        }, this),
        'touchstart.owl.core': $.proxy(function() {
          if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
            this.pause();
          }
        }, this),
        'touchend.owl.core': $.proxy(function() {
          if (this._core.settings.autoplayHoverPause) {
            this.play();
          }
        }, this)
      };
  
      // register event handlers
      this._core.$element.on(this._handlers);
  
      // set default options
      this._core.options = $.extend({}, Autoplay.Defaults, this._core.options);
    };
  
    /**
     * Default options.
     * @public
     */
    Autoplay.Defaults = {
      autoplay: false,
      autoplayTimeout: 5000,
      autoplayHoverPause: false,
      autoplaySpeed: false
    };
  
    /**
     * Transition to the next slide and set a timeout for the next transition.
     * @private
     * @param {Number} [speed] - The animation speed for the animations.
     */
    Autoplay.prototype._next = function(speed) {
      this._call = window.setTimeout(
        $.proxy(this._next, this, speed),
        this._timeout * (Math.round(this.read() / this._timeout) + 1) - this.read()
      );
  
      if (this._core.is('interacting') || document.hidden) {
        return;
      }
      this._core.next(speed || this._core.settings.autoplaySpeed);
    }
  
    /**
     * Reads the current timer value when the timer is playing.
     * @public
     */
    Autoplay.prototype.read = function() {
      return new Date().getTime() - this._time;
    };
  
    /**
     * Starts the autoplay.
     * @public
     * @param {Number} [timeout] - The interval before the next animation starts.
     * @param {Number} [speed] - The animation speed for the animations.
     */
    Autoplay.prototype.play = function(timeout, speed) {
      var elapsed;
  
      if (!this._core.is('rotating')) {
        this._core.enter('rotating');
      }
  
      timeout = timeout || this._core.settings.autoplayTimeout;
  
      // Calculate the elapsed time since the last transition. If the carousel
      // wasn't playing this calculation will yield zero.
      elapsed = Math.min(this._time % (this._timeout || timeout), timeout);
  
      if (this._paused) {
        // Start the clock.
        this._time = this.read();
        this._paused = false;
      } else {
        // Clear the active timeout to allow replacement.
        window.clearTimeout(this._call);
      }
  
      // Adjust the origin of the timer to match the new timeout value.
      this._time += this.read() % timeout - elapsed;
  
      this._timeout = timeout;
      this._call = window.setTimeout($.proxy(this._next, this, speed), timeout - elapsed);
    };
  
    /**
     * Stops the autoplay.
     * @public
     */
    Autoplay.prototype.stop = function() {
      if (this._core.is('rotating')) {
        // Reset the clock.
        this._time = 0;
        this._paused = true;
  
        window.clearTimeout(this._call);
        this._core.leave('rotating');
      }
    };
  
    /**
     * Pauses the autoplay.
     * @public
     */
    Autoplay.prototype.pause = function() {
      if (this._core.is('rotating') && !this._paused) {
        // Pause the clock.
        this._time = this.read();
        this._paused = true;
  
        window.clearTimeout(this._call);
      }
    };
  
    /**
     * Destroys the plugin.
     */
    Autoplay.prototype.destroy = function() {
      var handler, property;
  
      this.stop();
  
      for (handler in this._handlers) {
        this._core.$element.off(handler, this._handlers[handler]);
      }
      for (property in Object.getOwnPropertyNames(this)) {
        typeof this[property] != 'function' && (this[property] = null);
      }
    };
  
    $.fn.owlCarousel.Constructor.Plugins.autoplay = Autoplay;
  
  })(window.Zepto || window.jQuery, window, document);
  
  /**
   * Navigation Plugin
   * @version 2.3.4
   * @author Artus Kolanowski
   * @author David Deutsch
   * @license The MIT License (MIT)
   */
  ;(function($, window, document, undefined) {
    'use strict';
  
    /**
     * Creates the navigation plugin.
     * @class The Navigation Plugin
     * @param {Owl} carousel - The Owl Carousel.
     */
    var Navigation = function(carousel) {
      /**
       * Reference to the core.
       * @protected
       * @type {Owl}
       */
      this._core = carousel;
  
      /**
       * Indicates whether the plugin is initialized or not.
       * @protected
       * @type {Boolean}
       */
      this._initialized = false;
  
      /**
       * The current paging indexes.
       * @protected
       * @type {Array}
       */
      this._pages = [];
  
      /**
       * All DOM elements of the user interface.
       * @protected
       * @type {Object}
       */
      this._controls = {};
  
      /**
       * Markup for an indicator.
       * @protected
       * @type {Array.<String>}
       */
      this._templates = [];
  
      /**
       * The carousel element.
       * @type {jQuery}
       */
      this.$element = this._core.$element;
  
      /**
       * Overridden methods of the carousel.
       * @protected
       * @type {Object}
       */
      this._overrides = {
        next: this._core.next,
        prev: this._core.prev,
        to: this._core.to
      };
  
      /**
       * All event handlers.
       * @protected
       * @type {Object}
       */
      this._handlers = {
        'prepared.owl.carousel': $.proxy(function(e) {
          if (e.namespace && this._core.settings.dotsData) {
            this._templates.push('<div class="' + this._core.settings.dotClass + '">' +
              $(e.content).find('[data-dot]').addBack('[data-dot]').attr('data-dot') + '</div>');
          }
        }, this),
        'added.owl.carousel': $.proxy(function(e) {
          if (e.namespace && this._core.settings.dotsData) {
            this._templates.splice(e.position, 0, this._templates.pop());
          }
        }, this),
        'remove.owl.carousel': $.proxy(function(e) {
          if (e.namespace && this._core.settings.dotsData) {
            this._templates.splice(e.position, 1);
          }
        }, this),
        'changed.owl.carousel': $.proxy(function(e) {
          if (e.namespace && e.property.name == 'position') {
            this.draw();
          }
        }, this),
        'initialized.owl.carousel': $.proxy(function(e) {
          if (e.namespace && !this._initialized) {
            this._core.trigger('initialize', null, 'navigation');
            this.initialize();
            this.update();
            this.draw();
            this._initialized = true;
            this._core.trigger('initialized', null, 'navigation');
          }
        }, this),
        'refreshed.owl.carousel': $.proxy(function(e) {
          if (e.namespace && this._initialized) {
            this._core.trigger('refresh', null, 'navigation');
            this.update();
            this.draw();
            this._core.trigger('refreshed', null, 'navigation');
          }
        }, this)
      };
  
      // set default options
      this._core.options = $.extend({}, Navigation.Defaults, this._core.options);
  
      // register event handlers
      this.$element.on(this._handlers);
    };
  
    /**
     * Default options.
     * @public
     * @todo Rename `slideBy` to `navBy`
     */
    Navigation.Defaults = {
      nav: false,
      navText: [
        '<span aria-label="' + 'Previous' + '">&#x2039;</span>',
        '<span aria-label="' + 'Next' + '">&#x203a;</span>'
      ],
      navSpeed: false,
      navElement: 'button type="button" role="presentation"',
      navContainer: false,
      navContainerClass: 'owl-nav',
      navClass: [
        'owl-prev',
        'owl-next'
      ],
      slideBy: 1,
      dotClass: 'owl-dot',
      dotsClass: 'owl-dots',
      dots: true,
      dotsEach: false,
      dotsData: false,
      dotsSpeed: false,
      dotsContainer: false
    };
  
    /**
     * Initializes the layout of the plugin and extends the carousel.
     * @protected
     */
    Navigation.prototype.initialize = function() {
      var override,
        settings = this._core.settings;
  
      // create DOM structure for relative navigation
      this._controls.$relative = (settings.navContainer ? $(settings.navContainer)
        : $('<div>').addClass(settings.navContainerClass).appendTo(this.$element)).addClass('disabled');
  
      this._controls.$previous = $('<' + settings.navElement + '>')
        .addClass(settings.navClass[0])
        .html(settings.navText[0])
        .prependTo(this._controls.$relative)
        .on('click', $.proxy(function(e) {
          this.prev(settings.navSpeed);
        }, this));
      this._controls.$next = $('<' + settings.navElement + '>')
        .addClass(settings.navClass[1])
        .html(settings.navText[1])
        .appendTo(this._controls.$relative)
        .on('click', $.proxy(function(e) {
          this.next(settings.navSpeed);
        }, this));
  
      // create DOM structure for absolute navigation
      if (!settings.dotsData) {
        this._templates = [ $('<button role="button">')
          .addClass(settings.dotClass)
          .append($('<span>'))
          .prop('outerHTML') ];
      }
  
      this._controls.$absolute = (settings.dotsContainer ? $(settings.dotsContainer)
        : $('<div>').addClass(settings.dotsClass).appendTo(this.$element)).addClass('disabled');
  
      this._controls.$absolute.on('click', 'button', $.proxy(function(e) {
        var index = $(e.target).parent().is(this._controls.$absolute)
          ? $(e.target).index() : $(e.target).parent().index();
  
        e.preventDefault();
  
        this.to(index, settings.dotsSpeed);
      }, this));
  
      /*$el.on('focusin', function() {
        $(document).off(".carousel");
  
        $(document).on('keydown.carousel', function(e) {
          if(e.keyCode == 37) {
            $el.trigger('prev.owl')
          }
          if(e.keyCode == 39) {
            $el.trigger('next.owl')
          }
        });
      });*/
  
      // override public methods of the carousel
      for (override in this._overrides) {
        this._core[override] = $.proxy(this[override], this);
      }
    };
  
    /**
     * Destroys the plugin.
     * @protected
     */
    Navigation.prototype.destroy = function() {
      var handler, control, property, override, settings;
      settings = this._core.settings;
  
      for (handler in this._handlers) {
        this.$element.off(handler, this._handlers[handler]);
      }
      for (control in this._controls) {
        if (control === '$relative' && settings.navContainer) {
          this._controls[control].html('');
        } else {
          this._controls[control].remove();
        }
      }
      for (override in this.overides) {
        this._core[override] = this._overrides[override];
      }
      for (property in Object.getOwnPropertyNames(this)) {
        typeof this[property] != 'function' && (this[property] = null);
      }
    };
  
    /**
     * Updates the internal state.
     * @protected
     */
    Navigation.prototype.update = function() {
      var i, j, k,
        lower = this._core.clones().length / 2,
        upper = lower + this._core.items().length,
        maximum = this._core.maximum(true),
        settings = this._core.settings,
        size = settings.center || settings.autoWidth || settings.dotsData
          ? 1 : settings.dotsEach || settings.items;
  
      if (settings.slideBy !== 'page') {
        settings.slideBy = Math.min(settings.slideBy, settings.items);
      }
  
      if (settings.dots || settings.slideBy == 'page') {
        this._pages = [];
  
        for (i = lower, j = 0, k = 0; i < upper; i++) {
          if (j >= size || j === 0) {
            this._pages.push({
              start: Math.min(maximum, i - lower),
              end: i - lower + size - 1
            });
            if (Math.min(maximum, i - lower) === maximum) {
              break;
            }
            j = 0, ++k;
          }
          j += this._core.mergers(this._core.relative(i));
        }
      }
    };
  
    /**
     * Draws the user interface.
     * @todo The option `dotsData` wont work.
     * @protected
     */
    Navigation.prototype.draw = function() {
      var difference,
        settings = this._core.settings,
        disabled = this._core.items().length <= settings.items,
        index = this._core.relative(this._core.current()),
        loop = settings.loop || settings.rewind;
  
      this._controls.$relative.toggleClass('disabled', !settings.nav || disabled);
  
      if (settings.nav) {
        this._controls.$previous.toggleClass('disabled', !loop && index <= this._core.minimum(true));
        this._controls.$next.toggleClass('disabled', !loop && index >= this._core.maximum(true));
      }
  
      this._controls.$absolute.toggleClass('disabled', !settings.dots || disabled);
  
      if (settings.dots) {
        difference = this._pages.length - this._controls.$absolute.children().length;
  
        if (settings.dotsData && difference !== 0) {
          this._controls.$absolute.html(this._templates.join(''));
        } else if (difference > 0) {
          this._controls.$absolute.append(new Array(difference + 1).join(this._templates[0]));
        } else if (difference < 0) {
          this._controls.$absolute.children().slice(difference).remove();
        }
  
        this._controls.$absolute.find('.active').removeClass('active');
        this._controls.$absolute.children().eq($.inArray(this.current(), this._pages)).addClass('active');
      }
    };
  
    /**
     * Extends event data.
     * @protected
     * @param {Event} event - The event object which gets thrown.
     */
    Navigation.prototype.onTrigger = function(event) {
      var settings = this._core.settings;
  
      event.page = {
        index: $.inArray(this.current(), this._pages),
        count: this._pages.length,
        size: settings && (settings.center || settings.autoWidth || settings.dotsData
          ? 1 : settings.dotsEach || settings.items)
      };
    };
  
    /**
     * Gets the current page position of the carousel.
     * @protected
     * @returns {Number}
     */
    Navigation.prototype.current = function() {
      var current = this._core.relative(this._core.current());
      return $.grep(this._pages, $.proxy(function(page, index) {
        return page.start <= current && page.end >= current;
      }, this)).pop();
    };
  
    /**
     * Gets the current succesor/predecessor position.
     * @protected
     * @returns {Number}
     */
    Navigation.prototype.getPosition = function(successor) {
      var position, length,
        settings = this._core.settings;
  
      if (settings.slideBy == 'page') {
        position = $.inArray(this.current(), this._pages);
        length = this._pages.length;
        successor ? ++position : --position;
        position = this._pages[((position % length) + length) % length].start;
      } else {
        position = this._core.relative(this._core.current());
        length = this._core.items().length;
        successor ? position += settings.slideBy : position -= settings.slideBy;
      }
  
      return position;
    };
  
    /**
     * Slides to the next item or page.
     * @public
     * @param {Number} [speed=false] - The time in milliseconds for the transition.
     */
    Navigation.prototype.next = function(speed) {
      $.proxy(this._overrides.to, this._core)(this.getPosition(true), speed);
    };
  
    /**
     * Slides to the previous item or page.
     * @public
     * @param {Number} [speed=false] - The time in milliseconds for the transition.
     */
    Navigation.prototype.prev = function(speed) {
      $.proxy(this._overrides.to, this._core)(this.getPosition(false), speed);
    };
  
    /**
     * Slides to the specified item or page.
     * @public
     * @param {Number} position - The position of the item or page.
     * @param {Number} [speed] - The time in milliseconds for the transition.
     * @param {Boolean} [standard=false] - Whether to use the standard behaviour or not.
     */
    Navigation.prototype.to = function(position, speed, standard) {
      var length;
  
      if (!standard && this._pages.length) {
        length = this._pages.length;
        $.proxy(this._overrides.to, this._core)(this._pages[((position % length) + length) % length].start, speed);
      } else {
        $.proxy(this._overrides.to, this._core)(position, speed);
      }
    };
  
    $.fn.owlCarousel.Constructor.Plugins.Navigation = Navigation;
  
  })(window.Zepto || window.jQuery, window, document);
  
  /**
   * Hash Plugin
   * @version 2.3.4
   * @author Artus Kolanowski
   * @author David Deutsch
   * @license The MIT License (MIT)
   */
  ;(function($, window, document, undefined) {
    'use strict';
  
    /**
     * Creates the hash plugin.
     * @class The Hash Plugin
     * @param {Owl} carousel - The Owl Carousel
     */
    var Hash = function(carousel) {
      /**
       * Reference to the core.
       * @protected
       * @type {Owl}
       */
      this._core = carousel;
  
      /**
       * Hash index for the items.
       * @protected
       * @type {Object}
       */
      this._hashes = {};
  
      /**
       * The carousel element.
       * @type {jQuery}
       */
      this.$element = this._core.$element;
  
      /**
       * All event handlers.
       * @protected
       * @type {Object}
       */
      this._handlers = {
        'initialized.owl.carousel': $.proxy(function(e) {
          if (e.namespace && this._core.settings.startPosition === 'URLHash') {
            $(window).trigger('hashchange.owl.navigation');
          }
        }, this),
        'prepared.owl.carousel': $.proxy(function(e) {
          if (e.namespace) {
            var hash = $(e.content).find('[data-hash]').addBack('[data-hash]').attr('data-hash');
  
            if (!hash) {
              return;
            }
  
            this._hashes[hash] = e.content;
          }
        }, this),
        'changed.owl.carousel': $.proxy(function(e) {
          if (e.namespace && e.property.name === 'position') {
            var current = this._core.items(this._core.relative(this._core.current())),
              hash = $.map(this._hashes, function(item, hash) {
                return item === current ? hash : null;
              }).join();
  
            if (!hash || window.location.hash.slice(1) === hash) {
              return;
            }
  
            window.location.hash = hash;
          }
        }, this)
      };
  
      // set default options
      this._core.options = $.extend({}, Hash.Defaults, this._core.options);
  
      // register the event handlers
      this.$element.on(this._handlers);
  
      // register event listener for hash navigation
      $(window).on('hashchange.owl.navigation', $.proxy(function(e) {
        var hash = window.location.hash.substring(1),
          items = this._core.$stage.children(),
          position = this._hashes[hash] && items.index(this._hashes[hash]);
  
        if (position === undefined || position === this._core.current()) {
          return;
        }
  
        this._core.to(this._core.relative(position), false, true);
      }, this));
    };
  
    /**
     * Default options.
     * @public
     */
    Hash.Defaults = {
      URLhashListener: false
    };
  
    /**
     * Destroys the plugin.
     * @public
     */
    Hash.prototype.destroy = function() {
      var handler, property;
  
      $(window).off('hashchange.owl.navigation');
  
      for (handler in this._handlers) {
        this._core.$element.off(handler, this._handlers[handler]);
      }
      for (property in Object.getOwnPropertyNames(this)) {
        typeof this[property] != 'function' && (this[property] = null);
      }
    };
  
    $.fn.owlCarousel.Constructor.Plugins.Hash = Hash;
  
  })(window.Zepto || window.jQuery, window, document);
  
  /**
   * Support Plugin
   *
   * @version 2.3.4
   * @author Vivid Planet Software GmbH
   * @author Artus Kolanowski
   * @author David Deutsch
   * @license The MIT License (MIT)
   */
  ;(function($, window, document, undefined) {
  
    var style = $('<support>').get(0).style,
      prefixes = 'Webkit Moz O ms'.split(' '),
      events = {
        transition: {
          end: {
            WebkitTransition: 'webkitTransitionEnd',
            MozTransition: 'transitionend',
            OTransition: 'oTransitionEnd',
            transition: 'transitionend'
          }
        },
        animation: {
          end: {
            WebkitAnimation: 'webkitAnimationEnd',
            MozAnimation: 'animationend',
            OAnimation: 'oAnimationEnd',
            animation: 'animationend'
          }
        }
      },
      tests = {
        csstransforms: function() {
          return !!test('transform');
        },
        csstransforms3d: function() {
          return !!test('perspective');
        },
        csstransitions: function() {
          return !!test('transition');
        },
        cssanimations: function() {
          return !!test('animation');
        }
      };
  
    function test(property, prefixed) {
      var result = false,
        upper = property.charAt(0).toUpperCase() + property.slice(1);
  
      $.each((property + ' ' + prefixes.join(upper + ' ') + upper).split(' '), function(i, property) {
        if (style[property] !== undefined) {
          result = prefixed ? property : true;
          return false;
        }
      });
  
      return result;
    }
  
    function prefixed(property) {
      return test(property, true);
    }
  
    if (tests.csstransitions()) {
      /* jshint -W053 */
      $.support.transition = new String(prefixed('transition'))
      $.support.transition.end = events.transition.end[ $.support.transition ];
    }
  
    if (tests.cssanimations()) {
      /* jshint -W053 */
      $.support.animation = new String(prefixed('animation'))
      $.support.animation.end = events.animation.end[ $.support.animation ];
    }
  
    if (tests.csstransforms()) {
      /* jshint -W053 */
      $.support.transform = new String(prefixed('transform'));
      $.support.transform3d = tests.csstransforms3d();
    }
  
  })(window.Zepto || window.jQuery, window, document);
  
  
  /* ====================================================================================================
    SHOW PASSWORD 
  ==================================================================================================== */
  (function (factory) {
  
    if (typeof define === 'function' && define.amd) {
      // AMD. Register as an anonymous module.
      define(['jquery'], factory);
    } else if (typeof exports === 'object') {
      // Node/CommonJS
      factory(require('jquery'));
    } else {
      // Browser globals
      factory(jQuery);
    }
  
  }(function ($, undef) {
  
    var dataKey = 'plugin_hideShowPassword',
      shorthandArgs = ['show', 'innerToggle'],
      SPACE = 32,
      ENTER = 13;
  
    var canSetInputAttribute = (function(){
      var body = document.body,
        input = document.createElement('input'),
        result = true;
      if (! body) {
        body = document.createElement('body');
      }
      input = body.appendChild(input);
      try {
        input.setAttribute('type', 'text');
      } catch (e) {
        result = false;
      }
      body.removeChild(input);
      return result;
    }());
  
    var defaults = {
      // Visibility of the password text. Can be true, false, 'toggle'
      // or 'infer'. If 'toggle', it will be the opposite of whatever
      // it currently is. If 'infer', it will be based on the input
      // type (false if 'password', otherwise true).
      show: 'infer',
  
      // Set to true to create an inner toggle for this input. Can
      // also be sent to an event name to delay visibility of toggle
      // until that event is triggered on the input element.
      innerToggle: false,
  
      // If false, the plugin will be disabled entirely. Set to
      // the outcome of a test to insure input attributes can be
      // set after input has been inserted into the DOM.
      enable: canSetInputAttribute,
  
      // Event to trigger whenever the element is toggled.
      // For example, if 'focus' it will focus the cursor in the
      // input element after toggling.
      triggerOnToggle: false,
  
      // Class to add to input element when the plugin is enabled.
      className: 'hideShowPassword-field',
  
      // Event to trigger when the plugin is initialized and enabled.
      initEvent: 'hideShowPasswordInit',
  
      // Event to trigger whenever the visibility changes.
      changeEvent: 'passwordVisibilityChange',
  
      // Properties to add to the input element.
      props: {
        autocapitalize: 'off',
        autocomplete: 'off',
        autocorrect: 'off',
        spellcheck: 'false'
      },
  
      // Options specific to the inner toggle.
      toggle: {
        // The element to create.
        element: '<button type="button">',
        // Class name of element.
        className: 'hideShowPassword-toggle',
        // Whether or not to support touch-specific enhancements.
        // Defaults to the value of Modernizr.touchevents if available,
        // otherwise false.
        touchSupport: (typeof Modernizr === 'undefined') ? false : Modernizr.touchevents,
        // Non-touch event to bind to.
        attachToEvent: 'click.hideShowPassword',
        // Event to bind to when touchSupport is true.
        attachToTouchEvent: 'touchstart.hideShowPassword mousedown.hideShowPassword',
        // Key event to bind to if attachToKeyCodes is an array
        // of at least one keycode.
        attachToKeyEvent: 'keyup',
        // Key codes to bind the toggle event to for accessibility.
        // If false, this feature is disabled entirely.
        // If true, the array of key codes will be determined based
        // on the value of the element option.
        attachToKeyCodes: true,
        // Styles to add to the toggle element. Does not include
        // positioning styles.
        styles: { position: 'absolute' },
        // Styles to add only when touchSupport is true.
        touchStyles: { pointerEvents: 'none' },
        // Where to position the inner toggle relative to the
        // input element. Can be 'right', 'left' or 'infer'. If
        // 'infer', it will be based on the text-direction of the
        // input element.
        position: 'infer',
        // Where to position the inner toggle on the y-axis
        // relative to the input element. Can be 'top', 'bottom'
        // or 'middle'.
        verticalAlign: 'middle',
        // Amount by which to "offset" the toggle from the edge
        // of the input element.
        offset: 0,
        // Attributes to add to the toggle element.
        attr: {
          role: 'button',
          'aria-label': 'Show Password',
          title: 'Show Password',
          tabIndex: 0
        }
      },
  
      // Options specific to the wrapper element, created
      // when the innerToggle is initialized to help with
      // positioning of that element.
      wrapper: {
        // The element to create.
        element: '<div>',
        // Class name of element.
        className: 'hideShowPassword-wrapper',
        // If true, the width of the wrapper will be set
        // unless it is already the same width as the inner
        // element. If false, the width will never be set. Any
        // other value will be used as the width.
        enforceWidth: false,
        // Styles to add to the wrapper element. Does not
        // include inherited styles or width if enforceWidth
        // is not false.
        styles: { position: 'relative' },
        // Styles to "inherit" from the input element, allowing
        // the wrapper to avoid disrupting page styles.
        inheritStyles: [
          'display',
          'verticalAlign',
          'marginTop',
          'marginRight',
          'marginBottom',
          'marginLeft'
        ],
        // Styles for the input element when wrapped.
        innerElementStyles: {
          marginTop: 0,
          marginRight: 0,
          marginBottom: 0,
          marginLeft: 0
        }
      },
  
      // Options specific to the 'shown' or 'hidden'
      // states of the input element.
      states: {
        shown: {
          className: 'hideShowPassword-shown',
          changeEvent: 'passwordShown',
          props: { type: 'text' },
          toggle: {
            className: 'hideShowPassword-toggle-hide',
            content: 'Hide',
            attr: {
              'aria-pressed': 'true',
              title: 'Hide Password'
            }
          }
        },
        hidden: {
          className: 'hideShowPassword-hidden',
          changeEvent: 'passwordHidden',
          props: { type: 'password' },
          toggle: {
            className: 'hideShowPassword-toggle-show',
            content: 'Show',
            attr: {
              'aria-pressed': 'false',
              title: 'Show Password'
            }
          }
        }
      }
  
    };
  
    function HideShowPassword (element, options) {
      this.element = $(element);
      this.wrapperElement = $();
      this.toggleElement = $();
      this.init(options);
    }
  
    HideShowPassword.prototype = {
  
      init: function (options) {
        if (this.update(options, defaults)) {
          this.element.addClass(this.options.className);
          if (this.options.innerToggle) {
            this.wrapElement(this.options.wrapper);
            this.initToggle(this.options.toggle);
            if (typeof this.options.innerToggle === 'string') {
              this.toggleElement.hide();
              this.element.one(this.options.innerToggle, $.proxy(function(){
                this.toggleElement.show();
              }, this));
            }
          }
          this.element.trigger(this.options.initEvent, [ this ]);
        }
      },
  
      update: function (options, base) {
        this.options = this.prepareOptions(options, base);
        if (this.updateElement()) {
          this.element
            .trigger(this.options.changeEvent, [ this ])
            .trigger(this.state().changeEvent, [ this ]);
        }
        return this.options.enable;
      },
  
      toggle: function (showVal) {
        showVal = showVal || 'toggle';
        return this.update({ show: showVal });
      },
  
      prepareOptions: function (options, base) {
        var original = options || {},
          keyCodes = [],
          testElement;
        base = base || this.options;
        options = $.extend(true, {}, base, options);
        // Ugly conditional to resolve #34 in a backwards-compatible way (for now)
        if (original.hasOwnProperty('wrapper') && original.wrapper.hasOwnProperty('inheritStyles')) {
          options.wrapper.inheritStyles = original.wrapper.inheritStyles;
        }
        if (options.enable) {
          if (options.show === 'toggle') {
            options.show = this.isType('hidden', options.states);
          } else if (options.show === 'infer') {
            options.show = this.isType('shown', options.states);
          }
          if (options.toggle.position === 'infer') {
            options.toggle.position = (this.element.css('text-direction') === 'rtl') ? 'left' : 'right';
          }
          if (! $.isArray(options.toggle.attachToKeyCodes)) {
            if (options.toggle.attachToKeyCodes === true) {
              testElement = $(options.toggle.element);
              switch(testElement.prop('tagName').toLowerCase()) {
                case 'button':
                case 'input':
                  break;
                case 'a':
                  if (testElement.filter('[href]').length) {
                    keyCodes.push(SPACE);
                    break;
                  }
                default:
                  keyCodes.push(SPACE, ENTER);
                  break;
              }
            }
            options.toggle.attachToKeyCodes = keyCodes;
          }
        }
        return options;
      },
  
      updateElement: function () {
        if (! this.options.enable || this.isType()) return false;
        this.element
          .prop($.extend({}, this.options.props, this.state().props))
          .addClass(this.state().className)
          .removeClass(this.otherState().className);
        if (this.options.triggerOnToggle) {
          this.element.trigger(this.options.triggerOnToggle, [ this ]);
        }
        this.updateToggle();
        return true;
      },
  
      isType: function (comparison, states) {
        states = states || this.options.states;
        comparison = comparison || this.state(undef, undef, states).props.type;
        if (states[comparison]) {
          comparison = states[comparison].props.type;
        }
        return this.element.prop('type') === comparison;
      },
  
      state: function (key, invert, states) {
        states = states || this.options.states;
        if (key === undef) {
          key = this.options.show;
        }
        if (typeof key === 'boolean') {
          key = key ? 'shown' : 'hidden';
        }
        if (invert) {
          key = (key === 'shown') ? 'hidden' : 'shown';
        }
        return states[key];
      },
  
      otherState: function (key) {
        return this.state(key, true);
      },
  
      wrapElement: function (options) {
        var enforceWidth = options.enforceWidth,
          targetWidth;
        if (! this.wrapperElement.length) {
          targetWidth = this.element.outerWidth();
          $.each(options.inheritStyles, $.proxy(function (index, prop) {
            options.styles[prop] = this.element.css(prop);
          }, this));
          this.element.css(options.innerElementStyles).wrap(
            $(options.element).addClass(options.className).css(options.styles)
          );
          this.wrapperElement = this.element.parent();
          if (enforceWidth === true) {
            enforceWidth = (this.wrapperElement.outerWidth() === targetWidth) ? false : targetWidth;
          }
          if (enforceWidth !== false) {
            this.wrapperElement.css('width', enforceWidth);
          }
        }
        return this.wrapperElement;
      },
  
      initToggle: function (options) {
        if (! this.toggleElement.length) {
          // Create element
          this.toggleElement = $(options.element)
            .attr(options.attr)
            .addClass(options.className)
            .css(options.styles)
            .appendTo(this.wrapperElement);
          // Update content/attributes
          this.updateToggle();
          // Position
          this.positionToggle(options.position, options.verticalAlign, options.offset);
          // Events
          if (options.touchSupport) {
            this.toggleElement.css(options.touchStyles);
            this.element.on(options.attachToTouchEvent, $.proxy(this.toggleTouchEvent, this));
          } else {
            this.toggleElement.on(options.attachToEvent, $.proxy(this.toggleEvent, this));
          }
          if (options.attachToKeyCodes.length) {
            this.toggleElement.on(options.attachToKeyEvent, $.proxy(this.toggleKeyEvent, this));
          }
        }
        return this.toggleElement;
      },
  
      positionToggle: function (position, verticalAlign, offset) {
        var styles = {};
        styles[position] = offset;
        switch (verticalAlign) {
          case 'top':
          case 'bottom':
            styles[verticalAlign] = offset;
            break;
          case 'middle':
            styles.top = '50%';
            styles.marginTop = this.toggleElement.outerHeight() / -2;
            break;
        }
        return this.toggleElement.css(styles);
      },
  
      updateToggle: function (state, otherState) {
        var paddingProp,
          targetPadding;
        if (this.toggleElement.length) {
          paddingProp = 'padding-' + this.options.toggle.position;
          state = state || this.state().toggle;
          otherState = otherState || this.otherState().toggle;
          this.toggleElement
            .attr(state.attr)
            .addClass(state.className)
            .removeClass(otherState.className)
            .html(state.content);
          targetPadding = this.toggleElement.outerWidth() + (this.options.toggle.offset * 2);
          if (this.element.css(paddingProp) !== targetPadding) {
            this.element.css(paddingProp, targetPadding);
          }
        }
        return this.toggleElement;
      },
  
      toggleEvent: function (event) {
        event.preventDefault();
        this.toggle();
      },
  
      toggleKeyEvent: function (event) {
        $.each(this.options.toggle.attachToKeyCodes, $.proxy(function(index, keyCode) {
          if (event.which === keyCode) {
            this.toggleEvent(event);
            return false;
          }
        }, this));
      },
  
      toggleTouchEvent: function (event) {
        var toggleX = this.toggleElement.offset().left,
          eventX,
          lesser,
          greater;
        if (toggleX) {
          eventX = event.pageX || event.originalEvent.pageX;
          if (this.options.toggle.position === 'left') {
            toggleX+= this.toggleElement.outerWidth();
            lesser = eventX;
            greater = toggleX;
          } else {
            lesser = toggleX;
            greater = eventX;
          }
          if (greater >= lesser) {
            this.toggleEvent(event);
          }
        }
      }
  
    };
  
    $.fn.hideShowPassword = function () {
      var options = {};
      $.each(arguments, function (index, value) {
        var newOptions = {};
        if (typeof value === 'object') {
          newOptions = value;
        } else if (shorthandArgs[index]) {
          newOptions[shorthandArgs[index]] = value;
        } else {
          return false;
        }
        $.extend(true, options, newOptions);
      });
      return this.each(function(){
        var $this = $(this),
          data = $this.data(dataKey);
        if (data) {
          data.update(options);
        } else {
          $this.data(dataKey, new HideShowPassword(this, options));
        }
      });
    };
  
    $.each({ 'show':true, 'hide':false, 'toggle':'toggle' }, function (verb, showVal) {
      $.fn[verb + 'Password'] = function (innerToggle, options) {
        return this.hideShowPassword(showVal, innerToggle, options);
      };
    });
  
  }));
  
  /* ====================================================================================================
    bootstrap-datepicker.js
  ==================================================================================================== */
  /* =========================================================
   * bootstrap-datepicker.js
   * Repo: https://github.com/eternicode/bootstrap-datepicker/
   * Demo: http://eternicode.github.io/bootstrap-datepicker/
   * Docs: http://bootstrap-datepicker.readthedocs.org/
   * Forked from http://www.eyecon.ro/bootstrap-datepicker
   * =========================================================
   * Started by Stefan Petre; improvements by Andrew Rowls + contributors
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   * http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   * ========================================================= */
  
  (function($, undefined) {
  
      var $window = $(window);
  
      function UTCDate() {
          return new Date(Date.UTC.apply(Date, arguments));
      }
  
      function UTCToday() {
          var today = new Date();
          return UTCDate(today.getFullYear(), today.getMonth(), today.getDate());
      }
  
      function alias(method) {
          return function() {
              return this[method].apply(this, arguments);
          };
      }
  
      var DateArray = (function() {
          var extras = {
              get: function(i) {
                  return this.slice(i)[0];
              },
              contains: function(d) {
                  // Array.indexOf is not cross-browser;
                  // $.inArray doesn't work with Dates
                  var val = d && d.valueOf();
                  for (var i = 0, l = this.length; i < l; i++)
                      if (this[i].valueOf() === val)
                          return i;
                  return -1;
              },
              remove: function(i) {
                  this.splice(i, 1);
              },
              replace: function(new_array) {
                  if (!new_array)
                      return;
                  if (!$.isArray(new_array))
                      new_array = [new_array];
                  this.clear();
                  this.push.apply(this, new_array);
              },
              clear: function() {
                  this.length = 0;
              },
              copy: function() {
                  var a = new DateArray();
                  a.replace(this);
                  return a;
              }
          };
  
          return function() {
              var a = [];
              a.push.apply(a, arguments);
              $.extend(a, extras);
              return a;
          };
      })();
  
  
      // Picker object
  
      var Datepicker = function(element, options) {
          this.dates = new DateArray();
          this.viewDate = UTCToday();
          this.focusDate = null;
  
          this._process_options(options);
  
          this.element = $(element);
          this.isInline = false;
          this.isInput = this.element.is('input');
          this.component = this.element.is('.date') ? this.element.find('.add-on, .input-group-addon, .btn') : false;
          this.hasInput = this.component && this.element.find('input').length;
          if (this.component && this.component.length === 0)
              this.component = false;
  
          this.picker = $(DPGlobal.template);
          this._buildEvents();
          this._attachEvents();
  
          if (this.isInline) {
              this.picker.addClass('datepicker-inline').appendTo(this.element);
          } else {
              this.picker.addClass('datepicker-dropdown dropdown-menu');
          }
  
          if (this.o.rtl) {
              this.picker.addClass('datepicker-rtl');
          }
  
          this.viewMode = this.o.startView;
  
          if (this.o.calendarWeeks)
              this.picker.find('tfoot th.today')
                  .attr('colspan', function(i, val) {
                      return parseInt(val) + 1;
                  });
  
          this._allow_update = false;
  
          this.setStartDate(this._o.startDate);
          this.setEndDate(this._o.endDate);
          this.setDaysOfWeekDisabled(this.o.daysOfWeekDisabled);
  
          this.fillDow();
          this.fillMonths();
  
          this._allow_update = true;
  
          this.update();
          this.showMode();
  
          if (this.isInline) {
              this.show();
          }
      };
  
      Datepicker.prototype = {
          constructor: Datepicker,
  
          _process_options: function(opts) {
              // Store raw options for reference
              this._o = $.extend({}, this._o, opts);
              // Processed options
              var o = this.o = $.extend({}, this._o);
  
              // Check if "de-DE" style date is available, if not language should
              // fallback to 2 letter code eg "de"
              var lang = o.language;
              if (!dates[lang]) {
                  lang = lang.split('-')[0];
                  if (!dates[lang])
                      lang = defaults.language;
              }
              o.language = lang;
  
              switch (o.startView) {
                  case 2:
                  case 'decade':
                      o.startView = 2;
                      break;
                  case 1:
                  case 'year':
                      o.startView = 1;
                      break;
                  default:
                      o.startView = 0;
              }
  
              switch (o.minViewMode) {
                  case 1:
                  case 'months':
                      o.minViewMode = 1;
                      break;
                  case 2:
                  case 'years':
                      o.minViewMode = 2;
                      break;
                  default:
                      o.minViewMode = 0;
              }
  
              o.startView = Math.max(o.startView, o.minViewMode);
  
              // true, false, or Number > 0
              if (o.multidate !== true) {
                  o.multidate = Number(o.multidate) || false;
                  if (o.multidate !== false)
                      o.multidate = Math.max(0, o.multidate);
                  else
                      o.multidate = 1;
              }
              o.multidateSeparator = String(o.multidateSeparator);
  
              o.weekStart %= 7;
              o.weekEnd = ((o.weekStart + 6) % 7);
  
              var format = DPGlobal.parseFormat(o.format);
              if (o.startDate !== -Infinity) {
                  if ( !! o.startDate) {
                      if (o.startDate instanceof Date)
                          o.startDate = this._local_to_utc(this._zero_time(o.startDate));
                      else
                          o.startDate = DPGlobal.parseDate(o.startDate, format, o.language);
                  } else {
                      o.startDate = -Infinity;
                  }
              }
              if (o.endDate !== Infinity) {
                  if ( !! o.endDate) {
                      if (o.endDate instanceof Date)
                          o.endDate = this._local_to_utc(this._zero_time(o.endDate));
                      else
                          o.endDate = DPGlobal.parseDate(o.endDate, format, o.language);
                  } else {
                      o.endDate = Infinity;
                  }
              }
  
              o.daysOfWeekDisabled = o.daysOfWeekDisabled || [];
              if (!$.isArray(o.daysOfWeekDisabled))
                  o.daysOfWeekDisabled = o.daysOfWeekDisabled.split(/[,\s]*/);
              o.daysOfWeekDisabled = $.map(o.daysOfWeekDisabled, function(d) {
                  return parseInt(d, 10);
              });
  
              var plc = String(o.orientation).toLowerCase().split(/\s+/g),
                  _plc = o.orientation.toLowerCase();
              plc = $.grep(plc, function(word) {
                  return (/^auto|left|right|top|bottom$/).test(word);
              });
              o.orientation = {
                  x: 'auto',
                  y: 'auto'
              };
              if (!_plc || _plc === 'auto')
              ; // no action
              else if (plc.length === 1) {
                  switch (plc[0]) {
                      case 'top':
                      case 'bottom':
                          o.orientation.y = plc[0];
                          break;
                      case 'left':
                      case 'right':
                          o.orientation.x = plc[0];
                          break;
                  }
              } else {
                  _plc = $.grep(plc, function(word) {
                      return (/^left|right$/).test(word);
                  });
                  o.orientation.x = _plc[0] || 'auto';
  
                  _plc = $.grep(plc, function(word) {
                      return (/^top|bottom$/).test(word);
                  });
                  o.orientation.y = _plc[0] || 'auto';
              }
          },
          _events: [],
          _secondaryEvents: [],
          _applyEvents: function(evs) {
              for (var i = 0, el, ch, ev; i < evs.length; i++) {
                  el = evs[i][0];
                  if (evs[i].length === 2) {
                      ch = undefined;
                      ev = evs[i][1];
                  } else if (evs[i].length === 3) {
                      ch = evs[i][1];
                      ev = evs[i][2];
                  }
                  el.on(ev, ch);
              }
          },
          _unapplyEvents: function(evs) {
              for (var i = 0, el, ev, ch; i < evs.length; i++) {
                  el = evs[i][0];
                  if (evs[i].length === 2) {
                      ch = undefined;
                      ev = evs[i][1];
                  } else if (evs[i].length === 3) {
                      ch = evs[i][1];
                      ev = evs[i][2];
                  }
                  el.off(ev, ch);
              }
          },
          _buildEvents: function() {
              if (this.isInput) { // single input
                  this._events = [
                      [this.element, {
                          focus: $.proxy(this.show, this),
                          keyup: $.proxy(function(e) {
                              if ($.inArray(e.keyCode, [27, 37, 39, 38, 40, 32, 13, 9]) === -1)
                                  this.update();
                          }, this),
                          keydown: $.proxy(this.keydown, this)
                      }]
                  ];
              } else if (this.component && this.hasInput) { // component: input + button
                  this._events = [
                      // For components that are not readonly, allow keyboard nav
                      [this.element.find('input'), {
                          focus: $.proxy(this.show, this),
                          keyup: $.proxy(function(e) {
                              if ($.inArray(e.keyCode, [27, 37, 39, 38, 40, 32, 13, 9]) === -1)
                                  this.update();
                          }, this),
                          keydown: $.proxy(this.keydown, this)
                      }],
                      [this.component, {
                          click: $.proxy(this.show, this)
                      }]
                  ];
              } else if (this.element.is('div')) { // inline datepicker
                  this.isInline = true;
              } else {
                  this._events = [
                      [this.element, {
                          click: $.proxy(this.show, this)
                      }]
                  ];
              }
              this._events.push(
                  // Component: listen for blur on element descendants
                  [this.element, '*', {
                      blur: $.proxy(function(e) {
                          this._focused_from = e.target;
                      }, this)
                  }],
                  // Input: listen for blur on element
                  [this.element, {
                      blur: $.proxy(function(e) {
                          this._focused_from = e.target;
                      }, this)
                  }]
              );
  
              this._secondaryEvents = [
                  [this.picker, {
                      click: $.proxy(this.click, this)
                  }],
                  [$(window), {
                      resize: $.proxy(this.place, this)
                  }],
                  [$(document), {
                      'mousedown touchstart': $.proxy(function(e) {
                          // Clicked outside the datepicker, hide it
                          if (!(
                              this.element.is(e.target) ||
                              this.element.find(e.target).length ||
                              this.picker.is(e.target) ||
                              this.picker.find(e.target).length
                          )) {
                              this.hide();
                          }
                      }, this)
                  }]
              ];
          },
          _attachEvents: function() {
              this._detachEvents();
              this._applyEvents(this._events);
          },
          _detachEvents: function() {
              this._unapplyEvents(this._events);
          },
          _attachSecondaryEvents: function() {
              this._detachSecondaryEvents();
              this._applyEvents(this._secondaryEvents);
          },
          _detachSecondaryEvents: function() {
              this._unapplyEvents(this._secondaryEvents);
          },
          _trigger: function(event, altdate) {
              var date = altdate || this.dates.get(-1),
                  local_date = this._utc_to_local(date);
  
              this.element.trigger({
                  type: event,
                  date: local_date,
                  dates: $.map(this.dates, this._utc_to_local),
                  format: $.proxy(function(ix, format) {
                      if (arguments.length === 0) {
                          ix = this.dates.length - 1;
                          format = this.o.format;
                      } else if (typeof ix === 'string') {
                          format = ix;
                          ix = this.dates.length - 1;
                      }
                      format = format || this.o.format;
                      var date = this.dates.get(ix);
                      return DPGlobal.formatDate(date, format, this.o.language);
                  }, this)
              });
          },
  
          show: function() {
              if (!this.isInline)
                  this.picker.appendTo('body');
              this.picker.show();
              this.place();
              this._attachSecondaryEvents();
              this._trigger('show');
          },
  
          hide: function() {
              if (this.isInline)
                  return;
              if (!this.picker.is(':visible'))
                  return;
              this.focusDate = null;
              this.picker.hide().detach();
              this._detachSecondaryEvents();
              this.viewMode = this.o.startView;
              this.showMode();
  
              if (
                  this.o.forceParse &&
                  (
                      this.isInput && this.element.val() ||
                      this.hasInput && this.element.find('input').val()
                  )
              )
                  this.setValue();
              this._trigger('hide');
          },
  
          remove: function() {
              this.hide();
              this._detachEvents();
              this._detachSecondaryEvents();
              this.picker.remove();
              delete this.element.data().datepicker;
              if (!this.isInput) {
                  delete this.element.data().date;
              }
          },
  
          _utc_to_local: function(utc) {
              return utc && new Date(utc.getTime() + (utc.getTimezoneOffset() * 60000));
          },
          _local_to_utc: function(local) {
              return local && new Date(local.getTime() - (local.getTimezoneOffset() * 60000));
          },
          _zero_time: function(local) {
              return local && new Date(local.getFullYear(), local.getMonth(), local.getDate());
          },
          _zero_utc_time: function(utc) {
              return utc && new Date(Date.UTC(utc.getUTCFullYear(), utc.getUTCMonth(), utc.getUTCDate()));
          },
  
          getDates: function() {
              return $.map(this.dates, this._utc_to_local);
          },
  
          getUTCDates: function() {
              return $.map(this.dates, function(d) {
                  return new Date(d);
              });
          },
  
          getDate: function() {
              return this._utc_to_local(this.getUTCDate());
          },
  
          getUTCDate: function() {
              return new Date(this.dates.get(-1));
          },
  
          setDates: function() {
              var args = $.isArray(arguments[0]) ? arguments[0] : arguments;
              this.update.apply(this, args);
              this._trigger('changeDate');
              this.setValue();
          },
  
          setUTCDates: function() {
              var args = $.isArray(arguments[0]) ? arguments[0] : arguments;
              this.update.apply(this, $.map(args, this._utc_to_local));
              this._trigger('changeDate');
              this.setValue();
          },
  
          setDate: alias('setDates'),
          setUTCDate: alias('setUTCDates'),
  
          setValue: function() {
              var formatted = this.getFormattedDate();
              if (!this.isInput) {
                  if (this.component) {
                      this.element.find('input').val(formatted).change();
                  }
              } else {
                  this.element.val(formatted).change();
              }
          },
  
          getFormattedDate: function(format) {
              if (format === undefined)
                  format = this.o.format;
  
              var lang = this.o.language;
              return $.map(this.dates, function(d) {
                  return DPGlobal.formatDate(d, format, lang);
              }).join(this.o.multidateSeparator);
          },
  
          setStartDate: function(startDate) {
              this._process_options({
                  startDate: startDate
              });
              this.update();
              this.updateNavArrows();
          },
  
          setEndDate: function(endDate) {
              this._process_options({
                  endDate: endDate
              });
              this.update();
              this.updateNavArrows();
          },
  
          setDaysOfWeekDisabled: function(daysOfWeekDisabled) {
              this._process_options({
                  daysOfWeekDisabled: daysOfWeekDisabled
              });
              this.update();
              this.updateNavArrows();
          },
  
          place: function() {
              if (this.isInline)
                  return;
              var calendarWidth = this.picker.outerWidth(),
                  calendarHeight = this.picker.outerHeight(),
                  visualPadding = 10,
                  windowWidth = $window.width(),
                  windowHeight = $window.height(),
                  scrollTop = $window.scrollTop();
  
              var zIndex = parseInt(this.element.parents().filter(function() {
                  return $(this).css('z-index') !== 'auto';
              }).first().css('z-index')) + 9999;
              var offset = this.component ? this.component.parent().offset() : this.element.offset();
              var height = this.component ? this.component.outerHeight(true) : this.element.outerHeight(false);
              var width = this.component ? this.component.outerWidth(true) : this.element.outerWidth(false);
              var left = offset.left,
                  top = offset.top;
  
              this.picker.removeClass(
                  'datepicker-orient-top datepicker-orient-bottom ' +
                  'datepicker-orient-right datepicker-orient-left'
              );
  
              if (this.o.orientation.x !== 'auto') {
                  this.picker.addClass('datepicker-orient-' + this.o.orientation.x);
                  if (this.o.orientation.x === 'right')
                      left -= calendarWidth - width;
              }
              // auto x orientation is best-placement: if it crosses a window
              // edge, fudge it sideways
              else {
                  // Default to left
                  this.picker.addClass('datepicker-orient-left');
                  if (offset.left < 0)
                      left -= offset.left - visualPadding;
                  else if (offset.left + calendarWidth > windowWidth)
                      left = windowWidth - calendarWidth - visualPadding;
              }
  
              // auto y orientation is best-situation: top or bottom, no fudging,
              // decision based on which shows more of the calendar
              var yorient = this.o.orientation.y,
                  top_overflow, bottom_overflow;
              if (yorient === 'auto') {
                  top_overflow = -scrollTop + offset.top - calendarHeight;
                  bottom_overflow = scrollTop + windowHeight - (offset.top + height + calendarHeight);
                  if (Math.max(top_overflow, bottom_overflow) === bottom_overflow)
                      yorient = 'top';
                  else
                      yorient = 'bottom';
              }
              this.picker.addClass('datepicker-orient-' + yorient);
              if (yorient === 'top')
                  top += height;
              else
                  top -= calendarHeight + parseInt(this.picker.css('padding-top'));
  
              this.picker.css({
                  top: top,
                  left: left,
                  zIndex: zIndex
              });
          },
  
          _allow_update: true,
          update: function() {
              if (!this._allow_update)
                  return;
  
              var oldDates = this.dates.copy(),
                  dates = [],
                  fromArgs = false;
              if (arguments.length) {
                  $.each(arguments, $.proxy(function(i, date) {
                      if (date instanceof Date)
                          date = this._local_to_utc(date);
                      dates.push(date);
                  }, this));
                  fromArgs = true;
              } else {
                  dates = this.isInput ? this.element.val() : this.element.data('date') || this.element.find('input').val();
                  if (dates && this.o.multidate)
                      dates = dates.split(this.o.multidateSeparator);
                  else
                      dates = [dates];
                  delete this.element.data().date;
              }
  
              dates = $.map(dates, $.proxy(function(date) {
                  return DPGlobal.parseDate(date, this.o.format, this.o.language);
              }, this));
              dates = $.grep(dates, $.proxy(function(date) {
                  return (
                      date < this.o.startDate ||
                      date > this.o.endDate || !date
                  );
              }, this), true);
              this.dates.replace(dates);
  
              if (this.dates.length)
                  this.viewDate = new Date(this.dates.get(-1));
              else if (this.viewDate < this.o.startDate)
                  this.viewDate = new Date(this.o.startDate);
              else if (this.viewDate > this.o.endDate)
                  this.viewDate = new Date(this.o.endDate);
  
              if (fromArgs) {
                  // setting date by clicking
                  this.setValue();
              } else if (dates.length) {
                  // setting date by typing
                  if (String(oldDates) !== String(this.dates))
                      this._trigger('changeDate');
              }
              if (!this.dates.length && oldDates.length)
                  this._trigger('clearDate');
  
              this.fill();
          },
  
          fillDow: function() {
              var dowCnt = this.o.weekStart,
                  html = '<tr>';
              if (this.o.calendarWeeks) {
                  var cell = '<th class="cw">&nbsp;</th>';
                  html += cell;
                  this.picker.find('.datepicker-days thead tr:first-child').prepend(cell);
              }
              while (dowCnt < this.o.weekStart + 7) {
                  html += '<th class="dow">' + dates[this.o.language].daysMin[(dowCnt++) % 7] + '</th>';
              }
              html += '</tr>';
              this.picker.find('.datepicker-days thead').append(html);
          },
  
          fillMonths: function() {
              var html = '',
                  i = 0;
              while (i < 12) {
                  html += '<span class="month">' + dates[this.o.language].monthsShort[i++] + '</span>';
              }
              this.picker.find('.datepicker-months td').html(html);
          },
  
          setRange: function(range) {
              if (!range || !range.length)
                  delete this.range;
              else
                  this.range = $.map(range, function(d) {
                      return d.valueOf();
                  });
              this.fill();
          },
  
          getClassNames: function(date) {
              var cls = [],
                  year = this.viewDate.getUTCFullYear(),
                  month = this.viewDate.getUTCMonth(),
                  today = new Date();
              if (date.getUTCFullYear() < year || (date.getUTCFullYear() === year && date.getUTCMonth() < month)) {
                  cls.push('old');
              } else if (date.getUTCFullYear() > year || (date.getUTCFullYear() === year && date.getUTCMonth() > month)) {
                  cls.push('new');
              }
              if (this.focusDate && date.valueOf() === this.focusDate.valueOf())
                  cls.push('focused');
              // Compare internal UTC date with local today, not UTC today
              if (this.o.todayHighlight &&
                  date.getUTCFullYear() === today.getFullYear() &&
                  date.getUTCMonth() === today.getMonth() &&
                  date.getUTCDate() === today.getDate()) {
                  cls.push('today');
              }
              if (this.dates.contains(date) !== -1)
                  cls.push('active');
              if (date.valueOf() < this.o.startDate || date.valueOf() > this.o.endDate ||
                  $.inArray(date.getUTCDay(), this.o.daysOfWeekDisabled) !== -1) {
                  cls.push('disabled');
              }
              if (this.range) {
                  if (date > this.range[0] && date < this.range[this.range.length - 1]) {
                      cls.push('range');
                  }
                  if ($.inArray(date.valueOf(), this.range) !== -1) {
                      cls.push('selected');
                  }
              }
              return cls;
          },
  
          fill: function() {
              var d = new Date(this.viewDate),
                  year = d.getUTCFullYear(),
                  month = d.getUTCMonth(),
                  startYear = this.o.startDate !== -Infinity ? this.o.startDate.getUTCFullYear() : -Infinity,
                  startMonth = this.o.startDate !== -Infinity ? this.o.startDate.getUTCMonth() : -Infinity,
                  endYear = this.o.endDate !== Infinity ? this.o.endDate.getUTCFullYear() : Infinity,
                  endMonth = this.o.endDate !== Infinity ? this.o.endDate.getUTCMonth() : Infinity,
                  todaytxt = dates[this.o.language].today || dates['en'].today || '',
                  cleartxt = dates[this.o.language].clear || dates['en'].clear || '',
                  tooltip;
              this.picker.find('.datepicker-days thead th.datepicker-switch')
                  .text(dates[this.o.language].months[month] + ' ' + year);
              this.picker.find('tfoot th.today')
                  .text(todaytxt)
                  .toggle(this.o.todayBtn !== false);
              this.picker.find('tfoot th.clear')
                  .text(cleartxt)
                  .toggle(this.o.clearBtn !== false);
              this.updateNavArrows();
              this.fillMonths();
              var prevMonth = UTCDate(year, month - 1, 28),
                  day = DPGlobal.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
              prevMonth.setUTCDate(day);
              prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.o.weekStart + 7) % 7);
              var nextMonth = new Date(prevMonth);
              nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
              nextMonth = nextMonth.valueOf();
              var html = [];
              var clsName;
              while (prevMonth.valueOf() < nextMonth) {
                  if (prevMonth.getUTCDay() === this.o.weekStart) {
                      html.push('<tr>');
                      if (this.o.calendarWeeks) {
                          // ISO 8601: First week contains first thursday.
                          // ISO also states week starts on Monday, but we can be more abstract here.
                          var
                          // Start of current week: based on weekstart/current date
                          ws = new Date(+prevMonth + (this.o.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
                              // Thursday of this week
                              th = new Date(Number(ws) + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
                              // First Thursday of year, year from thursday
                              yth = new Date(Number(yth = UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay()) % 7 * 864e5),
                              // Calendar week: ms between thursdays, div ms per day, div 7 days
                              calWeek = (th - yth) / 864e5 / 7 + 1;
                          html.push('<td class="cw">' + calWeek + '</td>');
  
                      }
                  }
                  clsName = this.getClassNames(prevMonth);
                  clsName.push('day');
  
                  if (this.o.beforeShowDay !== $.noop) {
                      var before = this.o.beforeShowDay(this._utc_to_local(prevMonth));
                      if (before === undefined)
                          before = {};
                      else if (typeof(before) === 'boolean')
                          before = {
                              enabled: before
                          };
                      else if (typeof(before) === 'string')
                          before = {
                              classes: before
                          };
                      if (before.enabled === false)
                          clsName.push('disabled');
                      if (before.classes)
                          clsName = clsName.concat(before.classes.split(/\s+/));
                      if (before.tooltip)
                          tooltip = before.tooltip;
                  }
  
                  clsName = $.unique(clsName);
                  html.push('<td class="' + clsName.join(' ') + '"' + (tooltip ? ' title="' + tooltip + '"' : '') + '>' + prevMonth.getUTCDate() + '</td>');
                  if (prevMonth.getUTCDay() === this.o.weekEnd) {
                      html.push('</tr>');
                  }
                  prevMonth.setUTCDate(prevMonth.getUTCDate() + 1);
              }
              this.picker.find('.datepicker-days tbody').empty().append(html.join(''));
  
              var months = this.picker.find('.datepicker-months')
                  .find('th:eq(1)')
                  .text(year)
                  .end()
                  .find('span').removeClass('active');
  
              $.each(this.dates, function(i, d) {
                  if (d.getUTCFullYear() === year)
                      months.eq(d.getUTCMonth()).addClass('active');
              });
  
              if (year < startYear || year > endYear) {
                  months.addClass('disabled');
              }
              if (year === startYear) {
                  months.slice(0, startMonth).addClass('disabled');
              }
              if (year === endYear) {
                  months.slice(endMonth + 1).addClass('disabled');
              }
  
              html = '';
              year = parseInt(year / 10, 10) * 10;
              var yearCont = this.picker.find('.datepicker-years')
                  .find('th:eq(1)')
                  .text(year + '-' + (year + 9))
                  .end()
                  .find('td');
              year -= 1;
              var years = $.map(this.dates, function(d) {
                  return d.getUTCFullYear();
              }),
                  classes;
              for (var i = -1; i < 11; i++) {
                  classes = ['year'];
                  if (i === -1)
                      classes.push('old');
                  else if (i === 10)
                      classes.push('new');
                  if ($.inArray(year, years) !== -1)
                      classes.push('active');
                  if (year < startYear || year > endYear)
                      classes.push('disabled');
                  html += '<span class="' + classes.join(' ') + '">' + year + '</span>';
                  year += 1;
              }
              yearCont.html(html);
          },
  
          updateNavArrows: function() {
              if (!this._allow_update)
                  return;
  
              var d = new Date(this.viewDate),
                  year = d.getUTCFullYear(),
                  month = d.getUTCMonth();
              switch (this.viewMode) {
                  case 0:
                      if (this.o.startDate !== -Infinity && year <= this.o.startDate.getUTCFullYear() && month <= this.o.startDate.getUTCMonth()) {
                          this.picker.find('.prev').css({
                              visibility: 'hidden'
                          });
                      } else {
                          this.picker.find('.prev').css({
                              visibility: 'visible'
                          });
                      }
                      if (this.o.endDate !== Infinity && year >= this.o.endDate.getUTCFullYear() && month >= this.o.endDate.getUTCMonth()) {
                          this.picker.find('.next').css({
                              visibility: 'hidden'
                          });
                      } else {
                          this.picker.find('.next').css({
                              visibility: 'visible'
                          });
                      }
                      break;
                  case 1:
                  case 2:
                      if (this.o.startDate !== -Infinity && year <= this.o.startDate.getUTCFullYear()) {
                          this.picker.find('.prev').css({
                              visibility: 'hidden'
                          });
                      } else {
                          this.picker.find('.prev').css({
                              visibility: 'visible'
                          });
                      }
                      if (this.o.endDate !== Infinity && year >= this.o.endDate.getUTCFullYear()) {
                          this.picker.find('.next').css({
                              visibility: 'hidden'
                          });
                      } else {
                          this.picker.find('.next').css({
                              visibility: 'visible'
                          });
                      }
                      break;
              }
          },
  
          click: function(e) {
              e.preventDefault();
              var target = $(e.target).closest('span, td, th'),
                  year, month, day;
              if (target.length === 1) {
                  switch (target[0].nodeName.toLowerCase()) {
                      case 'th':
                          switch (target[0].className) {
                              case 'datepicker-switch':
                                  this.showMode(1);
                                  break;
                              case 'prev':
                              case 'next':
                                  var dir = DPGlobal.modes[this.viewMode].navStep * (target[0].className === 'prev' ? -1 : 1);
                                  switch (this.viewMode) {
                                      case 0:
                                          this.viewDate = this.moveMonth(this.viewDate, dir);
                                          this._trigger('changeMonth', this.viewDate);
                                          break;
                                      case 1:
                                      case 2:
                                          this.viewDate = this.moveYear(this.viewDate, dir);
                                          if (this.viewMode === 1)
                                              this._trigger('changeYear', this.viewDate);
                                          break;
                                  }
                                  this.fill();
                                  break;
                              case 'today':
                                  var date = new Date();
                                  date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
  
                                  this.showMode(-2);
                                  var which = this.o.todayBtn === 'linked' ? null : 'view';
                                  this._setDate(date, which);
                                  break;
                              case 'clear':
                                  var element;
                                  if (this.isInput)
                                      element = this.element;
                                  else if (this.component)
                                      element = this.element.find('input');
                                  if (element)
                                      element.val("").change();
                                  this.update();
                                  this._trigger('changeDate');
                                  if (this.o.autoclose)
                                      this.hide();
                                  break;
                          }
                          break;
                      case 'span':
                          if (!target.is('.disabled')) {
                              this.viewDate.setUTCDate(1);
                              if (target.is('.month')) {
                                  day = 1;
                                  month = target.parent().find('span').index(target);
                                  year = this.viewDate.getUTCFullYear();
                                  this.viewDate.setUTCMonth(month);
                                  this._trigger('changeMonth', this.viewDate);
                                  if (this.o.minViewMode === 1) {
                                      this._setDate(UTCDate(year, month, day));
                                  }
                              } else {
                                  day = 1;
                                  month = 0;
                                  year = parseInt(target.text(), 10) || 0;
                                  this.viewDate.setUTCFullYear(year);
                                  this._trigger('changeYear', this.viewDate);
                                  if (this.o.minViewMode === 2) {
                                      this._setDate(UTCDate(year, month, day));
                                  }
                              }
                              this.showMode(-1);
                              this.fill();
                          }
                          break;
                      case 'td':
                          if (target.is('.day') && !target.is('.disabled')) {
                              day = parseInt(target.text(), 10) || 1;
                              year = this.viewDate.getUTCFullYear();
                              month = this.viewDate.getUTCMonth();
                              if (target.is('.old')) {
                                  if (month === 0) {
                                      month = 11;
                                      year -= 1;
                                  } else {
                                      month -= 1;
                                  }
                              } else if (target.is('.new')) {
                                  if (month === 11) {
                                      month = 0;
                                      year += 1;
                                  } else {
                                      month += 1;
                                  }
                              }
                              this._setDate(UTCDate(year, month, day));
                          }
                          break;
                  }
              }
              if (this.picker.is(':visible') && this._focused_from) {
                  $(this._focused_from).focus();
              }
              delete this._focused_from;
          },
  
          _toggle_multidate: function(date) {
              var ix = this.dates.contains(date);
              if (!date) {
                  this.dates.clear();
              } else if (ix !== -1) {
                  this.dates.remove(ix);
              } else {
                  this.dates.push(date);
              }
              if (typeof this.o.multidate === 'number')
                  while (this.dates.length > this.o.multidate)
                      this.dates.remove(0);
          },
  
          _setDate: function(date, which) {
              if (!which || which === 'date')
                  this._toggle_multidate(date && new Date(date));
              if (!which || which === 'view')
                  this.viewDate = date && new Date(date);
  
              this.fill();
              this.setValue();
              this._trigger('changeDate');
              var element;
              if (this.isInput) {
                  element = this.element;
              } else if (this.component) {
                  element = this.element.find('input');
              }
              if (element) {
                  element.change();
              }
              if (this.o.autoclose && (!which || which === 'date')) {
                  this.hide();
              }
          },
  
          moveMonth: function(date, dir) {
              if (!date)
                  return undefined;
              if (!dir)
                  return date;
              var new_date = new Date(date.valueOf()),
                  day = new_date.getUTCDate(),
                  month = new_date.getUTCMonth(),
                  mag = Math.abs(dir),
                  new_month, test;
              dir = dir > 0 ? 1 : -1;
              if (mag === 1) {
                  test = dir === -1
                  // If going back one month, make sure month is not current month
                  // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
                  ? function() {
                      return new_date.getUTCMonth() === month;
                  }
                  // If going forward one month, make sure month is as expected
                  // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
                  : function() {
                      return new_date.getUTCMonth() !== new_month;
                  };
                  new_month = month + dir;
                  new_date.setUTCMonth(new_month);
                  // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
                  if (new_month < 0 || new_month > 11)
                      new_month = (new_month + 12) % 12;
              } else {
                  // For magnitudes >1, move one month at a time...
                  for (var i = 0; i < mag; i++)
                  // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
                      new_date = this.moveMonth(new_date, dir);
                  // ...then reset the day, keeping it in the new month
                  new_month = new_date.getUTCMonth();
                  new_date.setUTCDate(day);
                  test = function() {
                      return new_month !== new_date.getUTCMonth();
                  };
              }
              // Common date-resetting loop -- if date is beyond end of month, make it
              // end of month
              while (test()) {
                  new_date.setUTCDate(--day);
                  new_date.setUTCMonth(new_month);
              }
              return new_date;
          },
  
          moveYear: function(date, dir) {
              return this.moveMonth(date, dir * 12);
          },
  
          dateWithinRange: function(date) {
              return date >= this.o.startDate && date <= this.o.endDate;
          },
  
          keydown: function(e) {
              if (this.picker.is(':not(:visible)')) {
                  if (e.keyCode === 27) // allow escape to hide and re-show picker
                      this.show();
                  return;
              }
              var dateChanged = false,
                  dir, newDate, newViewDate,
                  focusDate = this.focusDate || this.viewDate;
              switch (e.keyCode) {
                  case 27: // escape
                      if (this.focusDate) {
                          this.focusDate = null;
                          this.viewDate = this.dates.get(-1) || this.viewDate;
                          this.fill();
                      } else
                          this.hide();
                      e.preventDefault();
                      break;
                  case 37: // left
                  case 39: // right
                      if (!this.o.keyboardNavigation)
                          break;
                      dir = e.keyCode === 37 ? -1 : 1;
                      if (e.ctrlKey) {
                          newDate = this.moveYear(this.dates.get(-1) || UTCToday(), dir);
                          newViewDate = this.moveYear(focusDate, dir);
                          this._trigger('changeYear', this.viewDate);
                      } else if (e.shiftKey) {
                          newDate = this.moveMonth(this.dates.get(-1) || UTCToday(), dir);
                          newViewDate = this.moveMonth(focusDate, dir);
                          this._trigger('changeMonth', this.viewDate);
                      } else {
                          newDate = new Date(this.dates.get(-1) || UTCToday());
                          newDate.setUTCDate(newDate.getUTCDate() + dir);
                          newViewDate = new Date(focusDate);
                          newViewDate.setUTCDate(focusDate.getUTCDate() + dir);
                      }
                      if (this.dateWithinRange(newDate)) {
                          this.focusDate = this.viewDate = newViewDate;
                          this.setValue();
                          this.fill();
                          e.preventDefault();
                      }
                      break;
                  case 38: // up
                  case 40: // down
                      if (!this.o.keyboardNavigation)
                          break;
                      dir = e.keyCode === 38 ? -1 : 1;
                      if (e.ctrlKey) {
                          newDate = this.moveYear(this.dates.get(-1) || UTCToday(), dir);
                          newViewDate = this.moveYear(focusDate, dir);
                          this._trigger('changeYear', this.viewDate);
                      } else if (e.shiftKey) {
                          newDate = this.moveMonth(this.dates.get(-1) || UTCToday(), dir);
                          newViewDate = this.moveMonth(focusDate, dir);
                          this._trigger('changeMonth', this.viewDate);
                      } else {
                          newDate = new Date(this.dates.get(-1) || UTCToday());
                          newDate.setUTCDate(newDate.getUTCDate() + dir * 7);
                          newViewDate = new Date(focusDate);
                          newViewDate.setUTCDate(focusDate.getUTCDate() + dir * 7);
                      }
                      if (this.dateWithinRange(newDate)) {
                          this.focusDate = this.viewDate = newViewDate;
                          this.setValue();
                          this.fill();
                          e.preventDefault();
                      }
                      break;
                  case 32: // spacebar
                      // Spacebar is used in manually typing dates in some formats.
                      // As such, its behavior should not be hijacked.
                      break;
                  case 13: // enter
                      focusDate = this.focusDate || this.dates.get(-1) || this.viewDate;
                      this._toggle_multidate(focusDate);
                      dateChanged = true;
                      this.focusDate = null;
                      this.viewDate = this.dates.get(-1) || this.viewDate;
                      this.setValue();
                      this.fill();
                      if (this.picker.is(':visible')) {
                          e.preventDefault();
                          if (this.o.autoclose)
                              this.hide();
                      }
                      break;
                  case 9: // tab
                      this.focusDate = null;
                      this.viewDate = this.dates.get(-1) || this.viewDate;
                      this.fill();
                      this.hide();
                      break;
              }
              if (dateChanged) {
                  if (this.dates.length)
                      this._trigger('changeDate');
                  else
                      this._trigger('clearDate');
                  var element;
                  if (this.isInput) {
                      element = this.element;
                  } else if (this.component) {
                      element = this.element.find('input');
                  }
                  if (element) {
                      element.change();
                  }
              }
          },
  
          showMode: function(dir) {
              if (dir) {
                  this.viewMode = Math.max(this.o.minViewMode, Math.min(2, this.viewMode + dir));
              }
              this.picker
                  .find('>div')
                  .hide()
                  .filter('.datepicker-' + DPGlobal.modes[this.viewMode].clsName)
                  .css('display', 'block');
              this.updateNavArrows();
          }
      };
  
      var DateRangePicker = function(element, options) {
          this.element = $(element);
          this.inputs = $.map(options.inputs, function(i) {
              return i.jquery ? i[0] : i;
          });
          delete options.inputs;
  
          $(this.inputs)
              .datepicker(options)
              .bind('changeDate', $.proxy(this.dateUpdated, this));
  
          this.pickers = $.map(this.inputs, function(i) {
              return $(i).data('datepicker');
          });
          this.updateDates();
      };
      DateRangePicker.prototype = {
          updateDates: function() {
              this.dates = $.map(this.pickers, function(i) {
                  return i.getUTCDate();
              });
              this.updateRanges();
          },
          updateRanges: function() {
              var range = $.map(this.dates, function(d) {
                  return d.valueOf();
              });
              $.each(this.pickers, function(i, p) {
                  p.setRange(range);
              });
          },
          dateUpdated: function(e) {
              // `this.updating` is a workaround for preventing infinite recursion
              // between `changeDate` triggering and `setUTCDate` calling.  Until
              // there is a better mechanism.
              if (this.updating)
                  return;
              this.updating = true;
  
              var dp = $(e.target).data('datepicker'),
                  new_date = dp.getUTCDate(),
                  i = $.inArray(e.target, this.inputs),
                  l = this.inputs.length;
              if (i === -1)
                  return;
  
              $.each(this.pickers, function(i, p) {
                  if (!p.getUTCDate())
                      p.setUTCDate(new_date);
              });
  
              if (new_date < this.dates[i]) {
                  // Date being moved earlier/left
                  while (i >= 0 && new_date < this.dates[i]) {
                      this.pickers[i--].setUTCDate(new_date);
                  }
              } else if (new_date > this.dates[i]) {
                  // Date being moved later/right
                  while (i < l && new_date > this.dates[i]) {
                      this.pickers[i++].setUTCDate(new_date);
                  }
              }
              this.updateDates();
  
              delete this.updating;
          },
          remove: function() {
              $.map(this.pickers, function(p) {
                  p.remove();
              });
              delete this.element.data().datepicker;
          }
      };
  
      function opts_from_el(el, prefix) {
          // Derive options from element data-attrs
          var data = $(el).data(),
              out = {}, inkey,
              replace = new RegExp('^' + prefix.toLowerCase() + '([A-Z])');
          prefix = new RegExp('^' + prefix.toLowerCase());
  
          function re_lower(_, a) {
              return a.toLowerCase();
          }
          for (var key in data)
              if (prefix.test(key)) {
                  inkey = key.replace(replace, re_lower);
                  out[inkey] = data[key];
              }
          return out;
      }
  
      function opts_from_locale(lang) {
          // Derive options from locale plugins
          var out = {};
          // Check if "de-DE" style date is available, if not language should
          // fallback to 2 letter code eg "de"
          if (!dates[lang]) {
              lang = lang.split('-')[0];
              if (!dates[lang])
                  return;
          }
          var d = dates[lang];
          $.each(locale_opts, function(i, k) {
              if (k in d)
                  out[k] = d[k];
          });
          return out;
      }
  
      var old = $.fn.datepicker;
      $.fn.datepicker = function(option) {
          var args = Array.apply(null, arguments);
          args.shift();
          var internal_return;
          this.each(function() {
              var $this = $(this),
                  data = $this.data('datepicker'),
                  options = typeof option === 'object' && option;
              if (!data) {
                  var elopts = opts_from_el(this, 'date'),
                      // Preliminary otions
                      xopts = $.extend({}, defaults, elopts, options),
                      locopts = opts_from_locale(xopts.language),
                      // Options priority: js args, data-attrs, locales, defaults
                      opts = $.extend({}, defaults, locopts, elopts, options);
                  if ($this.is('.input-daterange') || opts.inputs) {
                      var ropts = {
                          inputs: opts.inputs || $this.find('input[name="start"], input[name="end"]').toArray()
                      };
                      $this.data('datepicker', (data = new DateRangePicker(this, $.extend(opts, ropts))));
                  } else {
                      $this.data('datepicker', (data = new Datepicker(this, opts)));
                  }
              }
              if (typeof option === 'string' && typeof data[option] === 'function') {
                  internal_return = data[option].apply(data, args);
                  if (internal_return !== undefined)
                      return false;
              }
          });
          if (internal_return !== undefined)
              return internal_return;
          else
              return this;
      };
  
      var defaults = $.fn.datepicker.defaults = {
          autoclose: true,
          beforeShowDay: $.noop,
          calendarWeeks: false,
          clearBtn: false,
          daysOfWeekDisabled: [],
          endDate: Infinity,
          forceParse: true,
          format: 'mm/dd/yyyy',
          keyboardNavigation: true,
          language: 'en',
          minViewMode: 0,
          multidate: false,
          multidateSeparator: ',',
          orientation: "auto",
          rtl: false,
          startDate: -Infinity,
          startView: 0,
          todayBtn: false,
          todayHighlight: false,
          weekStart: 0
      };
      var locale_opts = $.fn.datepicker.locale_opts = [
          'format',
          'rtl',
          'weekStart'
      ];
      $.fn.datepicker.Constructor = Datepicker;
      var dates = $.fn.datepicker.dates = {
          en: {
              days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
              daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
              daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
              months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
              monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
              today: "Today",
              clear: "Clear"
          }
      };
  
      var DPGlobal = {
          modes: [{
              clsName: 'days',
              navFnc: 'Month',
              navStep: 1
          }, {
              clsName: 'months',
              navFnc: 'FullYear',
              navStep: 1
          }, {
              clsName: 'years',
              navFnc: 'FullYear',
              navStep: 10
          }],
          isLeapYear: function(year) {
              return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0));
          },
          getDaysInMonth: function(year, month) {
              return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
          },
          validParts: /dd?|DD?|mm?|MM?|yy(?:yy)?/g,
          nonpunctuation: /[^ -\/:-@\[\u3400-\u9fff-`{-~\t\n\r]+/g,
          parseFormat: function(format) {
              // IE treats \0 as a string end in inputs (truncating the value),
              // so it's a bad format delimiter, anyway
              var separators = format.replace(this.validParts, '\0').split('\0'),
                  parts = format.match(this.validParts);
              if (!separators || !separators.length || !parts || parts.length === 0) {
                  throw new Error("Invalid date format.");
              }
              return {
                  separators: separators,
                  parts: parts
              };
          },
          parseDate: function(date, format, language) {
              if (!date)
                  return undefined;
              if (date instanceof Date)
                  return date;
              if (typeof format === 'string')
                  format = DPGlobal.parseFormat(format);
              var part_re = /([\-+]\d+)([dmwy])/,
                  parts = date.match(/([\-+]\d+)([dmwy])/g),
                  part, dir, i;
              if (/^[\-+]\d+[dmwy]([\s,]+[\-+]\d+[dmwy])*$/.test(date)) {
                  date = new Date();
                  for (i = 0; i < parts.length; i++) {
                      part = part_re.exec(parts[i]);
                      dir = parseInt(part[1]);
                      switch (part[2]) {
                          case 'd':
                              date.setUTCDate(date.getUTCDate() + dir);
                              break;
                          case 'm':
                              date = Datepicker.prototype.moveMonth.call(Datepicker.prototype, date, dir);
                              break;
                          case 'w':
                              date.setUTCDate(date.getUTCDate() + dir * 7);
                              break;
                          case 'y':
                              date = Datepicker.prototype.moveYear.call(Datepicker.prototype, date, dir);
                              break;
                      }
                  }
                  return UTCDate(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), 0, 0, 0);
              }
              parts = date && date.match(this.nonpunctuation) || [];
              date = new Date();
              var parsed = {},
                  setters_order = ['yyyy', 'yy', 'M', 'MM', 'm', 'mm', 'd', 'dd'],
                  setters_map = {
                      yyyy: function(d, v) {
                          return d.setUTCFullYear(v);
                      },
                      yy: function(d, v) {
                          return d.setUTCFullYear(2000 + v);
                      },
                      m: function(d, v) {
                          if (isNaN(d))
                              return d;
                          v -= 1;
                          while (v < 0) v += 12;
                          v %= 12;
                          d.setUTCMonth(v);
                          while (d.getUTCMonth() !== v)
                              d.setUTCDate(d.getUTCDate() - 1);
                          return d;
                      },
                      d: function(d, v) {
                          return d.setUTCDate(v);
                      }
                  },
                  val, filtered;
              setters_map['M'] = setters_map['MM'] = setters_map['mm'] = setters_map['m'];
              setters_map['dd'] = setters_map['d'];
              date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
              var fparts = format.parts.slice();
              // Remove noop parts
              if (parts.length !== fparts.length) {
                  fparts = $(fparts).filter(function(i, p) {
                      return $.inArray(p, setters_order) !== -1;
                  }).toArray();
              }
              // Process remainder
              function match_part() {
                  var m = this.slice(0, parts[i].length),
                      p = parts[i].slice(0, m.length);
                  return m === p;
              }
              if (parts.length === fparts.length) {
                  var cnt;
                  for (i = 0, cnt = fparts.length; i < cnt; i++) {
                      val = parseInt(parts[i], 10);
                      part = fparts[i];
                      if (isNaN(val)) {
                          switch (part) {
                              case 'MM':
                                  filtered = $(dates[language].months).filter(match_part);
                                  val = $.inArray(filtered[0], dates[language].months) + 1;
                                  break;
                              case 'M':
                                  filtered = $(dates[language].monthsShort).filter(match_part);
                                  val = $.inArray(filtered[0], dates[language].monthsShort) + 1;
                                  break;
                          }
                      }
                      parsed[part] = val;
                  }
                  var _date, s;
                  for (i = 0; i < setters_order.length; i++) {
                      s = setters_order[i];
                      if (s in parsed && !isNaN(parsed[s])) {
                          _date = new Date(date);
                          setters_map[s](_date, parsed[s]);
                          if (!isNaN(_date))
                              date = _date;
                      }
                  }
              }
              return date;
          },
          formatDate: function(date, format, language) {
              if (!date)
                  return '';
              if (typeof format === 'string')
                  format = DPGlobal.parseFormat(format);
              var val = {
                  d: date.getUTCDate(),
                  D: dates[language].daysShort[date.getUTCDay()],
                  DD: dates[language].days[date.getUTCDay()],
                  m: date.getUTCMonth() + 1,
                  M: dates[language].monthsShort[date.getUTCMonth()],
                  MM: dates[language].months[date.getUTCMonth()],
                  yy: date.getUTCFullYear().toString().substring(2),
                  yyyy: date.getUTCFullYear()
              };
              val.dd = (val.d < 10 ? '0' : '') + val.d;
              val.mm = (val.m < 10 ? '0' : '') + val.m;
              date = [];
              var seps = $.extend([], format.separators);
              for (var i = 0, cnt = format.parts.length; i <= cnt; i++) {
                  if (seps.length)
                      date.push(seps.shift());
                  date.push(val[format.parts[i]]);
              }
              return date.join('');
          },
          headTemplate: '<thead>' +
              '<tr>' +
              '<th class="prev"></th>' +
              '<th colspan="5" class="datepicker-switch"></th>' +
              '<th class="next"></th>' +
              '</tr>' +
              '</thead>',
          contTemplate: '<tbody><tr><td colspan="7"></td></tr></tbody>',
          footTemplate: '<tfoot>' +
              '<tr>' +
              '<th colspan="7" class="today"></th>' +
              '</tr>' +
              '<tr>' +
              '<th colspan="7" class="clear"></th>' +
              '</tr>' +
              '</tfoot>'
      };
      DPGlobal.template = '<div class="datepicker">' +
          '<div class="datepicker-days">' +
          '<table class=" table-condensed">' +
          DPGlobal.headTemplate +
          '<tbody></tbody>' +
          DPGlobal.footTemplate +
          '</table>' +
          '</div>' +
          '<div class="datepicker-months">' +
          '<table class="table-condensed">' +
          DPGlobal.headTemplate +
          DPGlobal.contTemplate +
          DPGlobal.footTemplate +
          '</table>' +
          '</div>' +
          '<div class="datepicker-years">' +
          '<table class="table-condensed">' +
          DPGlobal.headTemplate +
          DPGlobal.contTemplate +
          DPGlobal.footTemplate +
          '</table>' +
          '</div>' +
          '</div>';
  
      $.fn.datepicker.DPGlobal = DPGlobal;
  
  
      /* DATEPICKER NO CONFLICT
       * =================== */
  
      $.fn.datepicker.noConflict = function() {
          $.fn.datepicker = old;
          return this;
      };
  
  
      /* DATEPICKER DATA-API
       * ================== */
  
      $(document).on(
          'focus.datepicker.data-api click.datepicker.data-api',
          '[data-provide="datepicker"]',
          function(e) {
              var $this = $(this);
              if ($this.data('datepicker'))
                  return;
              e.preventDefault();
              // component click requires us to explicitly show it
              $this.datepicker('show');
          }
      );
      $(function() {
          $('[data-provide="datepicker-inline"]').datepicker();
      });
  
  }(window.jQuery));
  
  /* ====================================================================================================
    Timepicker Component for Twitter Bootstrap
  ==================================================================================================== */
  /*!
   * Timepicker Component for Twitter Bootstrap
   *
   * Copyright 2013 Joris de Wit
   *
   * Contributors https://github.com/jdewit/bootstrap-timepicker/graphs/contributors
   *
   * For the full copyright and license information, please view the LICENSE
   * file that was distributed with this source code.
   */
  (function($, window, document, undefined) {
      'use strict';
  
      // TIMEPICKER PUBLIC CLASS DEFINITION
      var Timepicker = function(element, options) {
          this.widget = '';
          this.$element = $(element);
          this.defaultTime = options.defaultTime;
          this.disableFocus = options.disableFocus;
          this.disableMousewheel = options.disableMousewheel;
          this.isOpen = options.isOpen;
          this.minuteStep = options.minuteStep;
          this.modalBackdrop = options.modalBackdrop;
          this.orientation = options.orientation;
          this.secondStep = options.secondStep;
          this.showInputs = options.showInputs;
          this.showMeridian = options.showMeridian;
          this.showSeconds = options.showSeconds;
          this.template = options.template;
          this.appendWidgetTo = options.appendWidgetTo;
          this.showWidgetOnAddonClick = options.showWidgetOnAddonClick;
  
          this._init();
      };
  
      Timepicker.prototype = {
  
          constructor: Timepicker,
          _init: function() {
              var self = this;
  
              if (this.showWidgetOnAddonClick && (this.$element.parent().hasClass('input-append') || this.$element.parent().hasClass('input-prepend'))) {
                  this.$element.parent('.input-append, .input-prepend').find('.add-on').on({
                      'click.timepicker': $.proxy(this.showWidget, this)
                  });
                  this.$element.on({
                      'focus.timepicker': $.proxy(this.highlightUnit, this),
                      'click.timepicker': $.proxy(this.highlightUnit, this),
                      'keydown.timepicker': $.proxy(this.elementKeydown, this),
                      'blur.timepicker': $.proxy(this.blurElement, this),
                      'mousewheel.timepicker DOMMouseScroll.timepicker': $.proxy(this.mousewheel, this)
                  });
              } else {
                  if (this.template) {
                      this.$element.on({
                          'focus.timepicker': $.proxy(this.showWidget, this),
                          'click.timepicker': $.proxy(this.showWidget, this),
                          'blur.timepicker': $.proxy(this.blurElement, this),
                          'mousewheel.timepicker DOMMouseScroll.timepicker': $.proxy(this.mousewheel, this)
                      });
                  } else {
                      this.$element.on({
                          'focus.timepicker': $.proxy(this.highlightUnit, this),
                          'click.timepicker': $.proxy(this.highlightUnit, this),
                          'keydown.timepicker': $.proxy(this.elementKeydown, this),
                          'blur.timepicker': $.proxy(this.blurElement, this),
                          'mousewheel.timepicker DOMMouseScroll.timepicker': $.proxy(this.mousewheel, this)
                      });
                  }
              }
  
              if (this.template !== false) {
                  this.$widget = $(this.getTemplate()).on('click', $.proxy(this.widgetClick, this));
              } else {
                  this.$widget = false;
              }
  
              if (this.showInputs && this.$widget !== false) {
                  this.$widget.find('input').each(function() {
                      $(this).on({
                          'click.timepicker': function() {
                              $(this).select();
                          },
                          'keydown.timepicker': $.proxy(self.widgetKeydown, self),
                          'keyup.timepicker': $.proxy(self.widgetKeyup, self)
                      });
                  });
              }
  
              this.setDefaultTime(this.defaultTime);
          },
  
          blurElement: function() {
              this.highlightedUnit = null;
              this.updateFromElementVal();
          },
  
          clear: function() {
              this.hour = '';
              this.minute = '';
              this.second = '';
              this.meridian = '';
  
              this.$element.val('');
          },
  
          decrementHour: function() {
              if (this.showMeridian) {
                  if (this.hour === 1) {
                      this.hour = 12;
                  } else if (this.hour === 12) {
                      this.hour--;
  
                      return this.toggleMeridian();
                  } else if (this.hour === 0) {
                      this.hour = 11;
  
                      return this.toggleMeridian();
                  } else {
                      this.hour--;
                  }
              } else {
                  if (this.hour <= 0) {
                      this.hour = 23;
                  } else {
                      this.hour--;
                  }
              }
          },
  
          decrementMinute: function(step) {
              var newVal;
  
              if (step) {
                  newVal = this.minute - step;
              } else {
                  newVal = this.minute - this.minuteStep;
              }
  
              if (newVal < 0) {
                  this.decrementHour();
                  this.minute = newVal + 60;
              } else {
                  this.minute = newVal;
              }
          },
  
          decrementSecond: function() {
              var newVal = this.second - this.secondStep;
  
              if (newVal < 0) {
                  this.decrementMinute(true);
                  this.second = newVal + 60;
              } else {
                  this.second = newVal;
              }
          },
  
          elementKeydown: function(e) {
              switch (e.keyCode) {
                  case 9: //tab
                  case 27: // escape
                      this.updateFromElementVal();
                      break;
                  case 37: // left arrow
                      e.preventDefault();
                      this.highlightPrevUnit();
                      break;
                  case 38: // up arrow
                      e.preventDefault();
                      switch (this.highlightedUnit) {
                          case 'hour':
                              this.incrementHour();
                              this.highlightHour();
                              break;
                          case 'minute':
                              this.incrementMinute();
                              this.highlightMinute();
                              break;
                          case 'second':
                              this.incrementSecond();
                              this.highlightSecond();
                              break;
                          case 'meridian':
                              this.toggleMeridian();
                              this.highlightMeridian();
                              break;
                      }
                      this.update();
                      break;
                  case 39: // right arrow
                      e.preventDefault();
                      this.highlightNextUnit();
                      break;
                  case 40: // down arrow
                      e.preventDefault();
                      switch (this.highlightedUnit) {
                          case 'hour':
                              this.decrementHour();
                              this.highlightHour();
                              break;
                          case 'minute':
                              this.decrementMinute();
                              this.highlightMinute();
                              break;
                          case 'second':
                              this.decrementSecond();
                              this.highlightSecond();
                              break;
                          case 'meridian':
                              this.toggleMeridian();
                              this.highlightMeridian();
                              break;
                      }
  
                      this.update();
                      break;
              }
          },
  
          getCursorPosition: function() {
              var input = this.$element.get(0);
  
              if ('selectionStart' in input) { // Standard-compliant browsers
  
                  return input.selectionStart;
              } else if (document.selection) { // IE fix
                  input.focus();
                  var sel = document.selection.createRange(),
                      selLen = document.selection.createRange().text.length;
  
                  sel.moveStart('character', -input.value.length);
  
                  return sel.text.length - selLen;
              }
          },
  
          getTemplate: function() {
              var template,
                  hourTemplate,
                  minuteTemplate,
                  secondTemplate,
                  meridianTemplate,
                  templateContent;
  
              if (this.showInputs) {
                  hourTemplate = '<input type="text" class="bootstrap-timepicker-hour" maxlength="2"/>';
                  minuteTemplate = '<input type="text" class="bootstrap-timepicker-minute" maxlength="2"/>';
                  secondTemplate = '<input type="text" class="bootstrap-timepicker-second" maxlength="2"/>';
                  meridianTemplate = '<input type="text" class="bootstrap-timepicker-meridian" maxlength="2"/>';
              } else {
                  hourTemplate = '<span class="bootstrap-timepicker-hour"></span>';
                  minuteTemplate = '<span class="bootstrap-timepicker-minute"></span>';
                  secondTemplate = '<span class="bootstrap-timepicker-second"></span>';
                  meridianTemplate = '<span class="bootstrap-timepicker-meridian"></span>';
              }
  
              templateContent = '<table>' +
                  '<tr>' +
                  '<td><a href="#" data-action="incrementHour"><i class="icon-up-open-big"></i></a></td>' +
                  '<td class="separator">&nbsp;</td>' +
                  '<td><a href="#" data-action="incrementMinute"><i class="icon-up-open-big"></i></a></td>' +
                  (this.showSeconds ?
                  '<td class="separator">&nbsp;</td>' +
                  '<td><a href="#" data-action="incrementSecond"><i class="icon-up-open-big"></i></a></td>' : '') +
                  (this.showMeridian ?
                  '<td class="separator">&nbsp;</td>' +
                  '<td class="meridian-column"><a href="#" data-action="toggleMeridian"><i class="icon-up-open-big"></i></a></td>' : '') +
                  '</tr>' +
                  '<tr>' +
                  '<td>' + hourTemplate + '</td> ' +
                  '<td class="separator">:</td>' +
                  '<td>' + minuteTemplate + '</td> ' +
                  (this.showSeconds ?
                  '<td class="separator">:</td>' +
                  '<td>' + secondTemplate + '</td>' : '') +
                  (this.showMeridian ?
                  '<td class="separator">&nbsp;</td>' +
                  '<td>' + meridianTemplate + '</td>' : '') +
                  '</tr>' +
                  '<tr>' +
                  '<td><a href="#" data-action="decrementHour"><i class="icon-down-open-big"></i></a></td>' +
                  '<td class="separator"></td>' +
                  '<td><a href="#" data-action="decrementMinute"><i class="icon-down-open-big"></i></a></td>' +
                  (this.showSeconds ?
                  '<td class="separator">&nbsp;</td>' +
                  '<td><a href="#" data-action="decrementSecond"><i class="icon-down-open-big"></i></a></td>' : '') +
                  (this.showMeridian ?
                  '<td class="separator">&nbsp;</td>' +
                  '<td><a href="#" data-action="toggleMeridian"><i class="icon-down-open-big"></i></a></td>' : '') +
                  '</tr>' +
                  '</table>';
  
              switch (this.template) {
                  case 'modal':
                      template = '<div class="bootstrap-timepicker-widget modal hide fade in" data-backdrop="' + (this.modalBackdrop ? 'true' : 'false') + '">' +
                          '<div class="modal-header">' +
                          '<a href="#" class="close" data-dismiss="modal">×</a>' +
                          '<h3>Pick a Time</h3>' +
                          '</div>' +
                          '<div class="modal-content">' +
                          templateContent +
                          '</div>' +
                          '<div class="modal-footer">' +
                          '<a href="#" class="btn btn-primary" data-dismiss="modal">OK</a>' +
                          '</div>' +
                          '</div>';
                      break;
                  case 'dropdown':
                      template = '<div class="bootstrap-timepicker-widget dropdown-menu">' + templateContent + '</div>';
                      break;
              }
  
              return template;
          },
  
          getTime: function() {
              if (this.hour === '') {
                  return '';
              }
  
              return this.hour + ':' + (this.minute.toString().length === 1 ? '0' + this.minute : this.minute) + (this.showSeconds ? ':' + (this.second.toString().length === 1 ? '0' + this.second : this.second) : '') + (this.showMeridian ? ' ' + this.meridian : '');
          },
  
          hideWidget: function() {
              if (this.isOpen === false) {
                  return;
              }
  
              this.$element.trigger({
                  'type': 'hide.timepicker',
                  'time': {
                      'value': this.getTime(),
                      'hours': this.hour,
                      'minutes': this.minute,
                      'seconds': this.second,
                      'meridian': this.meridian
                  }
              });
  
              if (this.template === 'modal' && this.$widget.modal) {
                  this.$widget.modal('hide');
              } else {
                  this.$widget.removeClass('open');
              }
  
              $(document).off('mousedown.timepicker, touchend.timepicker');
  
              this.isOpen = false;
              // show/hide approach taken by datepicker
              this.$widget.detach();
          },
  
          highlightUnit: function() {
              this.position = this.getCursorPosition();
              if (this.position >= 0 && this.position <= 2) {
                  this.highlightHour();
              } else if (this.position >= 3 && this.position <= 5) {
                  this.highlightMinute();
              } else if (this.position >= 6 && this.position <= 8) {
                  if (this.showSeconds) {
                      this.highlightSecond();
                  } else {
                      this.highlightMeridian();
                  }
              } else if (this.position >= 9 && this.position <= 11) {
                  this.highlightMeridian();
              }
          },
  
          highlightNextUnit: function() {
              switch (this.highlightedUnit) {
                  case 'hour':
                      this.highlightMinute();
                      break;
                  case 'minute':
                      if (this.showSeconds) {
                          this.highlightSecond();
                      } else if (this.showMeridian) {
                          this.highlightMeridian();
                      } else {
                          this.highlightHour();
                      }
                      break;
                  case 'second':
                      if (this.showMeridian) {
                          this.highlightMeridian();
                      } else {
                          this.highlightHour();
                      }
                      break;
                  case 'meridian':
                      this.highlightHour();
                      break;
              }
          },
  
          highlightPrevUnit: function() {
              switch (this.highlightedUnit) {
                  case 'hour':
                      if (this.showMeridian) {
                          this.highlightMeridian();
                      } else if (this.showSeconds) {
                          this.highlightSecond();
                      } else {
                          this.highlightMinute();
                      }
                      break;
                  case 'minute':
                      this.highlightHour();
                      break;
                  case 'second':
                      this.highlightMinute();
                      break;
                  case 'meridian':
                      if (this.showSeconds) {
                          this.highlightSecond();
                      } else {
                          this.highlightMinute();
                      }
                      break;
              }
          },
  
          highlightHour: function() {
              var $element = this.$element.get(0),
                  self = this;
  
              this.highlightedUnit = 'hour';
  
              if ($element.setSelectionRange) {
                  setTimeout(function() {
                      if (self.hour < 10) {
                          $element.setSelectionRange(0, 1);
                      } else {
                          $element.setSelectionRange(0, 2);
                      }
                  }, 0);
              }
          },
  
          highlightMinute: function() {
              var $element = this.$element.get(0),
                  self = this;
  
              this.highlightedUnit = 'minute';
  
              if ($element.setSelectionRange) {
                  setTimeout(function() {
                      if (self.hour < 10) {
                          $element.setSelectionRange(2, 4);
                      } else {
                          $element.setSelectionRange(3, 5);
                      }
                  }, 0);
              }
          },
  
          highlightSecond: function() {
              var $element = this.$element.get(0),
                  self = this;
  
              this.highlightedUnit = 'second';
  
              if ($element.setSelectionRange) {
                  setTimeout(function() {
                      if (self.hour < 10) {
                          $element.setSelectionRange(5, 7);
                      } else {
                          $element.setSelectionRange(6, 8);
                      }
                  }, 0);
              }
          },
  
          highlightMeridian: function() {
              var $element = this.$element.get(0),
                  self = this;
  
              this.highlightedUnit = 'meridian';
  
              if ($element.setSelectionRange) {
                  if (this.showSeconds) {
                      setTimeout(function() {
                          if (self.hour < 10) {
                              $element.setSelectionRange(8, 10);
                          } else {
                              $element.setSelectionRange(9, 11);
                          }
                      }, 0);
                  } else {
                      setTimeout(function() {
                          if (self.hour < 10) {
                              $element.setSelectionRange(5, 7);
                          } else {
                              $element.setSelectionRange(6, 8);
                          }
                      }, 0);
                  }
              }
          },
  
          incrementHour: function() {
              if (this.showMeridian) {
                  if (this.hour === 11) {
                      this.hour++;
                      return this.toggleMeridian();
                  } else if (this.hour === 12) {
                      this.hour = 0;
                  }
              }
              if (this.hour === 23) {
                  this.hour = 0;
  
                  return;
              }
              this.hour++;
          },
  
          incrementMinute: function(step) {
              var newVal;
  
              if (step) {
                  newVal = this.minute + step;
              } else {
                  newVal = this.minute + this.minuteStep - (this.minute % this.minuteStep);
              }
  
              if (newVal > 59) {
                  this.incrementHour();
                  this.minute = newVal - 60;
              } else {
                  this.minute = newVal;
              }
          },
  
          incrementSecond: function() {
              var newVal = this.second + this.secondStep - (this.second % this.secondStep);
  
              if (newVal > 59) {
                  this.incrementMinute(true);
                  this.second = newVal - 60;
              } else {
                  this.second = newVal;
              }
          },
  
          mousewheel: function(e) {
              if (this.disableMousewheel) {
                  return;
              }
  
              e.preventDefault();
              e.stopPropagation();
  
              var delta = e.originalEvent.wheelDelta || -e.originalEvent.detail,
                  scrollTo = null;
  
              if (e.type === 'mousewheel') {
                  scrollTo = (e.originalEvent.wheelDelta * -1);
              } else if (e.type === 'DOMMouseScroll') {
                  scrollTo = 40 * e.originalEvent.detail;
              }
  
              if (scrollTo) {
                  e.preventDefault();
                  $(this).scrollTop(scrollTo + $(this).scrollTop());
              }
  
              switch (this.highlightedUnit) {
                  case 'minute':
                      if (delta > 0) {
                          this.incrementMinute();
                      } else {
                          this.decrementMinute();
                      }
                      this.highlightMinute();
                      break;
                  case 'second':
                      if (delta > 0) {
                          this.incrementSecond();
                      } else {
                          this.decrementSecond();
                      }
                      this.highlightSecond();
                      break;
                  case 'meridian':
                      this.toggleMeridian();
                      this.highlightMeridian();
                      break;
                  default:
                      if (delta > 0) {
                          this.incrementHour();
                      } else {
                          this.decrementHour();
                      }
                      this.highlightHour();
                      break;
              }
  
              return false;
          },
  
          // This method was adapted from bootstrap-datepicker.
          place: function() {
              if (this.isInline) {
                  return;
              }
              var widgetWidth = this.$widget.outerWidth(),
                  widgetHeight = this.$widget.outerHeight(),
                  visualPadding = 10,
                  windowWidth =
                      $(window).width(),
                  windowHeight = $(window).height(),
                  scrollTop = $(window).scrollTop();
  
              var zIndex = parseInt(this.$element.parents().filter(function() {}).first().css('z-index'), 10) + 10;
              var offset = this.component ? this.component.parent().offset() : this.$element.offset();
              var height = this.component ? this.component.outerHeight(true) : this.$element.outerHeight(false);
              var width = this.component ? this.component.outerWidth(true) : this.$element.outerWidth(false);
              var left = offset.left,
                  top = offset.top;
  
              this.$widget.removeClass('timepicker-orient-top timepicker-orient-bottom timepicker-orient-right timepicker-orient-left');
  
              if (this.orientation.x !== 'auto') {
                  this.picker.addClass('datepicker-orient-' + this.orientation.x);
                  if (this.orientation.x === 'right') {
                      left -= widgetWidth - width;
                  }
              } else {
                  // auto x orientation is best-placement: if it crosses a window edge, fudge it sideways
                  // Default to left
                  this.$widget.addClass('timepicker-orient-left');
                  if (offset.left < 0) {
                      left -= offset.left - visualPadding;
                  } else if (offset.left + widgetWidth > windowWidth) {
                      left = windowWidth - widgetWidth - visualPadding;
                  }
              }
              // auto y orientation is best-situation: top or bottom, no fudging, decision based on which shows more of the widget
              var yorient = this.orientation.y,
                  topOverflow, bottomOverflow;
              if (yorient === 'auto') {
                  topOverflow = -scrollTop + offset.top - widgetHeight;
                  bottomOverflow = scrollTop + windowHeight - (offset.top + height + widgetHeight);
                  if (Math.max(topOverflow, bottomOverflow) === bottomOverflow) {
                      yorient = 'top';
                  } else {
                      yorient = 'bottom';
                  }
              }
              this.$widget.addClass('timepicker-orient-' + yorient);
              if (yorient === 'top') {
                  top += height;
              } else {
                  top -= widgetHeight + parseInt(this.$widget.css('padding-top'), 10);
              }
  
              this.$widget.css({
                  top: top,
                  left: left,
                  zIndex: zIndex
              });
          },
  
          remove: function() {
              $('document').off('.timepicker');
              if (this.$widget) {
                  this.$widget.remove();
              }
              delete this.$element.data().timepicker;
          },
  
          setDefaultTime: function(defaultTime) {
              if (!this.$element.val()) {
                  if (defaultTime === 'current') {
                      var dTime = new Date(),
                          hours = dTime.getHours(),
                          minutes = dTime.getMinutes(),
                          seconds = dTime.getSeconds(),
                          meridian = 'AM';
  
                      if (seconds !== 0) {
                          seconds = Math.ceil(dTime.getSeconds() / this.secondStep) * this.secondStep;
                          if (seconds === 60) {
                              minutes += 1;
                              seconds = 0;
                          }
                      }
  
                      if (minutes !== 0) {
                          minutes = Math.ceil(dTime.getMinutes() / this.minuteStep) * this.minuteStep;
                          if (minutes === 60) {
                              hours += 1;
                              minutes = 0;
                          }
                      }
  
                      if (this.showMeridian) {
                          if (hours === 0) {
                              hours = 12;
                          } else if (hours >= 12) {
                              if (hours > 12) {
                                  hours = hours - 12;
                              }
                              meridian = 'PM';
                          } else {
                              meridian = 'AM';
                          }
                      }
  
                      this.hour = hours;
                      this.minute = minutes;
                      this.second = seconds;
                      this.meridian = meridian;
  
                      this.update();
  
                  } else if (defaultTime === false) {
                      this.hour = 0;
                      this.minute = 0;
                      this.second = 0;
                      this.meridian = 'AM';
                  } else {
                      this.setTime(defaultTime);
                  }
              } else {
                  this.updateFromElementVal();
              }
          },
  
          setTime: function(time, ignoreWidget) {
              if (!time) {
                  this.clear();
                  return;
              }
  
              var timeArray,
                  hour,
                  minute,
                  second,
                  meridian;
  
              if (typeof time === 'object' && time.getMonth) {
                  // this is a date object
                  hour = time.getHours();
                  minute = time.getMinutes();
                  second = time.getSeconds();
  
                  if (this.showMeridian) {
                      meridian = 'AM';
                      if (hour > 12) {
                          meridian = 'PM';
                          hour = hour % 12;
                      }
  
                      if (hour === 12) {
                          meridian = 'PM';
                      }
                  }
              } else {
                  if (time.match(/p/i) !== null) {
                      meridian = 'PM';
                  } else {
                      meridian = 'AM';
                  }
  
                  time = time.replace(/[^0-9\:]/g, '');
  
                  timeArray = time.split(':');
  
                  hour = timeArray[0] ? timeArray[0].toString() : timeArray.toString();
                  minute = timeArray[1] ? timeArray[1].toString() : '';
                  second = timeArray[2] ? timeArray[2].toString() : '';
  
                  // idiot proofing
                  if (hour.length > 4) {
                      second = hour.substr(4, 2);
                  }
                  if (hour.length > 2) {
                      minute = hour.substr(2, 2);
                      hour = hour.substr(0, 2);
                  }
                  if (minute.length > 2) {
                      second = minute.substr(2, 2);
                      minute = minute.substr(0, 2);
                  }
                  if (second.length > 2) {
                      second = second.substr(2, 2);
                  }
  
                  hour = parseInt(hour, 10);
                  minute = parseInt(minute, 10);
                  second = parseInt(second, 10);
  
                  if (isNaN(hour)) {
                      hour = 0;
                  }
                  if (isNaN(minute)) {
                      minute = 0;
                  }
                  if (isNaN(second)) {
                      second = 0;
                  }
  
                  if (this.showMeridian) {
                      if (hour < 1) {
                          hour = 1;
                      } else if (hour > 12) {
                          hour = 12;
                      }
                  } else {
                      if (hour >= 24) {
                          hour = 23;
                      } else if (hour < 0) {
                          hour = 0;
                      }
                      if (hour < 13 && meridian === 'PM') {
                          hour = hour + 12;
                      }
                  }
  
                  if (minute < 0) {
                      minute = 0;
                  } else if (minute >= 60) {
                      minute = 59;
                  }
  
                  if (this.showSeconds) {
                      if (isNaN(second)) {
                          second = 0;
                      } else if (second < 0) {
                          second = 0;
                      } else if (second >= 60) {
                          second = 59;
                      }
                  }
              }
  
              this.hour = hour;
              this.minute = minute;
              this.second = second;
              this.meridian = meridian;
  
              this.update(ignoreWidget);
          },
  
          showWidget: function() {
              if (this.isOpen) {
                  return;
              }
  
              if (this.$element.is(':disabled')) {
                  return;
              }
  
              // show/hide approach taken by datepicker
              this.$widget.appendTo(this.appendWidgetTo);
              var self = this;
              $(document).on('mousedown.timepicker, touchend.timepicker', function(e) {
                  // This condition was inspired by bootstrap-datepicker.
                  // The element the timepicker is invoked on is the input but it has a sibling for addon/button.
                  if (!(self.$element.parent().find(e.target).length ||
                      self.$widget.is(e.target) ||
                      self.$widget.find(e.target).length)) {
                      self.hideWidget();
                  }
              });
  
              this.$element.trigger({
                  'type': 'show.timepicker',
                  'time': {
                      'value': this.getTime(),
                      'hours': this.hour,
                      'minutes': this.minute,
                      'seconds': this.second,
                      'meridian': this.meridian
                  }
              });
  
              this.place();
              if (this.disableFocus) {
                  this.$element.blur();
              }
  
              // widget shouldn't be empty on open
              if (this.hour === '') {
                  if (this.defaultTime) {
                      this.setDefaultTime(this.defaultTime);
                  } else {
                      this.setTime('0:0:0');
                  }
              }
  
              if (this.template === 'modal' && this.$widget.modal) {
                  this.$widget.modal('show').on('hidden', $.proxy(this.hideWidget, this));
              } else {
                  if (this.isOpen === false) {
                      this.$widget.addClass('open');
                  }
              }
  
              this.isOpen = true;
          },
  
          toggleMeridian: function() {
              this.meridian = this.meridian === 'AM' ? 'PM' : 'AM';
          },
  
          update: function(ignoreWidget) {
              this.updateElement();
              if (!ignoreWidget) {
                  this.updateWidget();
              }
  
              this.$element.trigger({
                  'type': 'changeTime.timepicker',
                  'time': {
                      'value': this.getTime(),
                      'hours': this.hour,
                      'minutes': this.minute,
                      'seconds': this.second,
                      'meridian': this.meridian
                  }
              });
          },
  
          updateElement: function() {
              this.$element.val(this.getTime()).change();
          },
  
          updateFromElementVal: function() {
              this.setTime(this.$element.val());
          },
  
          updateWidget: function() {
              if (this.$widget === false) {
                  return;
              }
  
              var hour = this.hour,
                  minute = this.minute.toString().length === 1 ? '0' + this.minute : this.minute,
                  second = this.second.toString().length === 1 ? '0' + this.second : this.second;
  
              if (this.showInputs) {
                  this.$widget.find('input.bootstrap-timepicker-hour').val(hour);
                  this.$widget.find('input.bootstrap-timepicker-minute').val(minute);
  
                  if (this.showSeconds) {
                      this.$widget.find('input.bootstrap-timepicker-second').val(second);
                  }
                  if (this.showMeridian) {
                      this.$widget.find('input.bootstrap-timepicker-meridian').val(this.meridian);
                  }
              } else {
                  this.$widget.find('span.bootstrap-timepicker-hour').text(hour);
                  this.$widget.find('span.bootstrap-timepicker-minute').text(minute);
  
                  if (this.showSeconds) {
                      this.$widget.find('span.bootstrap-timepicker-second').text(second);
                  }
                  if (this.showMeridian) {
                      this.$widget.find('span.bootstrap-timepicker-meridian').text(this.meridian);
                  }
              }
          },
  
          updateFromWidgetInputs: function() {
              if (this.$widget === false) {
                  return;
              }
  
              var t = this.$widget.find('input.bootstrap-timepicker-hour').val() + ':' +
                  this.$widget.find('input.bootstrap-timepicker-minute').val() +
                  (this.showSeconds ? ':' + this.$widget.find('input.bootstrap-timepicker-second').val() : '') +
                  (this.showMeridian ? this.$widget.find('input.bootstrap-timepicker-meridian').val() : '');
  
              this.setTime(t, true);
          },
  
          widgetClick: function(e) {
              e.stopPropagation();
              e.preventDefault();
  
              var $input = $(e.target),
                  action = $input.closest('a').data('action');
  
              if (action) {
                  this[action]();
              }
              this.update();
  
              if ($input.is('input')) {
                  $input.get(0).setSelectionRange(0, 2);
              }
          },
  
          widgetKeydown: function(e) {
              var $input = $(e.target),
                  name = $input.attr('class').replace('bootstrap-timepicker-', '');
  
              switch (e.keyCode) {
                  case 9: //tab
                      if ((this.showMeridian && name === 'meridian') || (this.showSeconds && name === 'second') || (!this.showMeridian && !this.showSeconds && name === 'minute')) {
                          return this.hideWidget();
                      }
                      break;
                  case 27: // escape
                      this.hideWidget();
                      break;
                  case 38: // up arrow
                      e.preventDefault();
                      switch (name) {
                          case 'hour':
                              this.incrementHour();
                              break;
                          case 'minute':
                              this.incrementMinute();
                              break;
                          case 'second':
                              this.incrementSecond();
                              break;
                          case 'meridian':
                              this.toggleMeridian();
                              break;
                      }
                      this.setTime(this.getTime());
                      $input.get(0).setSelectionRange(0, 2);
                      break;
                  case 40: // down arrow
                      e.preventDefault();
                      switch (name) {
                          case 'hour':
                              this.decrementHour();
                              break;
                          case 'minute':
                              this.decrementMinute();
                              break;
                          case 'second':
                              this.decrementSecond();
                              break;
                          case 'meridian':
                              this.toggleMeridian();
                              break;
                      }
                      this.setTime(this.getTime());
                      $input.get(0).setSelectionRange(0, 2);
                      break;
              }
          },
  
          widgetKeyup: function(e) {
              if ((e.keyCode === 65) || (e.keyCode === 77) || (e.keyCode === 80) || (e.keyCode === 46) || (e.keyCode === 8) || (e.keyCode >= 46 && e.keyCode <= 57)) {
                  this.updateFromWidgetInputs();
              }
          }
      };
  
      //TIMEPICKER PLUGIN DEFINITION
      $.fn.timepicker = function(option) {
          var args = Array.apply(null, arguments);
          args.shift();
          return this.each(function() {
              var $this = $(this),
                  data = $this.data('timepicker'),
                  options = typeof option === 'object' && option;
  
              if (!data) {
                  $this.data('timepicker', (data = new Timepicker(this, $.extend({}, $.fn.timepicker.defaults, options, $(this).data()))));
              }
  
              if (typeof option === 'string') {
                  data[option].apply(data, args);
              }
          });
      };
  
      $.fn.timepicker.defaults = {
          defaultTime: 'current',
          disableFocus: false,
          disableMousewheel: false,
          isOpen: false,
          minuteStep: 15,
          modalBackdrop: false,
          orientation: {
              x: 'auto',
              y: 'auto'
          },
          secondStep: 15,
          showSeconds: false,
          showInputs: true,
          showMeridian: true,
          template: 'dropdown',
          appendWidgetTo: 'body',
          showWidgetOnAddonClick: true
      };
  
      $.fn.timepicker.Constructor = Timepicker;
  
  })(jQuery, window, document);
  
  /* ====================================================================================================
    iCheck
  ==================================================================================================== */
  /*!
   * iCheck v1.0.2, http://git.io/arlzeA
   * ===================================
   * Powerful jQuery and Zepto plugin for checkboxes and radio buttons customization
   *
   * (c) 2013 Damir Sultanov, http://fronteed.com
   * MIT Licensed
   */
  
  (function($) {
  
    // Cached vars
    var _iCheck = 'iCheck',
      _iCheckHelper = _iCheck + '-helper',
      _checkbox = 'checkbox',
      _radio = 'radio',
      _checked = 'checked',
      _unchecked = 'un' + _checked,
      _disabled = 'disabled',
      _determinate = 'determinate',
      _indeterminate = 'in' + _determinate,
      _update = 'update',
      _type = 'type',
      _click = 'click',
      _touch = 'touchbegin.i touchend.i',
      _add = 'addClass',
      _remove = 'removeClass',
      _callback = 'trigger',
      _label = 'label',
      _cursor = 'cursor',
      _mobile = /ipad|iphone|ipod|android|blackberry|windows phone|opera mini|silk/i.test(navigator.userAgent);
  
    // Plugin init
    $.fn[_iCheck] = function(options, fire) {
  
      // Walker
      var handle = 'input[type="' + _checkbox + '"], input[type="' + _radio + '"]',
        stack = $(),
        walker = function(object) {
          object.each(function() {
            var self = $(this);
  
            if (self.is(handle)) {
              stack = stack.add(self);
            } else {
              stack = stack.add(self.find(handle));
            }
          });
        };
  
      // Check if we should operate with some method
      if (/^(check|uncheck|toggle|indeterminate|determinate|disable|enable|update|destroy)$/i.test(options)) {
  
        // Normalize method's name
        options = options.toLowerCase();
  
        // Find checkboxes and radio buttons
        walker(this);
  
        return stack.each(function() {
          var self = $(this);
  
          if (options == 'destroy') {
            tidy(self, 'ifDestroyed');
          } else {
            operate(self, true, options);
          }
  
          // Fire method's callback
          if ($.isFunction(fire)) {
            fire();
          }
        });
  
      // Customization
      } else if (typeof options == 'object' || !options) {
  
        // Check if any options were passed
        var settings = $.extend({
            checkedClass: _checked,
            disabledClass: _disabled,
            indeterminateClass: _indeterminate,
            labelHover: true
          }, options),
  
          selector = settings.handle,
          hoverClass = settings.hoverClass || 'hover',
          focusClass = settings.focusClass || 'focus',
          activeClass = settings.activeClass || 'active',
          labelHover = !!settings.labelHover,
          labelHoverClass = settings.labelHoverClass || 'hover',
  
          // Setup clickable area
          area = ('' + settings.increaseArea).replace('%', '') | 0;
  
        // Selector limit
        if (selector == _checkbox || selector == _radio) {
          handle = 'input[type="' + selector + '"]';
        }
  
        // Clickable area limit
        if (area < -50) {
          area = -50;
        }
  
        // Walk around the selector
        walker(this);
  
        return stack.each(function() {
          var self = $(this);
  
          // If already customized
          tidy(self);
  
          var node = this,
            id = node.id,
  
            // Layer styles
            offset = -area + '%',
            size = 100 + (area * 2) + '%',
            layer = {
              position: 'absolute',
              top: offset,
              left: offset,
              display: 'block',
              width: size,
              height: size,
              margin: 0,
              padding: 0,
              background: '#fff',
              border: 0,
              opacity: 0
            },
  
            // Choose how to hide input
            hide = _mobile ? {
              position: 'absolute',
              visibility: 'hidden'
            } : area ? layer : {
              position: 'absolute',
              opacity: 0
            },
  
            // Get proper class
            className = node[_type] == _checkbox ? settings.checkboxClass || 'i' + _checkbox : settings.radioClass || 'i' + _radio,
  
            // Find assigned labels
            label = $(_label + '[for="' + id + '"]').add(self.closest(_label)),
  
            // Check ARIA option
            aria = !!settings.aria,
  
            // Set ARIA placeholder
            ariaID = _iCheck + '-' + Math.random().toString(36).substr(2,6),
  
            // Parent & helper
            parent = '<div class="' + className + '" ' + (aria ? 'role="' + node[_type] + '" ' : ''),
            helper;
  
          // Set ARIA "labelledby"
          if (aria) {
            label.each(function() {
              parent += 'aria-labelledby="';
  
              if (this.id) {
                parent += this.id;
              } else {
                this.id = ariaID;
                parent += ariaID;
              }
  
              parent += '"';
            });
          }
  
          // Wrap input
          parent = self.wrap(parent + '/>')[_callback]('ifCreated').parent().append(settings.insert);
  
          // Layer addition
          helper = $('<ins class="' + _iCheckHelper + '"/>').css(layer).appendTo(parent);
  
          // Finalize customization
          self.data(_iCheck, {o: settings, s: self.attr('style')}).css(hide);
          !!settings.inheritClass && parent[_add](node.className || '');
          !!settings.inheritID && id && parent.attr('id', _iCheck + '-' + id);
          parent.css('position') == 'static' && parent.css('position', 'relative');
          operate(self, true, _update);
  
          // Label events
          if (label.length) {
            label.on(_click + '.i mouseover.i mouseout.i ' + _touch, function(event) {
              var type = event[_type],
                item = $(this);
  
              // Do nothing if input is disabled
              if (!node[_disabled]) {
  
                // Click
                if (type == _click) {
                  if ($(event.target).is('a')) {
                    return;
                  }
                  operate(self, false, true);
  
                // Hover state
                } else if (labelHover) {
  
                  // mouseout|touchend
                  if (/ut|nd/.test(type)) {
                    parent[_remove](hoverClass);
                    item[_remove](labelHoverClass);
                  } else {
                    parent[_add](hoverClass);
                    item[_add](labelHoverClass);
                  }
                }
  
                if (_mobile) {
                  event.stopPropagation();
                } else {
                  return false;
                }
              }
            });
          }
  
          // Input events
          self.on(_click + '.i focus.i blur.i keyup.i keydown.i keypress.i', function(event) {
            var type = event[_type],
              key = event.keyCode;
  
            // Click
            if (type == _click) {
              return false;
  
            // Keydown
            } else if (type == 'keydown' && key == 32) {
              if (!(node[_type] == _radio && node[_checked])) {
                if (node[_checked]) {
                  off(self, _checked);
                } else {
                  on(self, _checked);
                }
              }
  
              return false;
  
            // Keyup
            } else if (type == 'keyup' && node[_type] == _radio) {
              !node[_checked] && on(self, _checked);
  
            // Focus/blur
            } else if (/us|ur/.test(type)) {
              parent[type == 'blur' ? _remove : _add](focusClass);
            }
          });
  
          // Helper events
          helper.on(_click + ' mousedown mouseup mouseover mouseout ' + _touch, function(event) {
            var type = event[_type],
  
              // mousedown|mouseup
              toggle = /wn|up/.test(type) ? activeClass : hoverClass;
  
            // Do nothing if input is disabled
            if (!node[_disabled]) {
  
              // Click
              if (type == _click) {
                operate(self, false, true);
  
              // Active and hover states
              } else {
  
                // State is on
                if (/wn|er|in/.test(type)) {
  
                  // mousedown|mouseover|touchbegin
                  parent[_add](toggle);
  
                // State is off
                } else {
                  parent[_remove](toggle + ' ' + activeClass);
                }
  
                // Label hover
                if (label.length && labelHover && toggle == hoverClass) {
  
                  // mouseout|touchend
                  label[/ut|nd/.test(type) ? _remove : _add](labelHoverClass);
                }
              }
  
              if (_mobile) {
                event.stopPropagation();
              } else {
                return false;
              }
            }
          });
        });
      } else {
        return this;
      }
    };
  
    // Do something with inputs
    function operate(input, direct, method) {
      var node = input[0],
        state = /er/.test(method) ? _indeterminate : /bl/.test(method) ? _disabled : _checked,
        active = method == _update ? {
          checked: node[_checked],
          disabled: node[_disabled],
          indeterminate: input.attr(_indeterminate) == 'true' || input.attr(_determinate) == 'false'
        } : node[state];
  
      // Check, disable or indeterminate
      if (/^(ch|di|in)/.test(method) && !active) {
        on(input, state);
  
      // Uncheck, enable or determinate
      } else if (/^(un|en|de)/.test(method) && active) {
        off(input, state);
  
      // Update
      } else if (method == _update) {
  
        // Handle states
        for (var each in active) {
          if (active[each]) {
            on(input, each, true);
          } else {
            off(input, each, true);
          }
        }
  
      } else if (!direct || method == 'toggle') {
  
        // Helper or label was clicked
        if (!direct) {
          input[_callback]('ifClicked');
        }
  
        // Toggle checked state
        if (active) {
          if (node[_type] !== _radio) {
            off(input, state);
          }
        } else {
          on(input, state);
        }
      }
    }
  
    // Add checked, disabled or indeterminate state
    function on(input, state, keep) {
      var node = input[0],
        parent = input.parent(),
        checked = state == _checked,
        indeterminate = state == _indeterminate,
        disabled = state == _disabled,
        callback = indeterminate ? _determinate : checked ? _unchecked : 'enabled',
        regular = option(input, callback + capitalize(node[_type])),
        specific = option(input, state + capitalize(node[_type]));
  
      // Prevent unnecessary actions
      if (node[state] !== true) {
  
        // Toggle assigned radio buttons
        if (!keep && state == _checked && node[_type] == _radio && node.name) {
          var form = input.closest('form'),
            inputs = 'input[name="' + node.name + '"]';
  
          inputs = form.length ? form.find(inputs) : $(inputs);
  
          inputs.each(function() {
            if (this !== node && $(this).data(_iCheck)) {
              off($(this), state);
            }
          });
        }
  
        // Indeterminate state
        if (indeterminate) {
  
          // Add indeterminate state
          node[state] = true;
  
          // Remove checked state
          if (node[_checked]) {
            off(input, _checked, 'force');
          }
  
        // Checked or disabled state
        } else {
  
          // Add checked or disabled state
          if (!keep) {
            node[state] = true;
          }
  
          // Remove indeterminate state
          if (checked && node[_indeterminate]) {
            off(input, _indeterminate, false);
          }
        }
  
        // Trigger callbacks
        callbacks(input, checked, state, keep);
      }
  
      // Add proper cursor
      if (node[_disabled] && !!option(input, _cursor, true)) {
        parent.find('.' + _iCheckHelper).css(_cursor, 'default');
      }
  
      // Add state class
      parent[_add](specific || option(input, state) || '');
  
      // Set ARIA attribute
      if (!!parent.attr('role') && !indeterminate) {
        parent.attr('aria-' + (disabled ? _disabled : _checked), 'true');
      }
  
      // Remove regular state class
      parent[_remove](regular || option(input, callback) || '');
    }
  
    // Remove checked, disabled or indeterminate state
    function off(input, state, keep) {
      var node = input[0],
        parent = input.parent(),
        checked = state == _checked,
        indeterminate = state == _indeterminate,
        disabled = state == _disabled,
        callback = indeterminate ? _determinate : checked ? _unchecked : 'enabled',
        regular = option(input, callback + capitalize(node[_type])),
        specific = option(input, state + capitalize(node[_type]));
  
      // Prevent unnecessary actions
      if (node[state] !== false) {
  
        // Toggle state
        if (indeterminate || !keep || keep == 'force') {
          node[state] = false;
        }
  
        // Trigger callbacks
        callbacks(input, checked, callback, keep);
      }
  
      // Add proper cursor
      if (!node[_disabled] && !!option(input, _cursor, true)) {
        parent.find('.' + _iCheckHelper).css(_cursor, 'pointer');
      }
  
      // Remove state class
      parent[_remove](specific || option(input, state) || '');
  
      // Set ARIA attribute
      if (!!parent.attr('role') && !indeterminate) {
        parent.attr('aria-' + (disabled ? _disabled : _checked), 'false');
      }
  
      // Add regular state class
      parent[_add](regular || option(input, callback) || '');
    }
  
    // Remove all traces
    function tidy(input, callback) {
      if (input.data(_iCheck)) {
  
        // Remove everything except input
        input.parent().html(input.attr('style', input.data(_iCheck).s || ''));
  
        // Callback
        if (callback) {
          input[_callback](callback);
        }
  
        // Unbind events
        input.off('.i').unwrap();
        $(_label + '[for="' + input[0].id + '"]').add(input.closest(_label)).off('.i');
      }
    }
  
    // Get some option
    function option(input, state, regular) {
      if (input.data(_iCheck)) {
        return input.data(_iCheck).o[state + (regular ? '' : 'Class')];
      }
    }
  
    // Capitalize some string
    function capitalize(string) {
      return string.charAt(0).toUpperCase() + string.slice(1);
    }
  
    // Executable handlers
    function callbacks(input, checked, callback, keep) {
      if (!keep) {
        if (checked) {
          input[_callback]('ifToggled');
        }
  
        input[_callback]('ifChanged')[_callback]('if' + capitalize(callback));
      }
    }
  })(window.jQuery || window.Zepto);
  