/*!

* Masonry PACKAGED v4.2.2
* Cascading grid layout library
* https://masonry.desandro.com
* MIT License
* by David DeSandro
*/

/**

* 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 ) { 'use strict';

// —– 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;

}));

/**

* EvEmitter v1.1.0
* 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;
}
// copy over to avoid interference if .off() in listener
listeners = listeners.slice(0);
args = args || [];
// once stuff
var onceListeners = this._onceEvents && this._onceEvents[ eventName ];

for ( var i=0; i < listeners.length; i++ ) {
  var listener = listeners[i]
  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 );
}

return this;

};

proto.allOff = function() {

delete this._events;
delete this._onceEvents;

};

return EvEmitter;

}));

/*!

* getSize v2.0.3
* measure size of elements
* MIT license
*/

/* jshint browser: true, strict: true, undef: true, unused: true */ /* globals console: false */

( function( window, factory ) {

/* jshint strict: false */ /* globals define, module */
if ( typeof define == 'function' && define.amd ) {
  // AMD
  define( 'get-size/get-size',factory );
} else if ( typeof module == 'object' && module.exports ) {
  // CommonJS
  module.exports = factory();
} else {
  // browser global
  window.getSize = factory();
}

})( window, function factory() { 'use strict';

// ————————– 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 https://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 -------------------------- //

/**
 * Chrome & Safari measure the outer-width on style.width on border-box elems
 * IE11 & 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 );
// round value for browser zoom. desandro/masonry#928
isBoxSizeOuter = Math.round( getStyleSize( style.width ) ) == 200;
getSize.isBoxSizeOuter = isBoxSizeOuter;

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;

});

/**

* matchesSelector v2.0.2
* matchesSelector( element, '.selector' )
* MIT license
*/

/*jshint browser: true, strict: true, undef: true, unused: true */

( function( window, factory ) {

/*global define: false, module: false */
'use strict';
// universal module definition
if ( typeof define == 'function' && define.amd ) {
  // AMD
  define( 'desandro-matches-selector/matches-selector',factory );
} else if ( typeof module == 'object' && module.exports ) {
  // CommonJS
  module.exports = factory();
} else {
  // browser global
  window.matchesSelector = factory();
}

}( window, function factory() {

'use strict';

var matchesMethod = ( function() {
  var ElemProto = window.Element.prototype;
  // check for the standard method name first
  if ( ElemProto.matches ) {
    return 'matches';
  }
  // check un-prefixed
  if ( ElemProto.matchesSelector ) {
    return 'matchesSelector';
  }
  // check vendor prefixes
  var prefixes = [ 'webkit', 'moz', 'ms', 'o' ];

  for ( var i=0; i < prefixes.length; i++ ) {
    var prefix = prefixes[i];
    var method = prefix + 'MatchesSelector';
    if ( ElemProto[ method ] ) {
      return method;
    }
  }
})();

return function matchesSelector( elem, selector ) {
  return elem[ matchesMethod ]( selector );
};

}));

/**

* Fizzy UI utils v2.0.7
* MIT license
*/

/*jshint browser: true, undef: true, unused: true, strict: true */

( function( window, factory ) {

// universal module definition
/*jshint strict: false */ /*globals define, module, require */

if ( typeof define == 'function' && define.amd ) {
  // AMD
  define( 'fizzy-ui-utils/utils',[
    'desandro-matches-selector/matches-selector'
  ], function( matchesSelector ) {
    return factory( window, matchesSelector );
  });
} else if ( typeof module == 'object' && module.exports ) {
  // CommonJS
  module.exports = factory(
    window,
    require('desandro-matches-selector')
  );
} else {
  // browser global
  window.fizzyUIUtils = factory(
    window,
    window.matchesSelector
  );
}

}( window, function factory( window, matchesSelector ) {

var utils = {};

// —– extend —– //

// extends objects utils.extend = function( a, b ) {

for ( var prop in b ) {
  a[ prop ] = b[ prop ];
}
return a;

};

// —– modulo —– //

utils.modulo = function( num, div ) {

return ( ( num % div ) + div ) % div;

};

// —– makeArray —– //

var arraySlice = Array.prototype.slice;

// turn element or nodeList into an array utils.makeArray = function( obj ) {

if ( Array.isArray( obj ) ) {
  // use object if already an array
  return obj;
}
// return empty array if undefined or null. #6
if ( obj === null || obj === undefined ) {
  return [];
}

var isArrayLike = typeof obj == 'object' && typeof obj.length == 'number';
if ( isArrayLike ) {
  // convert nodeList to array
  return arraySlice.call( obj );
}

// array of single index
return [ obj ];

};

// —– removeFrom —– //

utils.removeFrom = function( ary, obj ) {

var index = ary.indexOf( obj );
if ( index != -1 ) {
  ary.splice( index, 1 );
}

};

// —– getParent —– //

utils.getParent = function( elem, selector ) {

while ( elem.parentNode && elem != document.body ) {
  elem = elem.parentNode;
  if ( matchesSelector( elem, selector ) ) {
    return elem;
  }
}

};

// —– getQueryElement —– //

// use element as selector string utils.getQueryElement = function( elem ) {

if ( typeof elem == 'string' ) {
  return document.querySelector( elem );
}
return elem;

};

// —– handleEvent —– //

// enable .ontype to trigger from .addEventListener( elem, 'type' ) utils.handleEvent = function( event ) {

var method = 'on' + event.type;
if ( this[ method ] ) {
  this[ method ]( event );
}

};

// —– filterFindElements —– //

utils.filterFindElements = function( elems, selector ) {

// make array of elems
elems = utils.makeArray( elems );
var ffElems = [];

elems.forEach( function( elem ) {
  // check that elem is an actual element
  if ( !( elem instanceof HTMLElement ) ) {
    return;
  }
  // add elem if no selector
  if ( !selector ) {
    ffElems.push( elem );
    return;
  }
  // filter & find items if we have a selector
  // filter
  if ( matchesSelector( elem, selector ) ) {
    ffElems.push( elem );
  }
  // find children
  var childElems = elem.querySelectorAll( selector );
  // concat childElems to filterFound array
  for ( var i=0; i < childElems.length; i++ ) {
    ffElems.push( childElems[i] );
  }
});

return ffElems;

};

// —– debounceMethod —– //

utils.debounceMethod = function( _class, methodName, threshold ) {

threshold = threshold || 100;
// original method
var method = _class.prototype[ methodName ];
var timeoutName = methodName + 'Timeout';

_class.prototype[ methodName ] = function() {
  var timeout = this[ timeoutName ];
  clearTimeout( timeout );

  var args = arguments;
  var _this = this;
  this[ timeoutName ] = setTimeout( function() {
    method.apply( _this, args );
    delete _this[ timeoutName ];
  }, threshold );
};

};

// —– docReady —– //

utils.docReady = function( callback ) {

var readyState = document.readyState;
if ( readyState == 'complete' || readyState == 'interactive' ) {
  // do async to allow for other scripts to run. metafizzy/flickity#441
  setTimeout( callback );
} else {
  document.addEventListener( 'DOMContentLoaded', callback );
}

};

// —– htmlInit —– //

// jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/ utils.toDashed = function( str ) {

return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) {
  return $1 + '-' + $2;
}).toLowerCase();

};

var console = window.console; /**

* allow user to initialize classes via [data-namespace] or .js-namespace class
* htmlInit( Widget, 'widgetName' )
* options are parsed from data-namespace-options
*/

utils.htmlInit = function( WidgetClass, namespace ) {

utils.docReady( function() {
  var dashedNamespace = utils.toDashed( namespace );
  var dataAttr = 'data-' + dashedNamespace;
  var dataAttrElems = document.querySelectorAll( '[' + dataAttr + ']' );
  var jsDashElems = document.querySelectorAll( '.js-' + dashedNamespace );
  var elems = utils.makeArray( dataAttrElems )
    .concat( utils.makeArray( jsDashElems ) );
  var dataOptionsAttr = dataAttr + '-options';
  var jQuery = window.jQuery;

  elems.forEach( function( elem ) {
    var attr = elem.getAttribute( dataAttr ) ||
      elem.getAttribute( dataOptionsAttr );
    var options;
    try {
      options = attr && JSON.parse( attr );
    } catch ( error ) {
      // log error, do not initialize
      if ( console ) {
        console.error( 'Error parsing ' + dataAttr + ' on ' + elem.className +
        ': ' + error );
      }
      return;
    }
    // initialize
    var instance = new WidgetClass( elem, options );
    // make available via $().data('namespace')
    if ( jQuery ) {
      jQuery.data( elem, namespace, instance );
    }
  });

});

};

// —– —– //

return utils;

}));

/**

* Outlayer Item
*/

( function( window, factory ) {

// universal module definition
/* jshint strict: false */ /* globals define, module, require */
if ( typeof define == 'function' && define.amd ) {
  // AMD - RequireJS
  define( 'outlayer/item',[
      'ev-emitter/ev-emitter',
      'get-size/get-size'
    ],
    factory
  );
} else if ( typeof module == 'object' && module.exports ) {
  // CommonJS - Browserify, Webpack
  module.exports = factory(
    require('ev-emitter'),
    require('get-size')
  );
} else {
  // browser global
  window.Outlayer = {};
  window.Outlayer.Item = factory(
    window.EvEmitter,
    window.getSize
  );
}

}( window, function factory( EvEmitter, getSize ) { 'use strict';

// —– helpers —– //

function isEmptyObj( obj ) {

for ( var prop in obj ) {
  return false;
}
prop = null;
return true;

}

// ————————– CSS3 support ————————– //

var docElemStyle = document.documentElement.style;

var transitionProperty = typeof docElemStyle.transition == 'string' ?

'transition' : 'WebkitTransition';

var transformProperty = typeof docElemStyle.transform == 'string' ?

'transform' : 'WebkitTransform';

var transitionEndEvent = {

WebkitTransition: 'webkitTransitionEnd',
transition: 'transitionend'

}[ transitionProperty ];

// cache all vendor properties that could have vendor prefix var vendorProperties = {

transform: transformProperty,
transition: transitionProperty,
transitionDuration: transitionProperty + 'Duration',
transitionProperty: transitionProperty + 'Property',
transitionDelay: transitionProperty + 'Delay'

};

// ————————– Item ————————– //

function Item( element, layout ) {

if ( !element ) {
  return;
}

this.element = element;
// parent layout class, i.e. Masonry, Isotope, or Packery
this.layout = layout;
this.position = {
  x: 0,
  y: 0
};

this._create();

}

// inherit EvEmitter var proto = Item.prototype = Object.create( EvEmitter.prototype ); proto.constructor = Item;

proto._create = function() {

// transition objects
this._transn = {
  ingProperties: {},
  clean: {},
  onEnd: {}
};

this.css({
  position: 'absolute'
});

};

// trigger specified handler for event type proto.handleEvent = function( event ) {

var method = 'on' + event.type;
if ( this[ method ] ) {
  this[ method ]( event );
}

};

proto.getSize = function() {

this.size = getSize( this.element );

};

/**

* apply CSS styles to element
* @param {Object} style
*/

proto.css = function( style ) {

var elemStyle = this.element.style;

for ( var prop in style ) {
  // use vendor property if available
  var supportedProp = vendorProperties[ prop ] || prop;
  elemStyle[ supportedProp ] = style[ prop ];
}

};

// measure position, and sets it

proto.getPosition = function() {

var style = getComputedStyle( this.element );
var isOriginLeft = this.layout._getOption('originLeft');
var isOriginTop = this.layout._getOption('originTop');
var xValue = style[ isOriginLeft ? 'left' : 'right' ];
var yValue = style[ isOriginTop ? 'top' : 'bottom' ];
var x = parseFloat( xValue );
var y = parseFloat( yValue );
// convert percent to pixels
var layoutSize = this.layout.size;
if ( xValue.indexOf('%') != -1 ) {
  x = ( x / 100 ) * layoutSize.width;
}
if ( yValue.indexOf('%') != -1 ) {
  y = ( y / 100 ) * layoutSize.height;
}
// clean up 'auto' or other non-integer values
x = isNaN( x ) ? 0 : x;
y = isNaN( y ) ? 0 : y;
// remove padding from measurement
x -= isOriginLeft ? layoutSize.paddingLeft : layoutSize.paddingRight;
y -= isOriginTop ? layoutSize.paddingTop : layoutSize.paddingBottom;

this.position.x = x;
this.position.y = y;

};

// set settled position, apply padding proto.layoutPosition = function() {

var layoutSize = this.layout.size;
var style = {};
var isOriginLeft = this.layout._getOption('originLeft');
var isOriginTop = this.layout._getOption('originTop');

// x
var xPadding = isOriginLeft ? 'paddingLeft' : 'paddingRight';
var xProperty = isOriginLeft ? 'left' : 'right';
var xResetProperty = isOriginLeft ? 'right' : 'left';

var x = this.position.x + layoutSize[ xPadding ];
// set in percentage or pixels
style[ xProperty ] = this.getXValue( x );
// reset other property
style[ xResetProperty ] = '';

// y
var yPadding = isOriginTop ? 'paddingTop' : 'paddingBottom';
var yProperty = isOriginTop ? 'top' : 'bottom';
var yResetProperty = isOriginTop ? 'bottom' : 'top';

var y = this.position.y + layoutSize[ yPadding ];
// set in percentage or pixels
style[ yProperty ] = this.getYValue( y );
// reset other property
style[ yResetProperty ] = '';

this.css( style );
this.emitEvent( 'layout', [ this ] );

};

proto.getXValue = function( x ) {

var isHorizontal = this.layout._getOption('horizontal');
return this.layout.options.percentPosition && !isHorizontal ?
  ( ( x / this.layout.size.width ) * 100 ) + '%' : x + 'px';

};

proto.getYValue = function( y ) {

var isHorizontal = this.layout._getOption('horizontal');
return this.layout.options.percentPosition && isHorizontal ?
  ( ( y / this.layout.size.height ) * 100 ) + '%' : y + 'px';

};

proto._transitionTo = function( x, y ) {

this.getPosition();
// get current x & y from top/left
var curX = this.position.x;
var curY = this.position.y;

var didNotMove = x == this.position.x && y == this.position.y;

// save end position
this.setPosition( x, y );

// if did not move and not transitioning, just go to layout
if ( didNotMove && !this.isTransitioning ) {
  this.layoutPosition();
  return;
}

var transX = x - curX;
var transY = y - curY;
var transitionStyle = {};
transitionStyle.transform = this.getTranslate( transX, transY );

this.transition({
  to: transitionStyle,
  onTransitionEnd: {
    transform: this.layoutPosition
  },
  isCleaning: true
});

};

proto.getTranslate = function( x, y ) {

// flip cooridinates if origin on right or bottom
var isOriginLeft = this.layout._getOption('originLeft');
var isOriginTop = this.layout._getOption('originTop');
x = isOriginLeft ? x : -x;
y = isOriginTop ? y : -y;
return 'translate3d(' + x + 'px, ' + y + 'px, 0)';

};

// non transition + transform support proto.goTo = function( x, y ) {

this.setPosition( x, y );
this.layoutPosition();

};

proto.moveTo = proto._transitionTo;

proto.setPosition = function( x, y ) {

this.position.x = parseFloat( x );
this.position.y = parseFloat( y );

};

// —– transition —– //

/**

* @param {Object} style - CSS
* @param {Function} onTransitionEnd
*/

// non transition, just trigger callback proto._nonTransition = function( args ) {

this.css( args.to );
if ( args.isCleaning ) {
  this._removeStyles( args.to );
}
for ( var prop in args.onTransitionEnd ) {
  args.onTransitionEnd[ prop ].call( this );
}

};

/**

* proper transition
* @param {Object} args - arguments
*   @param {Object} to - style to transition to
*   @param {Object} from - style to start transition from
*   @param {Boolean} isCleaning - removes transition styles after transition
*   @param {Function} onTransitionEnd - callback
*/

proto.transition = function( args ) {

// redirect to nonTransition if no transition duration
if ( !parseFloat( this.layout.options.transitionDuration ) ) {
  this._nonTransition( args );
  return;
}

var _transition = this._transn;
// keep track of onTransitionEnd callback by css property
for ( var prop in args.onTransitionEnd ) {
  _transition.onEnd[ prop ] = args.onTransitionEnd[ prop ];
}
// keep track of properties that are transitioning
for ( prop in args.to ) {
  _transition.ingProperties[ prop ] = true;
  // keep track of properties to clean up when transition is done
  if ( args.isCleaning ) {
    _transition.clean[ prop ] = true;
  }
}

// set from styles
if ( args.from ) {
  this.css( args.from );
  // force redraw. http://blog.alexmaccaw.com/css-transitions
  var h = this.element.offsetHeight;
  // hack for JSHint to hush about unused var
  h = null;
}
// enable transition
this.enableTransition( args.to );
// set styles that are transitioning
this.css( args.to );

this.isTransitioning = true;

};

// dash before all cap letters, including first for // WebkitTransform => -webkit-transform function toDashedAll( str ) {

return str.replace( /([A-Z])/g, function( $1 ) {
  return '-' + $1.toLowerCase();
});

}

var transitionProps = 'opacity,' + toDashedAll( transformProperty );

proto.enableTransition = function(/* style */) {

// HACK changing transitionProperty during a transition
// will cause transition to jump
if ( this.isTransitioning ) {
  return;
}

// make `transition: foo, bar, baz` from style object
// HACK un-comment this when enableTransition can work
// while a transition is happening
// var transitionValues = [];
// for ( var prop in style ) {
//   // dash-ify camelCased properties like WebkitTransition
//   prop = vendorProperties[ prop ] || prop;
//   transitionValues.push( toDashedAll( prop ) );
// }
// munge number to millisecond, to match stagger
var duration = this.layout.options.transitionDuration;
duration = typeof duration == 'number' ? duration + 'ms' : duration;
// enable transition styles
this.css({
  transitionProperty: transitionProps,
  transitionDuration: duration,
  transitionDelay: this.staggerDelay || 0
});
// listen for transition end event
this.element.addEventListener( transitionEndEvent, this, false );

};

// —– events —– //

proto.onwebkitTransitionEnd = function( event ) {

this.ontransitionend( event );

};

proto.onotransitionend = function( event ) {

this.ontransitionend( event );

};

// properties that I munge to make my life easier var dashedVendorProperties = {

'-webkit-transform': 'transform'

};

proto.ontransitionend = function( event ) {

// disregard bubbled events from children
if ( event.target !== this.element ) {
  return;
}
var _transition = this._transn;
// get property name of transitioned property, convert to prefix-free
var propertyName = dashedVendorProperties[ event.propertyName ] || event.propertyName;

// remove property that has completed transitioning
delete _transition.ingProperties[ propertyName ];
// check if any properties are still transitioning
if ( isEmptyObj( _transition.ingProperties ) ) {
  // all properties have completed transitioning
  this.disableTransition();
}
// clean style
if ( propertyName in _transition.clean ) {
  // clean up style
  this.element.style[ event.propertyName ] = '';
  delete _transition.clean[ propertyName ];
}
// trigger onTransitionEnd callback
if ( propertyName in _transition.onEnd ) {
  var onTransitionEnd = _transition.onEnd[ propertyName ];
  onTransitionEnd.call( this );
  delete _transition.onEnd[ propertyName ];
}

this.emitEvent( 'transitionEnd', [ this ] );

};

proto.disableTransition = function() {

this.removeTransitionStyles();
this.element.removeEventListener( transitionEndEvent, this, false );
this.isTransitioning = false;

};

/**

* removes style property from element
* @param {Object} style

**/ proto._removeStyles = function( style ) {

// clean up transition styles
var cleanStyle = {};
for ( var prop in style ) {
  cleanStyle[ prop ] = '';
}
this.css( cleanStyle );

};

var cleanTransitionStyle = {

transitionProperty: '',
transitionDuration: '',
transitionDelay: ''

};

proto.removeTransitionStyles = function() {

// remove transition
this.css( cleanTransitionStyle );

};

// —– stagger —– //

proto.stagger = function( delay ) {

delay = isNaN( delay ) ? 0 : delay;
this.staggerDelay = delay + 'ms';

};

// —– show/hide/remove —– //

// remove element from DOM proto.removeElem = function() {

this.element.parentNode.removeChild( this.element );
// remove display: none
this.css({ display: '' });
this.emitEvent( 'remove', [ this ] );

};

proto.remove = function() {

// just remove element if no transition support or no transition
if ( !transitionProperty || !parseFloat( this.layout.options.transitionDuration ) ) {
  this.removeElem();
  return;
}

// start transition
this.once( 'transitionEnd', function() {
  this.removeElem();
});
this.hide();

};

proto.reveal = function() {

delete this.isHidden;
// remove display: none
this.css({ display: '' });

var options = this.layout.options;

var onTransitionEnd = {};
var transitionEndProperty = this.getHideRevealTransitionEndProperty('visibleStyle');
onTransitionEnd[ transitionEndProperty ] = this.onRevealTransitionEnd;

this.transition({
  from: options.hiddenStyle,
  to: options.visibleStyle,
  isCleaning: true,
  onTransitionEnd: onTransitionEnd
});

};

proto.onRevealTransitionEnd = function() {

// check if still visible
// during transition, item may have been hidden
if ( !this.isHidden ) {
  this.emitEvent('reveal');
}

};

/**

* get style property use for hide/reveal transition end
* @param {String} styleProperty - hiddenStyle/visibleStyle
* @returns {String}
*/

proto.getHideRevealTransitionEndProperty = function( styleProperty ) {

var optionStyle = this.layout.options[ styleProperty ];
// use opacity
if ( optionStyle.opacity ) {
  return 'opacity';
}
// get first property
for ( var prop in optionStyle ) {
  return prop;
}

};

proto.hide = function() {

// set flag
this.isHidden = true;
// remove display: none
this.css({ display: '' });

var options = this.layout.options;

var onTransitionEnd = {};
var transitionEndProperty = this.getHideRevealTransitionEndProperty('hiddenStyle');
onTransitionEnd[ transitionEndProperty ] = this.onHideTransitionEnd;

this.transition({
  from: options.visibleStyle,
  to: options.hiddenStyle,
  // keep hidden stuff hidden
  isCleaning: true,
  onTransitionEnd: onTransitionEnd
});

};

proto.onHideTransitionEnd = function() {

// check if still hidden
// during transition, item may have been un-hidden
if ( this.isHidden ) {
  this.css({ display: 'none' });
  this.emitEvent('hide');
}

};

proto.destroy = function() {

this.css({
  position: '',
  left: '',
  right: '',
  top: '',
  bottom: '',
  transition: '',
  transform: ''
});

};

return Item;

}));

/*!

* Outlayer v2.1.1
* the brains and guts of a layout library
* MIT license
*/

( function( window, factory ) {

'use strict';
// universal module definition
/* jshint strict: false */ /* globals define, module, require */
if ( typeof define == 'function' && define.amd ) {
  // AMD - RequireJS
  define( 'outlayer/outlayer',[
      'ev-emitter/ev-emitter',
      'get-size/get-size',
      'fizzy-ui-utils/utils',
      './item'
    ],
    function( EvEmitter, getSize, utils, Item ) {
      return factory( window, EvEmitter, getSize, utils, Item);
    }
  );
} else if ( typeof module == 'object' && module.exports ) {
  // CommonJS - Browserify, Webpack
  module.exports = factory(
    window,
    require('ev-emitter'),
    require('get-size'),
    require('fizzy-ui-utils'),
    require('./item')
  );
} else {
  // browser global
  window.Outlayer = factory(
    window,
    window.EvEmitter,
    window.getSize,
    window.fizzyUIUtils,
    window.Outlayer.Item
  );
}

}( window, function factory( window, EvEmitter, getSize, utils, Item ) { 'use strict';

// —– vars —– //

var console = window.console; var jQuery = window.jQuery; var noop = function() {};

// ————————– Outlayer ————————– //

// globally unique identifiers var GUID = 0; // internal store of all Outlayer intances var instances = {};

/**

* @param {Element, String} element
* @param {Object} options
* @constructor
*/

function Outlayer( element, options ) {

var queryElement = utils.getQueryElement( element );
if ( !queryElement ) {
  if ( console ) {
    console.error( 'Bad element for ' + this.constructor.namespace +
      ': ' + ( queryElement || element ) );
  }
  return;
}
this.element = queryElement;
// add jQuery
if ( jQuery ) {
  this.$element = jQuery( this.element );
}

// options
this.options = utils.extend( {}, this.constructor.defaults );
this.option( options );

// add id for Outlayer.getFromElement
var id = ++GUID;
this.element.outlayerGUID = id; // expando
instances[ id ] = this; // associate via id

// kick it off
this._create();

var isInitLayout = this._getOption('initLayout');
if ( isInitLayout ) {
  this.layout();
}

}

// settings are for internal use only Outlayer.namespace = 'outlayer'; Outlayer.Item = Item;

// default options Outlayer.defaults = {

containerStyle: {
  position: 'relative'
},
initLayout: true,
originLeft: true,
originTop: true,
resize: true,
resizeContainer: true,
// item options
transitionDuration: '0.4s',
hiddenStyle: {
  opacity: 0,
  transform: 'scale(0.001)'
},
visibleStyle: {
  opacity: 1,
  transform: 'scale(1)'
}

};

var proto = Outlayer.prototype; // inherit EvEmitter utils.extend( proto, EvEmitter.prototype );

/**

* set options
* @param {Object} opts
*/

proto.option = function( opts ) {

utils.extend( this.options, opts );

};

/**

* get backwards compatible option value, check old name
*/

proto._getOption = function( option ) {

var oldOption = this.constructor.compatOptions[ option ];
return oldOption && this.options[ oldOption ] !== undefined ?
  this.options[ oldOption ] : this.options[ option ];

};

Outlayer.compatOptions = {

// currentName: oldName
initLayout: 'isInitLayout',
horizontal: 'isHorizontal',
layoutInstant: 'isLayoutInstant',
originLeft: 'isOriginLeft',
originTop: 'isOriginTop',
resize: 'isResizeBound',
resizeContainer: 'isResizingContainer'

};

proto._create = function() {

// get items from children
this.reloadItems();
// elements that affect layout, but are not laid out
this.stamps = [];
this.stamp( this.options.stamp );
// set container style
utils.extend( this.element.style, this.options.containerStyle );

// bind resize method
var canBindResize = this._getOption('resize');
if ( canBindResize ) {
  this.bindResize();
}

};

// goes through all children again and gets bricks in proper order proto.reloadItems = function() {

// collection of item elements
this.items = this._itemize( this.element.children );

};

/**

* turn elements into Outlayer.Items to be used in layout
* @param {Array or NodeList or HTMLElement} elems
* @returns {Array} items - collection of new Outlayer Items
*/

proto._itemize = function( elems ) {

var itemElems = this._filterFindItemElements( elems );
var Item = this.constructor.Item;

// create new Outlayer Items for collection
var items = [];
for ( var i=0; i < itemElems.length; i++ ) {
  var elem = itemElems[i];
  var item = new Item( elem, this );
  items.push( item );
}

return items;

};

/**

* get item elements to be used in layout
* @param {Array or NodeList or HTMLElement} elems
* @returns {Array} items - item elements
*/

proto._filterFindItemElements = function( elems ) {

return utils.filterFindElements( elems, this.options.itemSelector );

};

/**

* getter method for getting item elements
* @returns {Array} elems - collection of item elements
*/

proto.getItemElements = function() {

return this.items.map( function( item ) {
  return item.element;
});

};

// —– init & layout —– //

/**

* lays out all items
*/

proto.layout = function() {

this._resetLayout();
this._manageStamps();

// don't animate first layout
var layoutInstant = this._getOption('layoutInstant');
var isInstant = layoutInstant !== undefined ?
  layoutInstant : !this._isLayoutInited;
this.layoutItems( this.items, isInstant );

// flag for initalized
this._isLayoutInited = true;

};

// _init is alias for layout proto._init = proto.layout;

/**

* logic before any new layout
*/

proto._resetLayout = function() {

this.getSize();

};

proto.getSize = function() {

this.size = getSize( this.element );

};

/**

* get measurement from option, for columnWidth, rowHeight, gutter
* if option is String -> get element from selector string, & get size of element
* if option is Element -> get size of element
* else use option as a number
*
* @param {String} measurement
* @param {String} size - width or height
* @private
*/

proto._getMeasurement = function( measurement, size ) {

var option = this.options[ measurement ];
var elem;
if ( !option ) {
  // default to 0
  this[ measurement ] = 0;
} else {
  // use option as an element
  if ( typeof option == 'string' ) {
    elem = this.element.querySelector( option );
  } else if ( option instanceof HTMLElement ) {
    elem = option;
  }
  // use size of element, if element
  this[ measurement ] = elem ? getSize( elem )[ size ] : option;
}

};

/**

* layout a collection of item elements
* @api public
*/

proto.layoutItems = function( items, isInstant ) {

items = this._getItemsForLayout( items );

this._layoutItems( items, isInstant );

this._postLayout();

};

/**

* get the items to be laid out
* you may want to skip over some items
* @param {Array} items
* @returns {Array} items
*/

proto._getItemsForLayout = function( items ) {

return items.filter( function( item ) {
  return !item.isIgnored;
});

};

/**

* layout items
* @param {Array} items
* @param {Boolean} isInstant
*/

proto._layoutItems = function( items, isInstant ) {

this._emitCompleteOnItems( 'layout', items );

if ( !items || !items.length ) {
  // no items, emit event with empty array
  return;
}

var queue = [];

items.forEach( function( item ) {
  // get x/y object from method
  var position = this._getItemLayoutPosition( item );
  // enqueue
  position.item = item;
  position.isInstant = isInstant || item.isLayoutInstant;
  queue.push( position );
}, this );

this._processLayoutQueue( queue );

};

/**

* get item layout position
* @param {Outlayer.Item} item
* @returns {Object} x and y position
*/

proto._getItemLayoutPosition = function( /* item */ ) {

return {
  x: 0,
  y: 0
};

};

/**

* iterate over array and position each item
* Reason being - separating this logic prevents 'layout invalidation'
* thx @paul_irish
* @param {Array} queue
*/

proto._processLayoutQueue = function( queue ) {

this.updateStagger();
queue.forEach( function( obj, i ) {
  this._positionItem( obj.item, obj.x, obj.y, obj.isInstant, i );
}, this );

};

// set stagger from option in milliseconds number proto.updateStagger = function() {

var stagger = this.options.stagger;
if ( stagger === null || stagger === undefined ) {
  this.stagger = 0;
  return;
}
this.stagger = getMilliseconds( stagger );
return this.stagger;

};

/**

* Sets position of item in DOM
* @param {Outlayer.Item} item
* @param {Number} x - horizontal position
* @param {Number} y - vertical position
* @param {Boolean} isInstant - disables transitions
*/

proto._positionItem = function( item, x, y, isInstant, i ) {

if ( isInstant ) {
  // if not transition, just set CSS
  item.goTo( x, y );
} else {
  item.stagger( i * this.stagger );
  item.moveTo( x, y );
}

};

/**

* Any logic you want to do after each layout,
* i.e. size the container
*/

proto._postLayout = function() {

this.resizeContainer();

};

proto.resizeContainer = function() {

var isResizingContainer = this._getOption('resizeContainer');
if ( !isResizingContainer ) {
  return;
}
var size = this._getContainerSize();
if ( size ) {
  this._setContainerMeasure( size.width, true );
  this._setContainerMeasure( size.height, false );
}

};

/**

* Sets width or height of container if returned
* @returns {Object} size
*   @param {Number} width
*   @param {Number} height
*/

proto._getContainerSize = noop;

/**

* @param {Number} measure - size of width or height
* @param {Boolean} isWidth
*/

proto._setContainerMeasure = function( measure, isWidth ) {

if ( measure === undefined ) {
  return;
}

var elemSize = this.size;
// add padding and border width if border box
if ( elemSize.isBorderBox ) {
  measure += isWidth ? elemSize.paddingLeft + elemSize.paddingRight +
    elemSize.borderLeftWidth + elemSize.borderRightWidth :
    elemSize.paddingBottom + elemSize.paddingTop +
    elemSize.borderTopWidth + elemSize.borderBottomWidth;
}

measure = Math.max( measure, 0 );
this.element.style[ isWidth ? 'width' : 'height' ] = measure + 'px';

};

/**

* emit eventComplete on a collection of items events
* @param {String} eventName
* @param {Array} items - Outlayer.Items
*/

proto._emitCompleteOnItems = function( eventName, items ) {

var _this = this;
function onComplete() {
  _this.dispatchEvent( eventName + 'Complete', null, [ items ] );
}

var count = items.length;
if ( !items || !count ) {
  onComplete();
  return;
}

var doneCount = 0;
function tick() {
  doneCount++;
  if ( doneCount == count ) {
    onComplete();
  }
}

// bind callback
items.forEach( function( item ) {
  item.once( eventName, tick );
});

};

/**

* 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 ) {

// add original event to arguments
var emitArgs = event ? [ event ].concat( args ) : args;
this.emitEvent( type, emitArgs );

if ( jQuery ) {
  // set this.$element
  this.$element = this.$element || 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 );
  }
}

};

// ————————– ignore & stamps ————————– //

/**

* keep item in collection, but do not lay it out
* ignored items do not get skipped in layout
* @param {Element} elem
*/

proto.ignore = function( elem ) {

var item = this.getItem( elem );
if ( item ) {
  item.isIgnored = true;
}

};

/**

* return item to layout collection
* @param {Element} elem
*/

proto.unignore = function( elem ) {

var item = this.getItem( elem );
if ( item ) {
  delete item.isIgnored;
}

};

/**

* adds elements to stamps
* @param {NodeList, Array, Element, or String} elems
*/

proto.stamp = function( elems ) {

elems = this._find( elems );
if ( !elems ) {
  return;
}

this.stamps = this.stamps.concat( elems );
// ignore
elems.forEach( this.ignore, this );

};

/**

* removes elements to stamps
* @param {NodeList, Array, or Element} elems
*/

proto.unstamp = function( elems ) {

elems = this._find( elems );
if ( !elems ){
  return;
}

elems.forEach( function( elem ) {
  // filter out removed stamp elements
  utils.removeFrom( this.stamps, elem );
  this.unignore( elem );
}, this );

};

/**

* finds child elements
* @param {NodeList, Array, Element, or String} elems
* @returns {Array} elems
*/

proto._find = function( elems ) {

if ( !elems ) {
  return;
}
// if string, use argument as selector string
if ( typeof elems == 'string' ) {
  elems = this.element.querySelectorAll( elems );
}
elems = utils.makeArray( elems );
return elems;

};

proto._manageStamps = function() {

if ( !this.stamps || !this.stamps.length ) {
  return;
}

this._getBoundingRect();

this.stamps.forEach( this._manageStamp, this );

};

// update boundingLeft / Top proto._getBoundingRect = function() {

// get bounding rect for container element
var boundingRect = this.element.getBoundingClientRect();
var size = this.size;
this._boundingRect = {
  left: boundingRect.left + size.paddingLeft + size.borderLeftWidth,
  top: boundingRect.top + size.paddingTop + size.borderTopWidth,
  right: boundingRect.right - ( size.paddingRight + size.borderRightWidth ),
  bottom: boundingRect.bottom - ( size.paddingBottom + size.borderBottomWidth )
};

};

/**

* @param {Element} stamp

**/ proto._manageStamp = noop;

/**

* get x/y position of element relative to container element
* @param {Element} elem
* @returns {Object} offset - has left, top, right, bottom
*/

proto._getElementOffset = function( elem ) {

var boundingRect = elem.getBoundingClientRect();
var thisRect = this._boundingRect;
var size = getSize( elem );
var offset = {
  left: boundingRect.left - thisRect.left - size.marginLeft,
  top: boundingRect.top - thisRect.top - size.marginTop,
  right: thisRect.right - boundingRect.right - size.marginRight,
  bottom: thisRect.bottom - boundingRect.bottom - size.marginBottom
};
return offset;

};

// ————————– resize ————————– //

// enable event handlers for listeners // i.e. resize -> onresize proto.handleEvent = utils.handleEvent;

/**

* Bind layout to window resizing
*/

proto.bindResize = function() {

window.addEventListener( 'resize', this );
this.isResizeBound = true;

};

/**

* Unbind layout to window resizing
*/

proto.unbindResize = function() {

window.removeEventListener( 'resize', this );
this.isResizeBound = false;

};

proto.onresize = function() {

this.resize();

};

utils.debounceMethod( Outlayer, 'onresize', 100 );

proto.resize = function() {

// don't trigger if size did not change
// or if resize was unbound. See #9
if ( !this.isResizeBound || !this.needsResizeLayout() ) {
  return;
}

this.layout();

};

/**

* check if layout is needed post layout
* @returns Boolean
*/

proto.needsResizeLayout = function() {

var size = getSize( this.element );
// check that this.size and size are there
// IE8 triggers resize on body size change, so they might not be
var hasSizes = this.size && size;
return hasSizes && size.innerWidth !== this.size.innerWidth;

};

// ————————– methods ————————– //

/**

* add items to Outlayer instance
* @param {Array or NodeList or Element} elems
* @returns {Array} items - Outlayer.Items

**/ proto.addItems = function( elems ) {

var items = this._itemize( elems );
// add items to collection
if ( items.length ) {
  this.items = this.items.concat( items );
}
return items;

};

/**

* Layout newly-appended item elements
* @param {Array or NodeList or Element} elems
*/

proto.appended = function( elems ) {

var items = this.addItems( elems );
if ( !items.length ) {
  return;
}
// layout and reveal just the new items
this.layoutItems( items, true );
this.reveal( items );

};

/**

* Layout prepended elements
* @param {Array or NodeList or Element} elems
*/

proto.prepended = function( elems ) {

var items = this._itemize( elems );
if ( !items.length ) {
  return;
}
// add items to beginning of collection
var previousItems = this.items.slice(0);
this.items = items.concat( previousItems );
// start new layout
this._resetLayout();
this._manageStamps();
// layout new stuff without transition
this.layoutItems( items, true );
this.reveal( items );
// layout previous items
this.layoutItems( previousItems );

};

/**

* reveal a collection of items
* @param {Array of Outlayer.Items} items
*/

proto.reveal = function( items ) {

this._emitCompleteOnItems( 'reveal', items );
if ( !items || !items.length ) {
  return;
}
var stagger = this.updateStagger();
items.forEach( function( item, i ) {
  item.stagger( i * stagger );
  item.reveal();
});

};

/**

* hide a collection of items
* @param {Array of Outlayer.Items} items
*/

proto.hide = function( items ) {

this._emitCompleteOnItems( 'hide', items );
if ( !items || !items.length ) {
  return;
}
var stagger = this.updateStagger();
items.forEach( function( item, i ) {
  item.stagger( i * stagger );
  item.hide();
});

};

/**

* reveal item elements
* @param {Array}, {Element}, {NodeList} items
*/

proto.revealItemElements = function( elems ) {

var items = this.getItems( elems );
this.reveal( items );

};

/**

* hide item elements
* @param {Array}, {Element}, {NodeList} items
*/

proto.hideItemElements = function( elems ) {

var items = this.getItems( elems );
this.hide( items );

};

/**

* get Outlayer.Item, given an Element
* @param {Element} elem
* @param {Function} callback
* @returns {Outlayer.Item} item
*/

proto.getItem = function( elem ) {

// loop through items to get the one that matches
for ( var i=0; i < this.items.length; i++ ) {
  var item = this.items[i];
  if ( item.element == elem ) {
    // return item
    return item;
  }
}

};

/**

* get collection of Outlayer.Items, given Elements
* @param {Array} elems
* @returns {Array} items - Outlayer.Items
*/

proto.getItems = function( elems ) {

elems = utils.makeArray( elems );
var items = [];
elems.forEach( function( elem ) {
  var item = this.getItem( elem );
  if ( item ) {
    items.push( item );
  }
}, this );

return items;

};

/**

* remove element(s) from instance and DOM
* @param {Array or NodeList or Element} elems
*/

proto.remove = function( elems ) {

var removeItems = this.getItems( elems );

this._emitCompleteOnItems( 'remove', removeItems );

// bail if no items to remove
if ( !removeItems || !removeItems.length ) {
  return;
}

removeItems.forEach( function( item ) {
  item.remove();
  // remove item from collection
  utils.removeFrom( this.items, item );
}, this );

};

// —– destroy —– //

// remove and disable Outlayer instance proto.destroy = function() {

// clean up dynamic styles
var style = this.element.style;
style.height = '';
style.position = '';
style.width = '';
// destroy items
this.items.forEach( function( item ) {
  item.destroy();
});

this.unbindResize();

var id = this.element.outlayerGUID;
delete instances[ id ]; // remove reference to instance by id
delete this.element.outlayerGUID;
// remove data for jQuery
if ( jQuery ) {
  jQuery.removeData( this.element, this.constructor.namespace );
}

};

// ————————– data ————————– //

/**

* get Outlayer instance from element
* @param {Element} elem
* @returns {Outlayer}
*/

Outlayer.data = function( elem ) {

elem = utils.getQueryElement( elem );
var id = elem && elem.outlayerGUID;
return id && instances[ id ];

};

// ————————– create Outlayer class ————————– //

/**

* create a layout class
* @param {String} namespace
*/

Outlayer.create = function( namespace, options ) {

// sub-class Outlayer
var Layout = subclass( Outlayer );
// apply new options and compatOptions
Layout.defaults = utils.extend( {}, Outlayer.defaults );
utils.extend( Layout.defaults, options );
Layout.compatOptions = utils.extend( {}, Outlayer.compatOptions  );

Layout.namespace = namespace;

Layout.data = Outlayer.data;

// sub-class Item
Layout.Item = subclass( Item );

// -------------------------- declarative -------------------------- //

utils.htmlInit( Layout, namespace );

// -------------------------- jQuery bridge -------------------------- //

// make into jQuery plugin
if ( jQuery && jQuery.bridget ) {
  jQuery.bridget( namespace, Layout );
}

return Layout;

};

function subclass( Parent ) {

function SubClass() {
  Parent.apply( this, arguments );
}

SubClass.prototype = Object.create( Parent.prototype );
SubClass.prototype.constructor = SubClass;

return SubClass;

}

// —– helpers —– //

// how many milliseconds are in each unit var msUnits = {

ms: 1,
s: 1000

};

// munge time-like parameter into millisecond number // '0.4s' -> 40 function getMilliseconds( time ) {

if ( typeof time == 'number' ) {
  return time;
}
var matches = time.match( /(^\d*\.?\d*)(\w*)/ );
var num = matches && matches[1];
var unit = matches && matches[2];
if ( !num.length ) {
  return 0;
}
num = parseFloat( num );
var mult = msUnits[ unit ] || 1;
return num * mult;

}

// —– fin —– //

// back in global Outlayer.Item = Item;

return Outlayer;

}));

/*!

* Masonry v4.2.2
* Cascading grid layout library
* https://masonry.desandro.com
* MIT License
* by David DeSandro
*/

( function( window, factory ) {

// universal module definition
/* jshint strict: false */ /*globals define, module, require */
if ( typeof define == 'function' && define.amd ) {
  // AMD
  define( [
      'outlayer/outlayer',
      'get-size/get-size'
    ],
    factory );
} else if ( typeof module == 'object' && module.exports ) {
  // CommonJS
  module.exports = factory(
    require('outlayer'),
    require('get-size')
  );
} else {
  // browser global
  window.Masonry = factory(
    window.Outlayer,
    window.getSize
  );
}

}( window, function factory( Outlayer, getSize ) {

// ————————– masonryDefinition ————————– //

// create an Outlayer layout class
var Masonry = Outlayer.create('masonry');
// isFitWidth -> fitWidth
Masonry.compatOptions.fitWidth = 'isFitWidth';

var proto = Masonry.prototype;

proto._resetLayout = function() {
  this.getSize();
  this._getMeasurement( 'columnWidth', 'outerWidth' );
  this._getMeasurement( 'gutter', 'outerWidth' );
  this.measureColumns();

  // reset column Y
  this.colYs = [];
  for ( var i=0; i < this.cols; i++ ) {
    this.colYs.push( 0 );
  }

  this.maxY = 0;
  this.horizontalColIndex = 0;
};

proto.measureColumns = function() {
  this.getContainerWidth();
  // if columnWidth is 0, default to outerWidth of first item
  if ( !this.columnWidth ) {
    var firstItem = this.items[0];
    var firstItemElem = firstItem && firstItem.element;
    // columnWidth fall back to item of first element
    this.columnWidth = firstItemElem && getSize( firstItemElem ).outerWidth ||
      // if first elem has no width, default to size of container
      this.containerWidth;
  }

  var columnWidth = this.columnWidth += this.gutter;

  // calculate columns
  var containerWidth = this.containerWidth + this.gutter;
  var cols = containerWidth / columnWidth;
  // fix rounding errors, typically with gutters
  var excess = columnWidth - containerWidth % columnWidth;
  // if overshoot is less than a pixel, round up, otherwise floor it
  var mathMethod = excess && excess < 1 ? 'round' : 'floor';
  cols = Math[ mathMethod ]( cols );
  this.cols = Math.max( cols, 1 );
};

proto.getContainerWidth = function() {
  // container is parent if fit width
  var isFitWidth = this._getOption('fitWidth');
  var container = isFitWidth ? this.element.parentNode : this.element;
  // check that this.size and size are there
  // IE8 triggers resize on body size change, so they might not be
  var size = getSize( container );
  this.containerWidth = size && size.innerWidth;
};

proto._getItemLayoutPosition = function( item ) {
  item.getSize();
  // how many columns does this brick span
  var remainder = item.size.outerWidth % this.columnWidth;
  var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
  // round if off by 1 pixel, otherwise use ceil
  var colSpan = Math[ mathMethod ]( item.size.outerWidth / this.columnWidth );
  colSpan = Math.min( colSpan, this.cols );
  // use horizontal or top column position
  var colPosMethod = this.options.horizontalOrder ?
    '_getHorizontalColPosition' : '_getTopColPosition';
  var colPosition = this[ colPosMethod ]( colSpan, item );
  // position the brick
  var position = {
    x: this.columnWidth * colPosition.col,
    y: colPosition.y
  };
  // apply setHeight to necessary columns
  var setHeight = colPosition.y + item.size.outerHeight;
  var setMax = colSpan + colPosition.col;
  for ( var i = colPosition.col; i < setMax; i++ ) {
    this.colYs[i] = setHeight;
  }

  return position;
};

proto._getTopColPosition = function( colSpan ) {
  var colGroup = this._getTopColGroup( colSpan );
  // get the minimum Y value from the columns
  var minimumY = Math.min.apply( Math, colGroup );

  return {
    col: colGroup.indexOf( minimumY ),
    y: minimumY,
  };
};

/**
 * @param {Number} colSpan - number of columns the element spans
 * @returns {Array} colGroup
 */
proto._getTopColGroup = function( colSpan ) {
  if ( colSpan < 2 ) {
    // if brick spans only one column, use all the column Ys
    return this.colYs;
  }

  var colGroup = [];
  // how many different places could this brick fit horizontally
  var groupCount = this.cols + 1 - colSpan;
  // for each group potential horizontal position
  for ( var i = 0; i < groupCount; i++ ) {
    colGroup[i] = this._getColGroupY( i, colSpan );
  }
  return colGroup;
};

proto._getColGroupY = function( col, colSpan ) {
  if ( colSpan < 2 ) {
    return this.colYs[ col ];
  }
  // make an array of colY values for that one group
  var groupColYs = this.colYs.slice( col, col + colSpan );
  // and get the max value of the array
  return Math.max.apply( Math, groupColYs );
};

// get column position based on horizontal index. #873
proto._getHorizontalColPosition = function( colSpan, item ) {
  var col = this.horizontalColIndex % this.cols;
  var isOver = colSpan > 1 && col + colSpan > this.cols;
  // shift to next row if item can't fit on current row
  col = isOver ? 0 : col;
  // don't let zero-size items take up space
  var hasSize = item.size.outerWidth && item.size.outerHeight;
  this.horizontalColIndex = hasSize ? col + colSpan : this.horizontalColIndex;

  return {
    col: col,
    y: this._getColGroupY( col, colSpan ),
  };
};

proto._manageStamp = function( stamp ) {
  var stampSize = getSize( stamp );
  var offset = this._getElementOffset( stamp );
  // get the columns that this stamp affects
  var isOriginLeft = this._getOption('originLeft');
  var firstX = isOriginLeft ? offset.left : offset.right;
  var lastX = firstX + stampSize.outerWidth;
  var firstCol = Math.floor( firstX / this.columnWidth );
  firstCol = Math.max( 0, firstCol );
  var lastCol = Math.floor( lastX / this.columnWidth );
  // lastCol should not go over if multiple of columnWidth #425
  lastCol -= lastX % this.columnWidth ? 0 : 1;
  lastCol = Math.min( this.cols - 1, lastCol );
  // set colYs to bottom of the stamp

  var isOriginTop = this._getOption('originTop');
  var stampMaxY = ( isOriginTop ? offset.top : offset.bottom ) +
    stampSize.outerHeight;
  for ( var i = firstCol; i <= lastCol; i++ ) {
    this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
  }
};

proto._getContainerSize = function() {
  this.maxY = Math.max.apply( Math, this.colYs );
  var size = {
    height: this.maxY
  };

  if ( this._getOption('fitWidth') ) {
    size.width = this._getContainerFitWidth();
  }

  return size;
};

proto._getContainerFitWidth = function() {
  var unusedCols = 0;
  // count unused columns
  var i = this.cols;
  while ( --i ) {
    if ( this.colYs[i] !== 0 ) {
      break;
    }
    unusedCols++;
  }
  // fit container to columns that have been used
  return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
};

proto.needsResizeLayout = function() {
  var previousWidth = this.containerWidth;
  this.getContainerWidth();
  return previousWidth != this.containerWidth;
};

return Masonry;

}));