text: /*!
   * Draggabilly PACKAGED v2.1.1
   * Make that shiz draggable
   * http://draggabilly.desandro.com
   * MIT license
   */
  
  /**
   * Bridget makes jQuery widgets
   * v2.0.1
   * MIT license
   */
  
  /* jshint browser: true, strict: true, undef: true, unused: true */
  
  ( function( window, factory ) {
    // universal module definition
    /*jshint strict: false */ /* globals define, module, require */
    if ( typeof define == 'function' && define.amd ) {
      // AMD
      define( 'jquery-bridget/jquery-bridget',[ 'jquery' ], function( jQuery ) {
        return factory( window, jQuery );
      });
    } else if ( typeof module == 'object' && module.exports ) {
      // CommonJS
      module.exports = factory(
        window,
        require('jquery')
      );
    } else {
      // browser global
      window.jQueryBridget = factory(
        window,
        window.jQuery
      );
    }
  
  }( window, function factory( window, jQuery ) {
  
  
  // ----- utils ----- //
  
  var arraySlice = Array.prototype.slice;
  
  // helper function for logging errors
  // $.error breaks jQuery chaining
  var console = window.console;
  var logError = typeof console == 'undefined' ? function() {} :
    function( message ) {
      console.error( message );
    };
  
  // ----- jQueryBridget ----- //
  
  function jQueryBridget( namespace, PluginClass, $ ) {
    $ = $ || jQuery || window.jQuery;
    if ( !$ ) {
      return;
    }
  
    // add option method -> $().plugin('option', {...})
    if ( !PluginClass.prototype.option ) {
      // option setter
      PluginClass.prototype.option = function( opts ) {
        // bail out if not an object
        if ( !$.isPlainObject( opts ) ){
          return;
        }
        this.options = $.extend( true, this.options, opts );
      };
    }
  
    // make jQuery plugin
    $.fn[ namespace ] = function( arg0 /*, arg1 */ ) {
      if ( typeof arg0 == 'string' ) {
        // method call $().plugin( 'methodName', { options } )
        // shift arguments by 1
        var args = arraySlice.call( arguments, 1 );
        return methodCall( this, arg0, args );
      }
      // just $().plugin({ options })
      plainCall( this, arg0 );
      return this;
    };
  
    // $().plugin('methodName')
    function methodCall( $elems, methodName, args ) {
      var returnValue;
      var pluginMethodStr = '$().' + namespace + '("' + methodName + '")';
  
      $elems.each( function( i, elem ) {
        // get instance
        var instance = $.data( elem, namespace );
        if ( !instance ) {
          logError( namespace + ' not initialized. Cannot call methods, i.e. ' +
            pluginMethodStr );
          return;
        }
  
        var method = instance[ methodName ];
        if ( !method || methodName.charAt(0) == '_' ) {
          logError( pluginMethodStr + ' is not a valid method' );
          return;
        }
  
        // apply method, get return value
        var value = method.apply( instance, args );
        // set return value if value is returned, use only first value
        returnValue = returnValue === undefined ? value : returnValue;
      });
  
      return returnValue !== undefined ? returnValue : $elems;
    }
  
    function plainCall( $elems, options ) {
      $elems.each( function( i, elem ) {
        var instance = $.data( elem, namespace );
        if ( instance ) {
          // set options & init
          instance.option( options );
          instance._init();
        } else {
          // initialize new instance
          instance = new PluginClass( elem, options );
          $.data( elem, namespace, instance );
        }
      });
    }
  
    updateJQuery( $ );
  
  }
  
  // ----- updateJQuery ----- //
  
  // set $.bridget for v1 backwards compatibility
  function updateJQuery( $ ) {
    if ( !$ || ( $ && $.bridget ) ) {
      return;
    }
    $.bridget = jQueryBridget;
  }
  
  updateJQuery( jQuery || window.jQuery );
  
  // -----  ----- //
  
  return jQueryBridget;
  
  }));
  
  /*!
   * getSize v2.0.2
   * measure size of elements
   * MIT license
   */
  
  /*jshint browser: true, strict: true, undef: true, unused: true */
  /*global define: false, module: false, console: false */
  
  ( function( window, factory ) {
    'use strict';
  
    if ( typeof define == 'function' && define.amd ) {
      // AMD
      define( 'get-size/get-size',[],function() {
        return factory();
      });
    } else if ( typeof module == 'object' && module.exports ) {
      // CommonJS
      module.exports = factory();
    } else {
      // browser global
      window.getSize = factory();
    }
  
  })( window, function factory() {
  
  
  // -------------------------- helpers -------------------------- //
  
  // get a number from a string, not a percentage
  function getStyleSize( value ) {
    var num = parseFloat( value );
    // not a percent like '100%', and a number
    var isValid = value.indexOf('%') == -1 && !isNaN( num );
    return isValid && num;
  }
  
  function noop() {}
  
  var logError = typeof console == 'undefined' ? noop :
    function( message ) {
      console.error( message );
    };
  
  // -------------------------- measurements -------------------------- //
  
  var measurements = [
    'paddingLeft',
    'paddingRight',
    'paddingTop',
    'paddingBottom',
    'marginLeft',
    'marginRight',
    'marginTop',
    'marginBottom',
    'borderLeftWidth',
    'borderRightWidth',
    'borderTopWidth',
    'borderBottomWidth'
  ];
  
  var measurementsLength = measurements.length;
  
  function getZeroSize() {
    var size = {
      width: 0,
      height: 0,
      innerWidth: 0,
      innerHeight: 0,
      outerWidth: 0,
      outerHeight: 0
    };
    for ( var i=0; i < measurementsLength; i++ ) {
      var measurement = measurements[i];
      size[ measurement ] = 0;
    }
    return size;
  }
  
  // -------------------------- getStyle -------------------------- //
  
  /**
   * getStyle, get style of element, check for Firefox bug
   * https://bugzilla.mozilla.org/show_bug.cgi?id=548397
   */
  function getStyle( elem ) {
    var style = getComputedStyle( elem );
    if ( !style ) {
      logError( 'Style returned ' + style +
        '. Are you running this code in a hidden iframe on Firefox? ' +
        'See http://bit.ly/getsizebug1' );
    }
    return style;
  }
  
  // -------------------------- setup -------------------------- //
  
  var isSetup = false;
  
  var isBoxSizeOuter;
  
  /**
   * setup
   * check isBoxSizerOuter
   * do on first getSize() rather than on page load for Firefox bug
   */
  function setup() {
    // setup once
    if ( isSetup ) {
      return;
    }
    isSetup = true;
  
    // -------------------------- box sizing -------------------------- //
  
    /**
     * WebKit measures the outer-width on style.width on border-box elems
     * IE & Firefox<29 measures the inner-width
     */
    var div = document.createElement('div');
    div.style.width = '200px';
    div.style.padding = '1px 2px 3px 4px';
    div.style.borderStyle = 'solid';
    div.style.borderWidth = '1px 2px 3px 4px';
    div.style.boxSizing = 'border-box';
  
    var body = document.body || document.documentElement;
    body.appendChild( div );
    var style = getStyle( div );
  
    getSize.isBoxSizeOuter = isBoxSizeOuter = getStyleSize( style.width ) == 200;
    body.removeChild( div );
  
  }
  
  // -------------------------- getSize -------------------------- //
  
  function getSize( elem ) {
    setup();
  
    // use querySeletor if elem is string
    if ( typeof elem == 'string' ) {
      elem = document.querySelector( elem );
    }
  
    // do not proceed on non-objects
    if ( !elem || typeof elem != 'object' || !elem.nodeType ) {
      return;
    }
  
    var style = getStyle( elem );
  
    // if hidden, everything is 0
    if ( style.display == 'none' ) {
      return getZeroSize();
    }
  
    var size = {};
    size.width = elem.offsetWidth;
    size.height = elem.offsetHeight;
  
    var isBorderBox = size.isBorderBox = style.boxSizing == 'border-box';
  
    // get all measurements
    for ( var i=0; i < measurementsLength; i++ ) {
      var measurement = measurements[i];
      var value = style[ measurement ];
      var num = parseFloat( value );
      // any 'auto', 'medium' value will be 0
      size[ measurement ] = !isNaN( num ) ? num : 0;
    }
  
    var paddingWidth = size.paddingLeft + size.paddingRight;
    var paddingHeight = size.paddingTop + size.paddingBottom;
    var marginWidth = size.marginLeft + size.marginRight;
    var marginHeight = size.marginTop + size.marginBottom;
    var borderWidth = size.borderLeftWidth + size.borderRightWidth;
    var borderHeight = size.borderTopWidth + size.borderBottomWidth;
  
    var isBorderBoxSizeOuter = isBorderBox && isBoxSizeOuter;
  
    // overwrite width and height if we can get it from style
    var styleWidth = getStyleSize( style.width );
    if ( styleWidth !== false ) {
      size.width = styleWidth +
        // add padding and border unless it's already including it
        ( isBorderBoxSizeOuter ? 0 : paddingWidth + borderWidth );
    }
  
    var styleHeight = getStyleSize( style.height );
    if ( styleHeight !== false ) {
      size.height = styleHeight +
        // add padding and border unless it's already including it
        ( isBorderBoxSizeOuter ? 0 : paddingHeight + borderHeight );
    }
  
    size.innerWidth = size.width - ( paddingWidth + borderWidth );
    size.innerHeight = size.height - ( paddingHeight + borderHeight );
  
    size.outerWidth = size.width + marginWidth;
    size.outerHeight = size.height + marginHeight;
  
    return size;
  }
  
  return getSize;
  
  });
  
  /**
   * EvEmitter v1.0.3
   * Lil' event emitter
   * MIT License
   */
  
  /* jshint unused: true, undef: true, strict: true */
  
  ( function( global, factory ) {
    // universal module definition
    /* jshint strict: false */ /* globals define, module, window */
    if ( typeof define == 'function' && define.amd ) {
      // AMD - RequireJS
      define( 'ev-emitter/ev-emitter',factory );
    } else if ( typeof module == 'object' && module.exports ) {
      // CommonJS - Browserify, Webpack
      module.exports = factory();
    } else {
      // Browser globals
      global.EvEmitter = factory();
    }
  
  }( typeof window != 'undefined' ? window : this, function() {
  
  
  
  function EvEmitter() {}
  
  var proto = EvEmitter.prototype;
  
  proto.on = function( eventName, listener ) {
    if ( !eventName || !listener ) {
      return;
    }
    // set events hash
    var events = this._events = this._events || {};
    // set listeners array
    var listeners = events[ eventName ] = events[ eventName ] || [];
    // only add once
    if ( listeners.indexOf( listener ) == -1 ) {
      listeners.push( listener );
    }
  
    return this;
  };
  
  proto.once = function( eventName, listener ) {
    if ( !eventName || !listener ) {
      return;
    }
    // add event
    this.on( eventName, listener );
    // set once flag
    // set onceEvents hash
    var onceEvents = this._onceEvents = this._onceEvents || {};
    // set onceListeners object
    var onceListeners = onceEvents[ eventName ] = onceEvents[ eventName ] || {};
    // set flag
    onceListeners[ listener ] = true;
  
    return this;
  };
  
  proto.off = function( eventName, listener ) {
    var listeners = this._events && this._events[ eventName ];
    if ( !listeners || !listeners.length ) {
      return;
    }
    var index = listeners.indexOf( listener );
    if ( index != -1 ) {
      listeners.splice( index, 1 );
    }
  
    return this;
  };
  
  proto.emitEvent = function( eventName, args ) {
    var listeners = this._events && this._events[ eventName ];
    if ( !listeners || !listeners.length ) {
      return;
    }
    var i = 0;
    var listener = listeners[i];
    args = args || [];
    // once stuff
    var onceListeners = this._onceEvents && this._onceEvents[ eventName ];
  
    while ( listener ) {
      var isOnce = onceListeners && onceListeners[ listener ];
      if ( isOnce ) {
        // remove listener
        // remove before trigger to prevent recursion
        this.off( eventName, listener );
        // unset once flag
        delete onceListeners[ listener ];
      }
      // trigger listener
      listener.apply( this, args );
      // get next listener
      i += isOnce ? 0 : 1;
      listener = listeners[i];
    }
  
    return this;
  };
  
  return EvEmitter;
  
  }));
  
  /*!
   * Unipointer v2.1.0
   * base class for doing one thing with pointer event
   * MIT license
   */
  
  /*jshint browser: true, undef: true, unused: true, strict: true */
  
  ( function( window, factory ) {
    // universal module definition
    /* jshint strict: false */ /*global define, module, require */
    if ( typeof define == 'function' && define.amd ) {
      // AMD
      define( 'unipointer/unipointer',[
        'ev-emitter/ev-emitter'
      ], function( EvEmitter ) {
        return factory( window, EvEmitter );
      });
    } else if ( typeof module == 'object' && module.exports ) {
      // CommonJS
      module.exports = factory(
        window,
        require('ev-emitter')
      );
    } else {
      // browser global
      window.Unipointer = factory(
        window,
        window.EvEmitter
      );
    }
  
  }( window, function factory( window, EvEmitter ) {
  
  
  
  function noop() {}
  
  function Unipointer() {}
  
  // inherit EvEmitter
  var proto = Unipointer.prototype = Object.create( EvEmitter.prototype );
  
  proto.bindStartEvent = function( elem ) {
    this._bindStartEvent( elem, true );
  };
  
  proto.unbindStartEvent = function( elem ) {
    this._bindStartEvent( elem, false );
  };
  
  /**
   * works as unbinder, as you can ._bindStart( false ) to unbind
   * @param {Boolean} isBind - will unbind if falsey
   */
  proto._bindStartEvent = function( elem, isBind ) {
    // munge isBind, default to true
    isBind = isBind === undefined ? true : !!isBind;
    var bindMethod = isBind ? 'addEventListener' : 'removeEventListener';
  
    if ( window.navigator.pointerEnabled ) {
      // W3C Pointer Events, IE11. See https://coderwall.com/p/mfreca
      elem[ bindMethod ]( 'pointerdown', this );
    } else if ( window.navigator.msPointerEnabled ) {
      // IE10 Pointer Events
      elem[ bindMethod ]( 'MSPointerDown', this );
    } else {
      // listen for both, for devices like Chrome Pixel
      elem[ bindMethod ]( 'mousedown', this );
      elem[ bindMethod ]( 'touchstart', this );
    }
  };
  
  // trigger handler methods for events
  proto.handleEvent = function( event ) {
    var method = 'on' + event.type;
    if ( this[ method ] ) {
      this[ method ]( event );
    }
  };
  
  // returns the touch that we're keeping track of
  proto.getTouch = function( touches ) {
    for ( var i=0; i < touches.length; i++ ) {
      var touch = touches[i];
      if ( touch.identifier == this.pointerIdentifier ) {
        return touch;
      }
    }
  };
  
  // ----- start event ----- //
  
  proto.onmousedown = function( event ) {
    // dismiss clicks from right or middle buttons
    var button = event.button;
    if ( button && ( button !== 0 && button !== 1 ) ) {
      return;
    }
    this._pointerDown( event, event );
  };
  
  proto.ontouchstart = function( event ) {
    this._pointerDown( event, event.changedTouches[0] );
  };
  
  proto.onMSPointerDown =
  proto.onpointerdown = function( event ) {
    this._pointerDown( event, event );
  };
  
  /**
   * pointer start
   * @param {Event} event
   * @param {Event or Touch} pointer
   */
  proto._pointerDown = function( event, pointer ) {
    // dismiss other pointers
    if ( this.isPointerDown ) {
      return;
    }
  
    this.isPointerDown = true;
    // save pointer identifier to match up touch events
    this.pointerIdentifier = pointer.pointerId !== undefined ?
      // pointerId for pointer events, touch.indentifier for touch events
      pointer.pointerId : pointer.identifier;
  
    this.pointerDown( event, pointer );
  };
  
  proto.pointerDown = function( event, pointer ) {
    this._bindPostStartEvents( event );
    this.emitEvent( 'pointerDown', [ event, pointer ] );
  };
  
  // hash of events to be bound after start event
  var postStartEvents = {
    mousedown: [ 'mousemove', 'mouseup' ],
    touchstart: [ 'touchmove', 'touchend', 'touchcancel' ],
    pointerdown: [ 'pointermove', 'pointerup', 'pointercancel' ],
    MSPointerDown: [ 'MSPointerMove', 'MSPointerUp', 'MSPointerCancel' ]
  };
  
  proto._bindPostStartEvents = function( event ) {
    if ( !event ) {
      return;
    }
    // get proper events to match start event
    var events = postStartEvents[ event.type ];
    // bind events to node
    events.forEach( function( eventName ) {
      window.addEventListener( eventName, this );
    }, this );
    // save these arguments
    this._boundPointerEvents = events;
  };
  
  proto._unbindPostStartEvents = function() {
    // check for _boundEvents, in case dragEnd triggered twice (old IE8 bug)
    if ( !this._boundPointerEvents ) {
      return;
    }
    this._boundPointerEvents.forEach( function( eventName ) {
      window.removeEventListener( eventName, this );
    }, this );
  
    delete this._boundPointerEvents;
  };
  
  // ----- move event ----- //
  
  proto.onmousemove = function( event ) {
    this._pointerMove( event, event );
  };
  
  proto.onMSPointerMove =
  proto.onpointermove = function( event ) {
    if ( event.pointerId == this.pointerIdentifier ) {
      this._pointerMove( event, event );
    }
  };
  
  proto.ontouchmove = function( event ) {
    var touch = this.getTouch( event.changedTouches );
    if ( touch ) {
      this._pointerMove( event, touch );
    }
  };
  
  /**
   * pointer move
   * @param {Event} event
   * @param {Event or Touch} pointer
   * @private
   */
  proto._pointerMove = function( event, pointer ) {
    this.pointerMove( event, pointer );
  };
  
  // public
  proto.pointerMove = function( event, pointer ) {
    this.emitEvent( 'pointerMove', [ event, pointer ] );
  };
  
  // ----- end event ----- //
  
  
  proto.onmouseup = function( event ) {
    this._pointerUp( event, event );
  };
  
  proto.onMSPointerUp =
  proto.onpointerup = function( event ) {
    if ( event.pointerId == this.pointerIdentifier ) {
      this._pointerUp( event, event );
    }
  };
  
  proto.ontouchend = function( event ) {
    var touch = this.getTouch( event.changedTouches );
    if ( touch ) {
      this._pointerUp( event, touch );
    }
  };
  
  /**
   * pointer up
   * @param {Event} event
   * @param {Event or Touch} pointer
   * @private
   */
  proto._pointerUp = function( event, pointer ) {
    this._pointerDone();
    this.pointerUp( event, pointer );
  };
  
  // public
  proto.pointerUp = function( event, pointer ) {
    this.emitEvent( 'pointerUp', [ event, pointer ] );
  };
  
  // ----- pointer done ----- //
  
  // triggered on pointer up & pointer cancel
  proto._pointerDone = function() {
    // reset properties
    this.isPointerDown = false;
    delete this.pointerIdentifier;
    // remove events
    this._unbindPostStartEvents();
    this.pointerDone();
  };
  
  proto.pointerDone = noop;
  
  // ----- pointer cancel ----- //
  
  proto.onMSPointerCancel =
  proto.onpointercancel = function( event ) {
    if ( event.pointerId == this.pointerIdentifier ) {
      this._pointerCancel( event, event );
    }
  };
  
  proto.ontouchcancel = function( event ) {
    var touch = this.getTouch( event.changedTouches );
    if ( touch ) {
      this._pointerCancel( event, touch );
    }
  };
  
  /**
   * pointer cancel
   * @param {Event} event
   * @param {Event or Touch} pointer
   * @private
   */
  proto._pointerCancel = function( event, pointer ) {
    this._pointerDone();
    this.pointerCancel( event, pointer );
  };
  
  // public
  proto.pointerCancel = function( event, pointer ) {
    this.emitEvent( 'pointerCancel', [ event, pointer ] );
  };
  
  // -----  ----- //
  
  // utility function for getting x/y coords from event
  Unipointer.getPointerPoint = function( pointer ) {
    return {
      x: pointer.pageX,
      y: pointer.pageY
    };
  };
  
  // -----  ----- //
  
  return Unipointer;
  
  }));
  
  /*!
   * Unidragger v2.1.0
   * Draggable base class
   * MIT license
   */
  
  /*jshint browser: true, unused: true, undef: true, strict: true */
  
  ( function( window, factory ) {
    // universal module definition
    /*jshint strict: false */ /*globals define, module, require */
  
    if ( typeof define == 'function' && define.amd ) {
      // AMD
      define( 'unidragger/unidragger',[
        'unipointer/unipointer'
      ], function( Unipointer ) {
        return factory( window, Unipointer );
      });
    } else if ( typeof module == 'object' && module.exports ) {
      // CommonJS
      module.exports = factory(
        window,
        require('unipointer')
      );
    } else {
      // browser global
      window.Unidragger = factory(
        window,
        window.Unipointer
      );
    }
  
  }( window, function factory( window, Unipointer ) {
  
  
  
  // -----  ----- //
  
  function noop() {}
  
  // -------------------------- Unidragger -------------------------- //
  
  function Unidragger() {}
  
  // inherit Unipointer & EvEmitter
  var proto = Unidragger.prototype = Object.create( Unipointer.prototype );
  
  // ----- bind start ----- //
  
  proto.bindHandles = function() {
    this._bindHandles( true );
  };
  
  proto.unbindHandles = function() {
    this._bindHandles( false );
  };
  
  var navigator = window.navigator;
  /**
   * works as unbinder, as you can .bindHandles( false ) to unbind
   * @param {Boolean} isBind - will unbind if falsey
   */
  proto._bindHandles = function( isBind ) {
    // munge isBind, default to true
    isBind = isBind === undefined ? true : !!isBind;
    // extra bind logic
    var binderExtra;
    if ( navigator.pointerEnabled ) {
      binderExtra = function( handle ) {
        // disable scrolling on the element
        handle.style.touchAction = isBind ? 'none' : '';
      };
    } else if ( navigator.msPointerEnabled ) {
      binderExtra = function( handle ) {
        // disable scrolling on the element
        handle.style.msTouchAction = isBind ? 'none' : '';
      };
    } else {
      binderExtra = noop;
    }
    // bind each handle
    var bindMethod = isBind ? 'addEventListener' : 'removeEventListener';
    for ( var i=0; i < this.handles.length; i++ ) {
      var handle = this.handles[i];
      this._bindStartEvent( handle, isBind );
      binderExtra( handle );
      handle[ bindMethod ]( 'click', this );
    }
  };
  
  // ----- start event ----- //
  
  /**
   * pointer start
   * @param {Event} event
   * @param {Event or Touch} pointer
   */
  proto.pointerDown = function( event, pointer ) {
    // dismiss range sliders
    if ( event.target.nodeName == 'INPUT' && event.target.type == 'range' ) {
      // reset pointerDown logic
      this.isPointerDown = false;
      delete this.pointerIdentifier;
      return;
    }
  
    this._dragPointerDown( event, pointer );
    // kludge to blur focused inputs in dragger
    var focused = document.activeElement;
    if ( focused && focused.blur ) {
      focused.blur();
    }
    // bind move and end events
    this._bindPostStartEvents( event );
    this.emitEvent( 'pointerDown', [ event, pointer ] );
  };
  
  // base pointer down logic
  proto._dragPointerDown = function( event, pointer ) {
    // track to see when dragging starts
    this.pointerDownPoint = Unipointer.getPointerPoint( pointer );
  
    var canPreventDefault = this.canPreventDefaultOnPointerDown( event, pointer );
    if ( canPreventDefault ) {
      event.preventDefault();
    }
  };
  
  // overwriteable method so Flickity can prevent for scrolling
  proto.canPreventDefaultOnPointerDown = function( event ) {
    // prevent default, unless touchstart or <select>
    return event.target.nodeName != 'SELECT';
  };
  
  // ----- move event ----- //
  
  /**
   * drag move
   * @param {Event} event
   * @param {Event or Touch} pointer
   */
  proto.pointerMove = function( event, pointer ) {
    var moveVector = this._dragPointerMove( event, pointer );
    this.emitEvent( 'pointerMove', [ event, pointer, moveVector ] );
    this._dragMove( event, pointer, moveVector );
  };
  
  // base pointer move logic
  proto._dragPointerMove = function( event, pointer ) {
    var movePoint = Unipointer.getPointerPoint( pointer );
    var moveVector = {
      x: movePoint.x - this.pointerDownPoint.x,
      y: movePoint.y - this.pointerDownPoint.y
    };
    // start drag if pointer has moved far enough to start drag
    if ( !this.isDragging && this.hasDragStarted( moveVector ) ) {
      this._dragStart( event, pointer );
    }
    return moveVector;
  };
  
  // condition if pointer has moved far enough to start drag
  proto.hasDragStarted = function( moveVector ) {
    return Math.abs( moveVector.x ) > 3 || Math.abs( moveVector.y ) > 3;
  };
  
  
  // ----- end event ----- //
  
  /**
   * pointer up
   * @param {Event} event
   * @param {Event or Touch} pointer
   */
  proto.pointerUp = function( event, pointer ) {
    this.emitEvent( 'pointerUp', [ event, pointer ] );
    this._dragPointerUp( event, pointer );
  };
  
  proto._dragPointerUp = function( event, pointer ) {
    if ( this.isDragging ) {
      this._dragEnd( event, pointer );
    } else {
      // pointer didn't move enough for drag to start
      this._staticClick( event, pointer );
    }
  };
  
  // -------------------------- drag -------------------------- //
  
  // dragStart
  proto._dragStart = function( event, pointer ) {
    this.isDragging = true;
    this.dragStartPoint = Unipointer.getPointerPoint( pointer );
    // prevent clicks
    this.isPreventingClicks = true;
  
    this.dragStart( event, pointer );
  };
  
  proto.dragStart = function( event, pointer ) {
    this.emitEvent( 'dragStart', [ event, pointer ] );
  };
  
  // dragMove
  proto._dragMove = function( event, pointer, moveVector ) {
    // do not drag if not dragging yet
    if ( !this.isDragging ) {
      return;
    }
  
    this.dragMove( event, pointer, moveVector );
  };
  
  proto.dragMove = function( event, pointer, moveVector ) {
    event.preventDefault();
    this.emitEvent( 'dragMove', [ event, pointer, moveVector ] );
  };
  
  // dragEnd
  proto._dragEnd = function( event, pointer ) {
    // set flags
    this.isDragging = false;
    // re-enable clicking async
    setTimeout( function() {
      delete this.isPreventingClicks;
    }.bind( this ) );
  
    this.dragEnd( event, pointer );
  };
  
  proto.dragEnd = function( event, pointer ) {
    this.emitEvent( 'dragEnd', [ event, pointer ] );
  };
  
  // ----- onclick ----- //
  
  // handle all clicks and prevent clicks when dragging
  proto.onclick = function( event ) {
    if ( this.isPreventingClicks ) {
      event.preventDefault();
    }
  };
  
  // ----- staticClick ----- //
  
  // triggered after pointer down & up with no/tiny movement
  proto._staticClick = function( event, pointer ) {
    // ignore emulated mouse up clicks
    if ( this.isIgnoringMouseUp && event.type == 'mouseup' ) {
      return;
    }
  
    // allow click in <input>s and <textarea>s
    var nodeName = event.target.nodeName;
    if ( nodeName == 'INPUT' || nodeName == 'TEXTAREA' ) {
      event.target.focus();
    }
    this.staticClick( event, pointer );
  
    // set flag for emulated clicks 300ms after touchend
    if ( event.type != 'mouseup' ) {
      this.isIgnoringMouseUp = true;
      // reset flag after 300ms
      setTimeout( function() {
        delete this.isIgnoringMouseUp;
      }.bind( this ), 400 );
    }
  };
  
  proto.staticClick = function( event, pointer ) {
    this.emitEvent( 'staticClick', [ event, pointer ] );
  };
  
  // ----- utils ----- //
  
  Unidragger.getPointerPoint = Unipointer.getPointerPoint;
  
  // -----  ----- //
  
  return Unidragger;
  
  }));
  
  /*!
   * Draggabilly v2.1.1
   * Make that shiz draggable
   * http://draggabilly.desandro.com
   * MIT license
   */
  
  /*jshint browser: true, strict: true, undef: true, unused: true */
  
  ( function( window, factory ) {
    // universal module definition
    /* jshint strict: false */ /*globals define, module, require */
    if ( typeof define == 'function' && define.amd ) {
      // AMD
      define( [
          'get-size/get-size',
          'unidragger/unidragger'
        ],
        function( getSize, Unidragger ) {
          return factory( window, getSize, Unidragger );
        });
    } else if ( typeof module == 'object' && module.exports ) {
      // CommonJS
      module.exports = factory(
        window,
        require('get-size'),
        require('unidragger')
      );
    } else {
      // browser global
      window.Draggabilly = factory(
        window,
        window.getSize,
        window.Unidragger
      );
    }
  
  }( window, function factory( window, getSize, Unidragger ) {
  
  
  
  // vars
  var document = window.document;
  
  function noop() {}
  
  // -------------------------- helpers -------------------------- //
  
  // extend objects
  function extend( a, b ) {
    for ( var prop in b ) {
      a[ prop ] = b[ prop ];
    }
    return a;
  }
  
  function isElement( obj ) {
    return obj instanceof HTMLElement;
  }
  
  // -------------------------- requestAnimationFrame -------------------------- //
  
  // get rAF, prefixed, if present
  var requestAnimationFrame = window.requestAnimationFrame ||
    window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame;
  
  // fallback to setTimeout
  var lastTime = 0;
  if ( !requestAnimationFrame )  {
    requestAnimationFrame = function( callback ) {
      var currTime = new Date().getTime();
      var timeToCall = Math.max( 0, 16 - ( currTime - lastTime ) );
      var id = setTimeout( callback, timeToCall );
      lastTime = currTime + timeToCall;
      return id;
    };
  }
  
  // -------------------------- support -------------------------- //
  
  var docElem = document.documentElement;
  var transformProperty = typeof docElem.style.transform == 'string' ?
    'transform' : 'WebkitTransform';
  
  var jQuery = window.jQuery;
  
  // --------------------------  -------------------------- //
  
  function Draggabilly( element, options ) {
    // querySelector if string
    this.element = typeof element == 'string' ?
      document.querySelector( element ) : element;
  
    if ( jQuery ) {
      this.$element = jQuery( this.element );
    }
  
    // options
    this.options = extend( {}, this.constructor.defaults );
    this.option( options );
  
    this._create();
  }
  
  // inherit Unidragger methods
  var proto = Draggabilly.prototype = Object.create( Unidragger.prototype );
  
  Draggabilly.defaults = {
  };
  
  /**
   * set options
   * @param {Object} opts
   */
  proto.option = function( opts ) {
    extend( this.options, opts );
  };
  
  // css position values that don't need to be set
  var positionValues = {
    relative: true,
    absolute: true,
    fixed: true
  };
  
  proto._create = function() {
  
    // properties
    this.position = {};
    this._getPosition();
  
    this.startPoint = { x: 0, y: 0 };
    this.dragPoint = { x: 0, y: 0 };
  
    this.startPosition = extend( {}, this.position );
  
    // set relative positioning
    var style = getComputedStyle( this.element );
    if ( !positionValues[ style.position ] ) {
      this.element.style.position = 'relative';
    }
  
    this.enable();
    this.setHandles();
  
  };
  
  /**
   * set this.handles and bind start events to 'em
   */
  proto.setHandles = function() {
    this.handles = this.options.handle ?
      this.element.querySelectorAll( this.options.handle ) : [ this.element ];
  
    this.bindHandles();
  };
  
  /**
   * emits events via EvEmitter and jQuery events
   * @param {String} type - name of event
   * @param {Event} event - original event
   * @param {Array} args - extra arguments
   */
  proto.dispatchEvent = function( type, event, args ) {
    var emitArgs = [ event ].concat( args );
    this.emitEvent( type, emitArgs );
    var jQuery = window.jQuery;
    // trigger jQuery event
    if ( jQuery && this.$element ) {
      if ( event ) {
        // create jQuery event
        var $event = jQuery.Event( event );
        $event.type = type;
        this.$element.trigger( $event, args );
      } else {
        // just trigger with type if no event available
        this.$element.trigger( type, args );
      }
    }
  };
  
  // -------------------------- position -------------------------- //
  
  // get x/y position from style
  proto._getPosition = function() {
    var style = getComputedStyle( this.element );
    var x = this._getPositionCoord( style.left, 'width' );
    var y = this._getPositionCoord( style.top, 'height' );
    // clean up 'auto' or other non-integer values
    this.position.x = isNaN( x ) ? 0 : x;
    this.position.y = isNaN( y ) ? 0 : y;
  
    this._addTransformPosition( style );
  };
  
  proto._getPositionCoord = function( styleSide, measure ) {
    if ( styleSide.indexOf('%') != -1 ) {
      // convert percent into pixel for Safari, #75
      var parentSize = getSize( this.element.parentNode );
      // prevent not-in-DOM element throwing bug, #131
      return !parentSize ? 0 :
        ( parseFloat( styleSide ) / 100 ) * parentSize[ measure ];
    }
    return parseInt( styleSide, 10 );
  };
  
  // add transform: translate( x, y ) to position
  proto._addTransformPosition = function( style ) {
    var transform = style[ transformProperty ];
    // bail out if value is 'none'
    if ( transform.indexOf('matrix') !== 0 ) {
      return;
    }
    // split matrix(1, 0, 0, 1, x, y)
    var matrixValues = transform.split(',');
    // translate X value is in 12th or 4th position
    var xIndex = transform.indexOf('matrix3d') === 0 ? 12 : 4;
    var translateX = parseInt( matrixValues[ xIndex ], 10 );
    // translate Y value is in 13th or 5th position
    var translateY = parseInt( matrixValues[ xIndex + 1 ], 10 );
    this.position.x += translateX;
    this.position.y += translateY;
  };
  
  // -------------------------- events -------------------------- //
  
  // preventDefault if enabled and not a <select>. #141
  proto.canPreventDefaultOnPointerDown = function( event ) {
    // prevent default, unless touchstart or <select>
    return this.isEnabled && event.target.nodeName != 'SELECT';
  };
  
  /**
   * pointer start
   * @param {Event} event
   * @param {Event or Touch} pointer
   */
  proto.pointerDown = function( event, pointer ) {
    this._dragPointerDown( event, pointer );
    // kludge to blur focused inputs in dragger
    var focused = document.activeElement;
    // do not blur body for IE10, metafizzy/flickity#117
    if ( focused && focused.blur && focused != document.body ) {
      focused.blur();
    }
    // bind move and end events
    this._bindPostStartEvents( event );
    this.element.classList.add('is-pointer-down');
    this.dispatchEvent( 'pointerDown', event, [ pointer ] );
  };
  
  /**
   * drag move
   * @param {Event} event
   * @param {Event or Touch} pointer
   */
  proto.pointerMove = function( event, pointer ) {
    var moveVector = this._dragPointerMove( event, pointer );
    this.dispatchEvent( 'pointerMove', event, [ pointer, moveVector ] );
    this._dragMove( event, pointer, moveVector );
  };
  
  /**
   * drag start
   * @param {Event} event
   * @param {Event or Touch} pointer
   */
  proto.dragStart = function( event, pointer ) {
    if ( !this.isEnabled ) {
      return;
    }
    this._getPosition();
    this.measureContainment();
    // position _when_ drag began
    this.startPosition.x = this.position.x;
    this.startPosition.y = this.position.y;
    // reset left/top style
    this.setLeftTop();
  
    this.dragPoint.x = 0;
    this.dragPoint.y = 0;
  
    this.element.classList.add('is-dragging');
    this.dispatchEvent( 'dragStart', event, [ pointer ] );
    // start animation
    this.animate();
  };
  
  proto.measureContainment = function() {
    var containment = this.options.containment;
    if ( !containment ) {
      return;
    }
  
    // use element if element
    var container = isElement( containment ) ? containment :
      // fallback to querySelector if string
      typeof containment == 'string' ? document.querySelector( containment ) :
      // otherwise just `true`, use the parent
      this.element.parentNode;
  
    var elemSize = getSize( this.element );
    var containerSize = getSize( container );
    var elemRect = this.element.getBoundingClientRect();
    var containerRect = container.getBoundingClientRect();
  
    var borderSizeX = containerSize.borderLeftWidth + containerSize.borderRightWidth;
    var borderSizeY = containerSize.borderTopWidth + containerSize.borderBottomWidth;
  
    var position = this.relativeStartPosition = {
      x: elemRect.left - ( containerRect.left + containerSize.borderLeftWidth ),
      y: elemRect.top - ( containerRect.top + containerSize.borderTopWidth )
    };
  
    this.containSize = {
      width: ( containerSize.width - borderSizeX ) - position.x - elemSize.width,
      height: ( containerSize.height - borderSizeY ) - position.y - elemSize.height
    };
  };
  
  // ----- move event ----- //
  
  /**
   * drag move
   * @param {Event} event
   * @param {Event or Touch} pointer
   */
  proto.dragMove = function( event, pointer, moveVector ) {
    if ( !this.isEnabled ) {
      return;
    }
    var dragX = moveVector.x;
    var dragY = moveVector.y;
  
    var grid = this.options.grid;
    var gridX = grid && grid[0];
    var gridY = grid && grid[1];
  
    dragX = applyGrid( dragX, gridX );
    dragY = applyGrid( dragY, gridY );
  
    dragX = this.containDrag( 'x', dragX, gridX );
    dragY = this.containDrag( 'y', dragY, gridY );
  
    // constrain to axis
    dragX = this.options.axis == 'y' ? 0 : dragX;
    dragY = this.options.axis == 'x' ? 0 : dragY;
  
    this.position.x = this.startPosition.x + dragX;
    this.position.y = this.startPosition.y + dragY;
    // set dragPoint properties
    this.dragPoint.x = dragX;
    this.dragPoint.y = dragY;
  
    this.dispatchEvent( 'dragMove', event, [ pointer, moveVector ] );
  };
  
  function applyGrid( value, grid, method ) {
    method = method || 'round';
    return grid ? Math[ method ]( value / grid ) * grid : value;
  }
  
  proto.containDrag = function( axis, drag, grid ) {
    if ( !this.options.containment ) {
      return drag;
    }
    var measure = axis == 'x' ? 'width' : 'height';
  
    var rel = this.relativeStartPosition[ axis ];
    var min = applyGrid( -rel, grid, 'ceil' );
    var max = this.containSize[ measure ];
    max = applyGrid( max, grid, 'floor' );
    return  Math.min( max, Math.max( min, drag ) );
  };
  
  // ----- end event ----- //
  
  /**
   * pointer up
   * @param {Event} event
   * @param {Event or Touch} pointer
   */
  proto.pointerUp = function( event, pointer ) {
    this.element.classList.remove('is-pointer-down');
    this.dispatchEvent( 'pointerUp', event, [ pointer ] );
    this._dragPointerUp( event, pointer );
  };
  
  /**
   * drag end
   * @param {Event} event
   * @param {Event or Touch} pointer
   */
  proto.dragEnd = function( event, pointer ) {
    if ( !this.isEnabled ) {
      return;
    }
    // use top left position when complete
    if ( transformProperty ) {
      this.element.style[ transformProperty ] = '';
      this.setLeftTop();
    }
    this.element.classList.remove('is-dragging');
    this.dispatchEvent( 'dragEnd', event, [ pointer ] );
  };
  
  // -------------------------- animation -------------------------- //
  
  proto.animate = function() {
    // only render and animate if dragging
    if ( !this.isDragging ) {
      return;
    }
  
    this.positionDrag();
  
    var _this = this;
    requestAnimationFrame( function animateFrame() {
      _this.animate();
    });
  
  };
  
  // left/top positioning
  proto.setLeftTop = function() {
    this.element.style.left = this.position.x + 'px';
    this.element.style.top  = this.position.y + 'px';
  };
  
  proto.positionDrag = function() {
    this.element.style[ transformProperty ] = 'translate3d( ' + this.dragPoint.x +
      'px, ' + this.dragPoint.y + 'px, 0)';
  };
  
  // ----- staticClick ----- //
  
  proto.staticClick = function( event, pointer ) {
    this.dispatchEvent( 'staticClick', event, [ pointer ] );
  };
  
  // ----- methods ----- //
  
  proto.enable = function() {
    this.isEnabled = true;
  };
  
  proto.disable = function() {
    this.isEnabled = false;
    if ( this.isDragging ) {
      this.dragEnd();
    }
  };
  
  proto.destroy = function() {
    this.disable();
    // reset styles
    this.element.style[ transformProperty ] = '';
    this.element.style.left = '';
    this.element.style.top = '';
    this.element.style.position = '';
    // unbind handles
    this.unbindHandles();
    // remove jQuery data
    if ( this.$element ) {
      this.$element.removeData('draggabilly');
    }
  };
  
  // ----- jQuery bridget ----- //
  
  // required for jQuery bridget
  proto._init = noop;
  
  if ( jQuery && jQuery.bridget ) {
    jQuery.bridget( 'draggabilly', Draggabilly );
  }
  
  // -----  ----- //
  
  return Draggabilly;
  
  }));
  
  