PageSourceSearch

https://st-albertus.sch.id/wp-content/plugins/builderpress/assets/libs/isotope/isotope.pkgd.min.js?ver=7.1.3

js st-albertus.sch.id collected 2026-10-08 18:48:54 UTC 88,020 bytes, 3,578 lines download raw bytes

vendor: 38,691 bytes, lines 1-1575
1/*!
2 * Isotope PACKAGED v3.0.5
3 *
4 * Licensed GPLv3 for open source use
5 * or Isotope Commercial License for commercial use
6 *
7 * https://isotope.metafizzy.co
8 * Copyright 2017 Metafizzy
9 */
10
11/**
12 * Bridget makes jQuery widgets
13 * v2.0.1
14 * MIT license
15 */
16
17/* jshint browser: true, strict: true, undef: true, unused: true */
18
19(function (window, factory) {
20	// universal module definition
21	/*jshint strict: false */
22	/* globals define, module, require */
23	if (typeof define == 'function' && define.amd) {
24		// AMD
25		define('jquery-bridget/jquery-bridget', ['jquery'], function (jQuery) {
26			return factory(window, jQuery);
27		});
28	} else if (typeof module == 'object' && module.exports) {
29		// CommonJS
30		module.exports = factory(
31			window,
32			require('jquery')
33		);
34	} else {
35		// browser global
36		window.jQueryBridget = factory(
37			window,
38			window.jQuery
39		);
40	}
41
42}(window, function factory(window, jQuery) {
43	'use strict';
44
45// ----- utils ----- //
46
47	var arraySlice = Array.prototype.slice;
48
49// helper function for logging errors
50// $.error breaks jQuery chaining
51	var console = window.console;
52	var logError = typeof console == 'undefined' ? function () {
53		} :
54		function (message) {
55			console.error(message);
56		};
57
58// ----- jQueryBridget ----- //
59
60	function jQueryBridget(namespace, PluginClass, $) {
61		$ = $ || jQuery || window.jQuery;
62		if (!$) {
63			return;
64		}
65
66		// add option method -> $().plugin('option', {...})
67		if (!PluginClass.prototype.option) {
68			// option setter
69			PluginClass.prototype.option = function (opts) {
70				// bail out if not an object
71				if (!$.isPlainObject(opts)) {
72					return;
73				}
74				this.options = $.extend(true, this.options, opts);
75			};
76		}
77
78		// make jQuery plugin
79		$.fn[namespace] = function (arg0 /*, arg1 */) {
80			if (typeof arg0 == 'string') {
81				// method call $().plugin( 'methodName', { options } )
82				// shift arguments by 1
83				var args = arraySlice.call(arguments, 1);
84				return methodCall(this, arg0, args);
85			}
86			// just $().plugin({ options })
87			plainCall(this, arg0);
88			return this;
89		};
90
91		// $().plugin('methodName')
92		function methodCall($elems, methodName, args) {
93			var returnValue;
94			var pluginMethodStr = '$().' + namespace + '("' + methodName + '")';
95
96			$elems.each(function (i, elem) {
97				// get instance
98				var instance = $.data(elem, namespace);
99				if (!instance) {
100					logError(namespace + ' not initialized. Cannot call methods, i.e. ' +
101						pluginMethodStr);
102					return;
103				}
104
105				var method = instance[methodName];
106				if (!method || methodName.charAt(0) == '_') {
107					logError(pluginMethodStr + ' is not a valid method');
108					return;
109				}
110
111				// apply method, get return value
112				var value = method.apply(instance, args);
113				// set return value if value is returned, use only first value
114				returnValue = returnValue === undefined ? value : returnValue;
115			});
116
117			return returnValue !== undefined ? returnValue : $elems;
118		}
119
120		function plainCall($elems, options) {
121			$elems.each(function (i, elem) {
122				var instance = $.data(elem, namespace);
123				if (instance) {
124					// set options & init
125					instance.option(options);
126					instance._init();
127				} else {
128					// initialize new instance
129					instance = new PluginClass(elem, options);
130					$.data(elem, namespace, instance);
131				}
132			});
133		}
134
135		updateJQuery($);
136
137	}
138
139// ----- updateJQuery ----- //
140
141// set $.bridget for v1 backwards compatibility
142	function updateJQuery($) {
143		if (!$ || ($ && $.bridget)) {
144			return;
145		}
146		$.bridget = jQueryBridget;
147	}
148
149	updateJQuery(jQuery || window.jQuery);
150
151// -----  ----- //
152
153	return jQueryBridget;
154
155}));
156
157/**
158 * EvEmitter v1.1.0
159 * Lil' event emitter
160 * MIT License
161 */
162
163/* jshint unused: true, undef: true, strict: true */
164
165(function (global, factory) {
166	// universal module definition
167	/* jshint strict: false */
168	/* globals define, module, window */
169	if (typeof define == 'function' && define.amd) {
170		// AMD - RequireJS
171		define('ev-emitter/ev-emitter', factory);
172	} else if (typeof module == 'object' && module.exports) {
173		// CommonJS - Browserify, Webpack
174		module.exports = factory();
175	} else {
176		// Browser globals
177		global.EvEmitter = factory();
178	}
179
180}(typeof window != 'undefined' ? window : this, function () {
181
182
183	function EvEmitter() {
184	}
185
186	var proto = EvEmitter.prototype;
187
188	proto.on = function (eventName, listener) {
189		if (!eventName || !listener) {
190			return;
191		}
192		// set events hash
193		var events = this._events = this._events || {};
194		// set listeners array
195		var listeners = events[eventName] = events[eventName] || [];
196		// only add once
197		if (listeners.indexOf(listener) == -1) {
198			listeners.push(listener);
199		}
200
201		return this;
202	};
203
204	proto.once = function (eventName, listener) {
205		if (!eventName || !listener) {
206			return;
207		}
208		// add event
209		this.on(eventName, listener);
210		// set once flag
211		// set onceEvents hash
212		var onceEvents = this._onceEvents = this._onceEvents || {};
213		// set onceListeners object
214		var onceListeners = onceEvents[eventName] = onceEvents[eventName] || {};
215		// set flag
216		onceListeners[listener] = true;
217
218		return this;
219	};
220
221	proto.off = function (eventName, listener) {
222		var listeners = this._events && this._events[eventName];
223		if (!listeners || !listeners.length) {
224			return;
225		}
226		var index = listeners.indexOf(listener);
227		if (index != -1) {
228			listeners.splice(index, 1);
229		}
230
231		return this;
232	};
233
234	proto.emitEvent = function (eventName, args) {
235		var listeners = this._events && this._events[eventName];
236		if (!listeners || !listeners.length) {
237			return;
238		}
239		// copy over to avoid interference if .off() in listener
240		listeners = listeners.slice(0);
241		args = args || [];
242		// once stuff
243		var onceListeners = this._onceEvents && this._onceEvents[eventName];
244
245		for (var i = 0; i < listeners.length; i++) {
246			var listener = listeners[i]
247			var isOnce = onceListeners && onceListeners[listener];
248			if (isOnce) {
249				// remove listener
250				// remove before trigger to prevent recursion
251				this.off(eventName, listener);
252				// unset once flag
253				delete onceListeners[listener];
254			}
255			// trigger listener
256			listener.apply(this, args);
257		}
258
259		return this;
260	};
261
262	proto.allOff = function () {
263		delete this._events;
264		delete this._onceEvents;
265	};
266
267	return EvEmitter;
268
269}));
270
271/*!
272 * getSize v2.0.2
273 * measure size of elements
274 * MIT license
275 */
276
277/*jshint browser: true, strict: true, undef: true, unused: true */
278/*global define: false, module: false, console: false */
279
280(function (window, factory) {
281	'use strict';
282
283	if (typeof define == 'function' && define.amd) {
284		// AMD
285		define('get-size/get-size', [], function () {
286			return factory();
287		});
288	} else if (typeof module == 'object' && module.exports) {
289		// CommonJS
290		module.exports = factory();
291	} else {
292		// browser global
293		window.getSize = factory();
294	}
295
296})(window, function factory() {
297	'use strict';
298
299// -------------------------- helpers -------------------------- //
300
301// get a number from a string, not a percentage
302	function getStyleSize(value) {
303		var num = parseFloat(value);
304		// not a percent like '100%', and a number
305		var isValid = value.indexOf('%') == -1 && !isNaN(num);
306		return isValid && num;
307	}
308
309	function noop() {
310	}
311
312	var logError = typeof console == 'undefined' ? noop :
313		function (message) {
314			console.error(message);
315		};
316
317// -------------------------- measurements -------------------------- //
318
319	var measurements = [
320		'paddingLeft',
321		'paddingRight',
322		'paddingTop',
323		'paddingBottom',
324		'marginLeft',
325		'marginRight',
326		'marginTop',
327		'marginBottom',
328		'borderLeftWidth',
329		'borderRightWidth',
330		'borderTopWidth',
331		'borderBottomWidth'
332	];
333
334	var measurementsLength = measurements.length;
335
336	function getZeroSize() {
337		var size = {
338			width      : 0,
339			height     : 0,
340			innerWidth : 0,
341			innerHeight: 0,
342			outerWidth : 0,
343			outerHeight: 0
344		};
345		for (var i = 0; i < measurementsLength; i++) {
346			var measurement = measurements[i];
347			size[measurement] = 0;
348		}
349		return size;
350	}
351
352// -------------------------- getStyle -------------------------- //
353
354	/**
355	 * getStyle, get style of element, check for Firefox bug
356	 * https://bugzilla.mozilla.org/show_bug.cgi?id=548397
357	 */
358	function getStyle(elem) {
359		var style = getComputedStyle(elem);
360		if (!style) {
361			logError('Style returned ' + style +
362				'. Are you running this code in a hidden iframe on Firefox? ' +
363				'See http://bit.ly/getsizebug1');
364		}
365		return style;
366	}
367
368// -------------------------- setup -------------------------- //
369
370	var isSetup = false;
371
372	var isBoxSizeOuter;
373
374	/**
375	 * setup
376	 * check isBoxSizerOuter
377	 * do on first getSize() rather than on page load for Firefox bug
378	 */
379	function setup() {
380		// setup once
381		if (isSetup) {
382			return;
383		}
384		isSetup = true;
385
386		// -------------------------- box sizing -------------------------- //
387
388		/**
389		 * WebKit measures the outer-width on style.width on border-box elems
390		 * IE & Firefox<29 measures the inner-width
391		 */
392		var div = document.createElement('div');
393		div.style.width = '200px';
394		div.style.padding = '1px 2px 3px 4px';
395		div.style.borderStyle = 'solid';
396		div.style.borderWidth = '1px 2px 3px 4px';
397		div.style.boxSizing = 'border-box';
398
399		var body = document.body || document.documentElement;
400		body.appendChild(div);
401		var style = getStyle(div);
402
403		getSize.isBoxSizeOuter = isBoxSizeOuter = getStyleSize(style.width) == 200;
404		body.removeChild(div);
405
406	}
407
408// -------------------------- getSize -------------------------- //
409
410	function getSize(elem) {
411		setup();
412
413		// use querySeletor if elem is string
414		if (typeof elem == 'string') {
415			elem = document.querySelector(elem);
416		}
417
418		// do not proceed on non-objects
419		if (!elem || typeof elem != 'object' || !elem.nodeType) {
420			return;
421		}
422
423		var style = getStyle(elem);
424
425		// if hidden, everything is 0
426		if (style.display == 'none') {
427			return getZeroSize();
428		}
429
430		var size = {};
431		size.width = elem.offsetWidth;
432		size.height = elem.offsetHeight;
433
434		var isBorderBox = size.isBorderBox = style.boxSizing == 'border-box';
435
436		// get all measurements
437		for (var i = 0; i < measurementsLength; i++) {
438			var measurement = measurements[i];
439			var value = style[measurement];
440			var num = parseFloat(value);
441			// any 'auto', 'medium' value will be 0
442			size[measurement] = !isNaN(num) ? num : 0;
443		}
444
445		var paddingWidth = size.paddingLeft + size.paddingRight;
446		var paddingHeight = size.paddingTop + size.paddingBottom;
447		var marginWidth = size.marginLeft + size.marginRight;
448		var marginHeight = size.marginTop + size.marginBottom;
449		var borderWidth = size.borderLeftWidth + size.borderRightWidth;
450		var borderHeight = size.borderTopWidth + size.borderBottomWidth;
451
452		var isBorderBoxSizeOuter = isBorderBox && isBoxSizeOuter;
453
454		// overwrite width and height if we can get it from style
455		var styleWidth = getStyleSize(style.width);
456		if (styleWidth !== false) {
457			size.width = styleWidth +
458				// add padding and border unless it's already including it
459				(isBorderBoxSizeOuter ? 0 : paddingWidth + borderWidth);
460		}
461
462		var styleHeight = getStyleSize(style.height);
463		if (styleHeight !== false) {
464			size.height = styleHeight +
465				// add padding and border unless it's already including it
466				(isBorderBoxSizeOuter ? 0 : paddingHeight + borderHeight);
467		}
468
469		size.innerWidth = size.width - (paddingWidth + borderWidth);
470		size.innerHeight = size.height - (paddingHeight + borderHeight);
471
472		size.outerWidth = size.width + marginWidth;
473		size.outerHeight = size.height + marginHeight;
474
475		return size;
476	}
477
478	return getSize;
479
480});
481
482/**
483 * matchesSelector v2.0.2
484 * matchesSelector( element, '.selector' )
485 * MIT license
486 */
487
488/*jshint browser: true, strict: true, undef: true, unused: true */
489
490(function (window, factory) {
491	/*global define: false, module: false */
492	'use strict';
493	// universal module definition
494	if (typeof define == 'function' && define.amd) {
495		// AMD
496		define('desandro-matches-selector/matches-selector', factory);
497	} else if (typeof module == 'object' && module.exports) {
498		// CommonJS
499		module.exports = factory();
500	} else {
501		// browser global
502		window.matchesSelector = factory();
503	}
504
505}(window, function factory() {
506	'use strict';
507
508	var matchesMethod = (function () {
509		var ElemProto = window.Element.prototype;
510		// check for the standard method name first
511		if (ElemProto.matches) {
512			return 'matches';
513		}
514		// check un-prefixed
515		if (ElemProto.matchesSelector) {
516			return 'matchesSelector';
517		}
518		// check vendor prefixes
519		var prefixes = ['webkit', 'moz', 'ms', 'o'];
520
521		for (var i = 0; i < prefixes.length; i++) {
522			var prefix = prefixes[i];
523			var method = prefix + 'MatchesSelector';
524			if (ElemProto[method]) {
525				return method;
526			}
527		}
528	})();
529
530	return function matchesSelector(elem, selector) {
531		return elem[matchesMethod](selector);
532	};
533
534}));
535
536/**
537 * Fizzy UI utils v2.0.5
538 * MIT license
539 */
540
541/*jshint browser: true, undef: true, unused: true, strict: true */
542
543(function (window, factory) {
544	// universal module definition
545	/*jshint strict: false */
546	/*globals define, module, require */
547
548	if (typeof define == 'function' && define.amd) {
549		// AMD
550		define('fizzy-ui-utils/utils', [
551			'desandro-matches-selector/matches-selector'
552		], function (matchesSelector) {
553			return factory(window, matchesSelector);
554		});
555	} else if (typeof module == 'object' && module.exports) {
556		// CommonJS
557		module.exports = factory(
558			window,
559			require('desandro-matches-selector')
560		);
561	} else {
562		// browser global
563		window.fizzyUIUtils = factory(
564			window,
565			window.matchesSelector
566		);
567	}
568
569}(window, function factory(window, matchesSelector) {
570
571
572	var utils = {};
573
574// ----- extend ----- //
575
576// extends objects
577	utils.extend = function (a, b) {
578		for (var prop in b) {
579			a[prop] = b[prop];
580		}
581		return a;
582	};
583
584// ----- modulo ----- //
585
586	utils.modulo = function (num, div) {
587		return ((num % div) + div) % div;
588	};
589
590// ----- makeArray ----- //
591
592// turn element or nodeList into an array
593	utils.makeArray = function (obj) {
594		var ary = [];
595		if (Array.isArray(obj)) {
596			// use object if already an array
597			ary = obj;
598		} else if (obj && typeof obj == 'object' &&
599			typeof obj.length == 'number') {
600			// convert nodeList to array
601			for (var i = 0; i < obj.length; i++) {
602				ary.push(obj[i]);
603			}
604		} else {
605			// array of single index
606			ary.push(obj);
607		}
608		return ary;
609	};
610
611// ----- removeFrom ----- //
612
613	utils.removeFrom = function (ary, obj) {
614		var index = ary.indexOf(obj);
615		if (index != -1) {
616			ary.splice(index, 1);
617		}
618	};
619
620// ----- getParent ----- //
621
622	utils.getParent = function (elem, selector) {
623		while (elem.parentNode && elem != document.body) {
624			elem = elem.parentNode;
625			if (matchesSelector(elem, selector)) {
626				return elem;
627			}
628		}
629	};
630
631// ----- getQueryElement ----- //
632
633// use element as selector string
634	utils.getQueryElement = function (elem) {
635		if (typeof elem == 'string') {
636			return document.querySelector(elem);
637		}
638		return elem;
639	};
640
641// ----- handleEvent ----- //
642
643// enable .ontype to trigger from .addEventListener( elem, 'type' )
644	utils.handleEvent = function (event) {
645		var method = 'on' + event.type;
646		if (this[method]) {
647			this[method](event);
648		}
649	};
650
651// ----- filterFindElements ----- //
652
653	utils.filterFindElements = function (elems, selector) {
654		// make array of elems
655		elems = utils.makeArray(elems);
656		var ffElems = [];
657
658		elems.forEach(function (elem) {
659			// check that elem is an actual element
660			if (!(elem instanceof HTMLElement)) {
661				return;
662			}
663			// add elem if no selector
664			if (!selector) {
665				ffElems.push(elem);
666				return;
667			}
668			// filter & find items if we have a selector
669			// filter
670			if (matchesSelector(elem, selector)) {
671				ffElems.push(elem);
672			}
673			// find children
674			var childElems = elem.querySelectorAll(selector);
675			// concat childElems to filterFound array
676			for (var i = 0; i < childElems.length; i++) {
677				ffElems.push(childElems[i]);
678			}
679		});
680
681		return ffElems;
682	};
683
684// ----- debounceMethod ----- //
685
686	utils.debounceMethod = function (_class, methodName, threshold) {
687		// original method
688		var method = _class.prototype[methodName];
689		var timeoutName = methodName + 'Timeout';
690
691		_class.prototype[methodName] = function () {
692			var timeout = this[timeoutName];
693			if (timeout) {
694				clearTimeout(timeout);
695			}
696			var args = arguments;
697
698			var _this = this;
699			this[timeoutName] = setTimeout(function () {
700				method.apply(_this, args);
701				delete _this[timeoutName];
702			}, threshold || 100);
703		};
704	};
705
706// ----- docReady ----- //
707
708	utils.docReady = function (callback) {
709		var readyState = document.readyState;
710		if (readyState == 'complete' || readyState == 'interactive') {
711			// do async to allow for other scripts to run. metafizzy/flickity#441
712			setTimeout(callback);
713		} else {
714			document.addEventListener('DOMContentLoaded', callback);
715		}
716	};
717
718// ----- htmlInit ----- //
719
720// http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/
721	utils.toDashed = function (str) {
722		return str.replace(/(.)([A-Z])/g, function (match, $1, $2) {
723			return $1 + '-' + $2;
724		}).toLowerCase();
725	};
726
727	var console = window.console;
728	/**
729	 * allow user to initialize classes via [data-namespace] or .js-namespace class
730	 * htmlInit( Widget, 'widgetName' )
731	 * options are parsed from data-namespace-options
732	 */
733	utils.htmlInit = function (WidgetClass, namespace) {
734		utils.docReady(function () {
735			var dashedNamespace = utils.toDashed(namespace);
736			var dataAttr = 'data-' + dashedNamespace;
737			var dataAttrElems = document.querySelectorAll('[' + dataAttr + ']');
738			var jsDashElems = document.querySelectorAll('.js-' + dashedNamespace);
739			var elems = utils.makeArray(dataAttrElems)
740				.concat(utils.makeArray(jsDashElems));
741			var dataOptionsAttr = dataAttr + '-options';
742			var jQuery = window.jQuery;
743
744			elems.forEach(function (elem) {
745				var attr = elem.getAttribute(dataAttr) ||
746					elem.getAttribute(dataOptionsAttr);
747				var options;
748				try {
749					options = attr && JSON.parse(attr);
750				} catch (error) {
751					// log error, do not initialize
752					if (console) {
753						console.error('Error parsing ' + dataAttr + ' on ' + elem.className +
754							': ' + error);
755					}
756					return;
757				}
758				// initialize
759				var instance = new WidgetClass(elem, options);
760				// make available via $().data('namespace')
761				if (jQuery) {
762					jQuery.data(elem, namespace, instance);
763				}
764			});
765
766		});
767	};
768
769// -----  ----- //
770
771	return utils;
772
773}));
774
775/**
776 * Outlayer Item
777 */
778
779(function (window, factory) {
780	// universal module definition
781	/* jshint strict: false */
782	/* globals define, module, require */
783	if (typeof define == 'function' && define.amd) {
784		// AMD - RequireJS
785		define('outlayer/item', [
786				'ev-emitter/ev-emitter',
787				'get-size/get-size'
788			],
789			factory
790		);
791	} else if (typeof module == 'object' && module.exports) {
792		// CommonJS - Browserify, Webpack
793		module.exports = factory(
794			require('ev-emitter'),
795			require('get-size')
796		);
797	} else {
798		// browser global
799		window.Outlayer = {};
800		window.Outlayer.Item = factory(
801			window.EvEmitter,
802			window.getSize
803		);
804	}
805
806}(window, function factory(EvEmitter, getSize) {
807	'use strict';
808
809// ----- helpers ----- //
810
811	function isEmptyObj(obj) {
812		for (var prop in obj) {
813			return false;
814		}
815		prop = null;
816		return true;
817	}
818
819// -------------------------- CSS3 support -------------------------- //
820
821
822	var docElemStyle = document.documentElement.style;
823
824	var transitionProperty = typeof docElemStyle.transition == 'string' ?
825		'transition' : 'WebkitTransition';
826	var transformProperty = typeof docElemStyle.transform == 'string' ?
827		'transform' : 'WebkitTransform';
828
829	var transitionEndEvent = {
830		WebkitTransition: 'webkitTransitionEnd',
831		transition      : 'transitionend'
832	}[transitionProperty];
833
834// cache all vendor properties that could have vendor prefix
835	var vendorProperties = {
836		transform         : transformProperty,
837		transition        : transitionProperty,
838		transitionDuration: transitionProperty + 'Duration',
839		transitionProperty: transitionProperty + 'Property',
840		transitionDelay   : transitionProperty + 'Delay'
841	};
842
843// -------------------------- Item -------------------------- //
844
845	function Item(element, layout) {
846		if (!element) {
847			return;
848		}
849
850		this.element = element;
851		// parent layout class, i.e. Masonry, Isotope, or Packery
852		this.layout = layout;
853		this.position = {
854			x: 0,
855			y: 0
856		};
857
858		this._create();
859	}
860
861// inherit EvEmitter
862	var proto = Item.prototype = Object.create(EvEmitter.prototype);
863	proto.constructor = Item;
864
865	proto._create = function () {
866		// transition objects
867		this._transn = {
868			ingProperties: {},
869			clean        : {},
870			onEnd        : {}
871		};
872
873		this.css({
874			position: 'absolute'
875		});
876	};
877
878// trigger specified handler for event type
879	proto.handleEvent = function (event) {
880		var method = 'on' + event.type;
881		if (this[method]) {
882			this[method](event);
883		}
884	};
885
886	proto.getSize = function () {
887		this.size = getSize(this.element);
888	};
889
890	/**
891	 * apply CSS styles to element
892	 * @param {Object} style
893	 */
894	proto.css = function (style) {
895		var elemStyle = this.element.style;
896
897		for (var prop in style) {
898			// use vendor property if available
899			var supportedProp = vendorProperties[prop] || prop;
900			elemStyle[supportedProp] = style[prop];
901		}
902	};
903
904	// measure position, and sets it
905	proto.getPosition = function () {
906		var style = getComputedStyle(this.element);
907		var isOriginLeft = this.layout._getOption('originLeft');
908		var isOriginTop = this.layout._getOption('originTop');
909		var xValue = style[isOriginLeft ? 'left' : 'right'];
910		var yValue = style[isOriginTop ? 'top' : 'bottom'];
911		// convert percent to pixels
912		var layoutSize = this.layout.size;
913		var x = xValue.indexOf('%') != -1 ?
914			(parseFloat(xValue) / 100) * layoutSize.width : parseInt(xValue, 10);
915		var y = yValue.indexOf('%') != -1 ?
916			(parseFloat(yValue) / 100) * layoutSize.height : parseInt(yValue, 10);
917
918		// clean up 'auto' or other non-integer values
919		x = isNaN(x) ? 0 : x;
920		y = isNaN(y) ? 0 : y;
921		// remove padding from measurement
922		x -= isOriginLeft ? layoutSize.paddingLeft : layoutSize.paddingRight;
923		y -= isOriginTop ? layoutSize.paddingTop : layoutSize.paddingBottom;
924
925		this.position.x = x;
926		this.position.y = y;
927	};
928
929// set settled position, apply padding
930	proto.layoutPosition = function () {
931		var layoutSize = this.layout.size;
932		var style = {};
933		var isOriginLeft = this.layout._getOption('originLeft');
934		var isOriginTop = this.layout._getOption('originTop');
935
936		// x
937		var xPadding = isOriginLeft ? 'paddingLeft' : 'paddingRight';
938		var xProperty = isOriginLeft ? 'left' : 'right';
939		var xResetProperty = isOriginLeft ? 'right' : 'left';
940
941		var x = this.position.x + layoutSize[xPadding];
942		// set in percentage or pixels
943		style[xProperty] = this.getXValue(x);
944		// reset other property
945		style[xResetProperty] = '';
946
947		// y
948		var yPadding = isOriginTop ? 'paddingTop' : 'paddingBottom';
949		var yProperty = isOriginTop ? 'top' : 'bottom';
950		var yResetProperty = isOriginTop ? 'bottom' : 'top';
951
952		var y = this.position.y + layoutSize[yPadding];
953		// set in percentage or pixels
954		style[yProperty] = this.getYValue(y);
955		// reset other property
956		style[yResetProperty] = '';
957
958		this.css(style);
959		this.emitEvent('layout', [this]);
960	};
961
962	proto.getXValue = function (x) {
963		var isHorizontal = this.layout._getOption('horizontal');
964		return this.layout.options.percentPosition && !isHorizontal ?
965			((x / this.layout.size.width) * 100) + '%' : x + 'px';
966	};
967
968	proto.getYValue = function (y) {
969		var isHorizontal = this.layout._getOption('horizontal');
970		return this.layout.options.percentPosition && isHorizontal ?
971			((y / this.layout.size.height) * 100) + '%' : y + 'px';
972	};
973
974	proto._transitionTo = function (x, y) {
975		this.getPosition();
976		// get current x & y from top/left
977		var curX = this.position.x;
978		var curY = this.position.y;
979
980		var compareX = parseInt(x, 10);
981		var compareY = parseInt(y, 10);
982		var didNotMove = compareX === this.position.x && compareY === this.position.y;
983
984		// save end position
985		this.setPosition(x, y);
986
987		// if did not move and not transitioning, just go to layout
988		if (didNotMove && !this.isTransitioning) {
989			this.layoutPosition();
990			return;
991		}
992
993		var transX = x - curX;
994		var transY = y - curY;
995		var transitionStyle = {};
996		transitionStyle.transform = this.getTranslate(transX, transY);
997
998		this.transition({
999			to             : transitionStyle,
1000			onTransitionEnd: {
1001				transform: this.layoutPosition
1002			},
1003			isCleaning     : true
1004		});
1005	};
1006
1007	proto.getTranslate = function (x, y) {
1008		// flip cooridinates if origin on right or bottom
1009		var isOriginLeft = this.layout._getOption('originLeft');
1010		var isOriginTop = this.layout._getOption('originTop');
1011		x = isOriginLeft ? x : -x;
1012		y = isOriginTop ? y : -y;
1013		return 'translate3d(' + x + 'px, ' + y + 'px, 0)';
1014	};
1015
1016// non transition + transform support
1017	proto.goTo = function (x, y) {
1018		this.setPosition(x, y);
1019		this.layoutPosition();
1020	};
1021
1022	proto.moveTo = proto._transitionTo;
1023
1024	proto.setPosition = function (x, y) {
1025		this.position.x = parseInt(x, 10);
1026		this.position.y = parseInt(y, 10);
1027	};
1028
1029// ----- transition ----- //
1030
1031	/**
1032	 * @param {Object} style - CSS
1033	 * @param {Function} onTransitionEnd
1034	 */
1035
1036// non transition, just trigger callback
1037	proto._nonTransition = function (args) {
1038		this.css(args.to);
1039		if (args.isCleaning) {
1040			this._removeStyles(args.to);
1041		}
1042		for (var prop in args.onTransitionEnd) {
1043			args.onTransitionEnd[prop].call(this);
1044		}
1045	};
1046
1047	/**
1048	 * proper transition
1049	 * @param {Object} args - arguments
1050	 *   @param {Object} to - style to transition to
1051	 *   @param {Object} from - style to start transition from
1052	 *   @param {Boolean} isCleaning - removes transition styles after transition
1053	 *   @param {Function} onTransitionEnd - callback
1054	 */
1055	proto.transition = function (args) {
1056		// redirect to nonTransition if no transition duration
1057		if (!parseFloat(this.layout.options.transitionDuration)) {
1058			this._nonTransition(args);
1059			return;
1060		}
1061
1062		var _transition = this._transn;
1063		// keep track of onTransitionEnd callback by css property
1064		for (var prop in args.onTransitionEnd) {
1065			_transition.onEnd[prop] = args.onTransitionEnd[prop];
1066		}
1067		// keep track of properties that are transitioning
1068		for (prop in args.to) {
1069			_transition.ingProperties[prop] = true;
1070			// keep track of properties to clean up when transition is done
1071			if (args.isCleaning) {
1072				_transition.clean[prop] = true;
1073			}
1074		}
1075
1076		// set from styles
1077		if (args.from) {
1078			this.css(args.from);
1079			// force redraw. http://blog.alexmaccaw.com/css-transitions
1080			var h = this.element.offsetHeight;
1081			// hack for JSHint to hush about unused var
1082			h = null;
1083		}
1084		// enable transition
1085		this.enableTransition(args.to);
1086		// set styles that are transitioning
1087		this.css(args.to);
1088
1089		this.isTransitioning = true;
1090
1091	};
1092
1093// dash before all cap letters, including first for
1094// WebkitTransform => -webkit-transform
1095	function toDashedAll(str) {
1096		return str.replace(/([A-Z])/g, function ($1) {
1097			return '-' + $1.toLowerCase();
1098		});
1099	}
1100
1101	var transitionProps = 'opacity,' + toDashedAll(transformProperty);
1102
1103	proto.enableTransition = function (/* style */) {
1104		// HACK changing transitionProperty during a transition
1105		// will cause transition to jump
1106		if (this.isTransitioning) {
1107			return;
1108		}
1109
1110		// make `transition: foo, bar, baz` from style object
1111		// HACK un-comment this when enableTransition can work
1112		// while a transition is happening
1113		// var transitionValues = [];
1114		// for ( var prop in style ) {
1115		//   // dash-ify camelCased properties like WebkitTransition
1116		//   prop = vendorProperties[ prop ] || prop;
1117		//   transitionValues.push( toDashedAll( prop ) );
1118		// }
1119		// munge number to millisecond, to match stagger
1120		var duration = this.layout.options.transitionDuration;
1121		duration = typeof duration == 'number' ? duration + 'ms' : duration;
1122		// enable transition styles
1123		this.css({
1124			transitionProperty: transitionProps,
1125			transitionDuration: duration,
1126			transitionDelay   : this.staggerDelay || 0
1127		});
1128		// listen for transition end event
1129		this.element.addEventListener(transitionEndEvent, this, false);
1130	};
1131
1132// ----- events ----- //
1133
1134	proto.onwebkitTransitionEnd = function (event) {
1135		this.ontransitionend(event);
1136	};
1137
1138	proto.onotransitionend = function (event) {
1139		this.ontransitionend(event);
1140	};
1141
1142// properties that I munge to make my life easier
1143	var dashedVendorProperties = {
1144		'-webkit-transform': 'transform'
1145	};
1146
1147	proto.ontransitionend = function (event) {
1148		// disregard bubbled events from children
1149		if (event.target !== this.element) {
1150			return;
1151		}
1152		var _transition = this._transn;
1153		// get property name of transitioned property, convert to prefix-free
1154		var propertyName = dashedVendorProperties[event.propertyName] || event.propertyName;
1155
1156		// remove property that has completed transitioning
1157		delete _transition.ingProperties[propertyName];
1158		// check if any properties are still transitioning
1159		if (isEmptyObj(_transition.ingProperties)) {
1160			// all properties have completed transitioning
1161			this.disableTransition();
1162		}
1163		// clean style
1164		if (propertyName in _transition.clean) {
1165			// clean up style
1166			this.element.style[event.propertyName] = '';
1167			delete _transition.clean[propertyName];
1168		}
1169		// trigger onTransitionEnd callback
1170		if (propertyName in _transition.onEnd) {
1171			var onTransitionEnd = _transition.onEnd[propertyName];
1172			onTransitionEnd.call(this);
1173			delete _transition.onEnd[propertyName];
1174		}
1175
1176		this.emitEvent('transitionEnd', [this]);
1177	};
1178
1179	proto.disableTransition = function () {
1180		this.removeTransitionStyles();
1181		this.element.removeEventListener(transitionEndEvent, this, false);
1182		this.isTransitioning = false;
1183	};
1184
1185	/**
1186	 * removes style property from element
1187	 * @param {Object} style
1188	 **/
1189	proto._removeStyles = function (style) {
1190		// clean up transition styles
1191		var cleanStyle = {};
1192		for (var prop in style) {
1193			cleanStyle[prop] = '';
1194		}
1195		this.css(cleanStyle);
1196	};
1197
1198	var cleanTransitionStyle = {
1199		transitionProperty: '',
1200		transitionDuration: '',
1201		transitionDelay   : ''
1202	};
1203
1204	proto.removeTransitionStyles = function () {
1205		// remove transition
1206		this.css(cleanTransitionStyle);
1207	};
1208
1209// ----- stagger ----- //
1210
1211	proto.stagger = function (delay) {
1212		delay = isNaN(delay) ? 0 : delay;
1213		this.staggerDelay = delay + 'ms';
1214	};
1215
1216// ----- show/hide/remove ----- //
1217
1218// remove element from DOM
1219	proto.removeElem = function () {
1220		this.element.parentNode.removeChild(this.element);
1221		// remove display: none
1222		this.css({display: ''});
1223		this.emitEvent('remove', [this]);
1224	};
1225
1226	proto.remove = function () {
1227		// just remove element if no transition support or no transition
1228		if (!transitionProperty || !parseFloat(this.layout.options.transitionDuration)) {
1229			this.removeElem();
1230			return;
1231		}
1232
1233		// start transition
1234		this.once('transitionEnd', function () {
1235			this.removeElem();
1236		});
1237		this.hide();
1238	};
1239
1240	proto.reveal = function () {
1241		delete this.isHidden;
1242		// remove display: none
1243		this.css({display: ''});
1244
1245		var options = this.layout.options;
1246
1247		var onTransitionEnd = {};
1248		var transitionEndProperty = this.getHideRevealTransitionEndProperty('visibleStyle');
1249		onTransitionEnd[transitionEndProperty] = this.onRevealTransitionEnd;
1250
1251		this.transition({
1252			from           : options.hiddenStyle,
1253			to             : options.visibleStyle,
1254			isCleaning     : true,
1255			onTransitionEnd: onTransitionEnd
1256		});
1257	};
1258
1259	proto.onRevealTransitionEnd = function () {
1260		// check if still visible
1261		// during transition, item may have been hidden
1262		if (!this.isHidden) {
1263			this.emitEvent('reveal');
1264		}
1265	};
1266
1267	/**
1268	 * get style property use for hide/reveal transition end
1269	 * @param {String} styleProperty - hiddenStyle/visibleStyle
1270	 * @returns {String}
1271	 */
1272	proto.getHideRevealTransitionEndProperty = function (styleProperty) {
1273		var optionStyle = this.layout.options[styleProperty];
1274		// use opacity
1275		if (optionStyle.opacity) {
1276			return 'opacity';
1277		}
1278		// get first property
1279		for (var prop in optionStyle) {
1280			return prop;
1281		}
1282	};
1283
1284	proto.hide = function () {
1285		// set flag
1286		this.isHidden = true;
1287		// remove display: none
1288		this.css({display: ''});
1289
1290		var options = this.layout.options;
1291
1292		var onTransitionEnd = {};
1293		var transitionEndProperty = this.getHideRevealTransitionEndProperty('hiddenStyle');
1294		onTransitionEnd[transitionEndProperty] = this.onHideTransitionEnd;
1295
1296		this.transition({
1297			from           : options.visibleStyle,
1298			to             : options.hiddenStyle,
1299			// keep hidden stuff hidden
1300			isCleaning     : true,
1301			onTransitionEnd: onTransitionEnd
1302		});
1303	};
1304
1305	proto.onHideTransitionEnd = function () {
1306		// check if still hidden
1307		// during transition, item may have been un-hidden
1308		if (this.isHidden) {
1309			this.css({display: 'none'});
1310			this.emitEvent('hide');
1311		}
1312	};
1313
1314	proto.destroy = function () {
1315		this.css({
1316			position  : '',
1317			left      : '',
1318			right     : '',
1319			top       : '',
1320			bottom    : '',
1321			transition: '',
1322			transform : ''
1323		});
1324	};
1325
1326	return Item;
1327
1328}));
1329
1330/*!
1331 * Outlayer v2.1.0
1332 * the brains and guts of a layout library
1333 * MIT license
1334 */
1335
1336(function (window, factory) {
1337	'use strict';
1338	// universal module definition
1339	/* jshint strict: false */
1340	/* globals define, module, require */
1341	if (typeof define == 'function' && define.amd) {
1342		// AMD - RequireJS
1343		define('outlayer/outlayer', [
1344				'ev-emitter/ev-emitter',
1345				'get-size/get-size',
1346				'fizzy-ui-utils/utils',
1347				'./item'
1348			],
1349			function (EvEmitter, getSize, utils, Item) {
1350				return factory(window, EvEmitter, getSize, utils, Item);
1351			}
1352		);
1353	} else if (typeof module == 'object' && module.exports) {
1354		// CommonJS - Browserify, Webpack
1355		module.exports = factory(
1356			window,
1357			require('ev-emitter'),
1358			require('get-size'),
1359			require('fizzy-ui-utils'),
1360			require('./item')
1361		);
1362	} else {
1363		// browser global
1364		window.Outlayer = factory(
1365			window,
1366			window.EvEmitter,
1367			window.getSize,
1368			window.fizzyUIUtils,
1369			window.Outlayer.Item
1370		);
1371	}
1372
1373}(window, function factory(window, EvEmitter, getSize, utils, Item) {
1374	'use strict';
1375
1376// ----- vars ----- //
1377
1378	var console = window.console;
1379	var jQuery = window.jQuery;
1380	var noop = function () {
1381	};
1382
1383// -------------------------- Outlayer -------------------------- //
1384
1385// globally unique identifiers
1386	var GUID = 0;
1387// internal store of all Outlayer intances
1388	var instances = {};
1389
1390
1391	/**
1392	 * @param {Element, String} element
1393	 * @param {Object} options
1394	 * @constructor
1395	 */
1396	function Outlayer(element, options) {
1397		var queryElement = utils.getQueryElement(element);
1398		if (!queryElement) {
1399			if (console) {
1400				console.error('Bad element for ' + this.constructor.namespace +
1401					': ' + (queryElement || element));
1402			}
1403			return;
1404		}
1405		this.element = queryElement;
1406		// add jQuery
1407		if (jQuery) {
1408			this.$element = jQuery(this.element);
1409		}
1410
1411		// options
1412		this.options = utils.extend({}, this.constructor.defaults);
1413		this.option(options);
1414
1415		// add id for Outlayer.getFromElement
1416		var id = ++GUID;
1417		this.element.outlayerGUID = id; // expando
1418		instances[id] = this; // associate via id
1419
1420		// kick it off
1421		this._create();
1422
1423		var isInitLayout = this._getOption('initLayout');
1424		if (isInitLayout) {
1425			this.layout();
1426		}
1427	}
1428
1429// settings are for internal use only
1430	Outlayer.namespace = 'outlayer';
1431	Outlayer.Item = Item;
1432
1433// default options
1434	Outlayer.defaults = {
1435		containerStyle    : {
1436			position: 'relative'
1437		},
1438		initLayout        : true,
1439		originLeft        : true,
1440		originTop         : true,
1441		resize            : true,
1442		resizeContainer   : true,
1443		// item options
1444		transitionDuration: '0.4s',
1445		hiddenStyle       : {
1446			opacity  : 0,
1447			transform: 'scale(0.001)'
1448		},
1449		visibleStyle      : {
1450			opacity  : 1,
1451			transform: 'scale(1)'
1452		}
1453	};
1454
1455	var proto = Outlayer.prototype;
1456// inherit EvEmitter
1457	utils.extend(proto, EvEmitter.prototype);
1458
1459	/**
1460	 * set options
1461	 * @param {Object} opts
1462	 */
1463	proto.option = function (opts) {
1464		utils.extend(this.options, opts);
1465	};
1466
1467	/**
1468	 * get backwards compatible option value, check old name
1469	 */
1470	proto._getOption = function (option) {
1471		var oldOption = this.constructor.compatOptions[option];
1472		return oldOption && this.options[oldOption] !== undefined ?
1473			this.options[oldOption] : this.options[option];
1474	};
1475
1476	Outlayer.compatOptions = {
1477		// currentName: oldName
1478		initLayout     : 'isInitLayout',
1479		horizontal     : 'isHorizontal',
1480		layoutInstant  : 'isLayoutInstant',
1481		originLeft     : 'isOriginLeft',
1482		originTop      : 'isOriginTop',
1483		resize         : 'isResizeBound',
1484		resizeContainer: 'isResizingContainer'
1485	};
1486
1487	proto._create = function () {
1488		// get items from children
1489		this.reloadItems();
1490		// elements that affect layout, but are not laid out
1491		this.stamps = [];
1492		this.stamp(this.options.stamp);
1493		// set container style
1494		utils.extend(this.element.style, this.options.containerStyle);
1495
1496		// bind resize method
1497		var canBindResize = this._getOption('resize');
1498		if (canBindResize) {
1499			this.bindResize();
1500		}
1501	};
1502
1503// goes through all children again and gets bricks in proper order
1504	proto.reloadItems = function () {
1505		// collection of item elements
1506		this.items = this._itemize(this.element.children);
1507	};
1508
1509
1510	/**
1511	 * turn elements into Outlayer.Items to be used in layout
1512	 * @param {Array or NodeList or HTMLElement} elems
1513	 * @returns {Array} items - collection of new Outlayer Items
1514	 */
1515	proto._itemize = function (elems) {
1516
1517		var itemElems = this._filterFindItemElements(elems);
1518		var Item = this.constructor.Item;
1519
1520		// create new Outlayer Items for collection
1521		var items = [];
1522		for (var i = 0; i < itemElems.length; i++) {
1523			var elem = itemElems[i];
1524			var item = new Item(elem, this);
1525			items.push(item);
1526		}
1527
1528		return items;
1529	};
1530
1531	/**
1532	 * get item elements to be used in layout
1533	 * @param {Array or NodeList or HTMLElement} elems
1534	 * @returns {Array} items - item elements
1535	 */
1536	proto._filterFindItemElements = function (elems) {
1537		return utils.filterFindElements(elems, this.options.itemSelector);
1538	};
1539
1540	/**
1541	 * getter method for getting item elements
1542	 * @returns {Array} elems - collection of item elements
1543	 */
1544	proto.getItemElements = function () {
1545		return this.items.map(function (item) {
1546			return item.element;
1547		});
1548	};
1549
1550// ----- init & layout ----- //
1551
1552	/**
1553	 * lays out all items
1554	 */
1555	proto.layout = function () {
1556		this._resetLayout();
1557		this._manageStamps();
1558
1559		// don't animate first layout
1560		var layoutInstant = this._getOption('layoutInstant');
1561		var isInstant = layoutInstant !== undefined ?
1562			layoutInstant : !this._isLayoutInited;
1563		this.layoutItems(this.items, isInstant);
1564
1565		// flag for initalized
1566		this._isLayoutInited = true;
1567	};
1568
1569// _init is alias for layout
1570	proto._init = proto.layout;
1571
1572	/**
1573	 * logic before any new layout
1574	 */
1575	proto._resetLayout = function () {
vendor: 13,397 bytes, lines 1576-2146
1576		this.getSize();
1577	};
1578
1579
1580	proto.getSize = function () {
1581		this.size = getSize(this.element);
1582	};
1583
1584	/**
1585	 * get measurement from option, for columnWidth, rowHeight, gutter
1586	 * if option is String -> get element from selector string, & get size of element
1587	 * if option is Element -> get size of element
1588	 * else use option as a number
1589	 *
1590	 * @param {String} measurement
1591	 * @param {String} size - width or height
1592	 * @private
1593	 */
1594	proto._getMeasurement = function (measurement, size) {
1595		var option = this.options[measurement];
1596		var elem;
1597		if (!option) {
1598			// default to 0
1599			this[measurement] = 0;
1600		} else {
1601			// use option as an element
1602			if (typeof option == 'string') {
1603				elem = this.element.querySelector(option);
1604			} else if (option instanceof HTMLElement) {
1605				elem = option;
1606			}
1607			// use size of element, if element
1608			this[measurement] = elem ? getSize(elem)[size] : option;
1609		}
1610	};
1611
1612	/**
1613	 * layout a collection of item elements
1614	 * @api public
1615	 */
1616	proto.layoutItems = function (items, isInstant) {
1617		items = this._getItemsForLayout(items);
1618
1619		this._layoutItems(items, isInstant);
1620
1621		this._postLayout();
1622	};
1623
1624	/**
1625	 * get the items to be laid out
1626	 * you may want to skip over some items
1627	 * @param {Array} items
1628	 * @returns {Array} items
1629	 */
1630	proto._getItemsForLayout = function (items) {
1631		return items.filter(function (item) {
1632			return !item.isIgnored;
1633		});
1634	};
1635
1636	/**
1637	 * layout items
1638	 * @param {Array} items
1639	 * @param {Boolean} isInstant
1640	 */
1641	proto._layoutItems = function (items, isInstant) {
1642		this._emitCompleteOnItems('layout', items);
1643
1644		if (!items || !items.length) {
1645			// no items, emit event with empty array
1646			return;
1647		}
1648
1649		var queue = [];
1650
1651		items.forEach(function (item) {
1652			// get x/y object from method
1653			var position = this._getItemLayoutPosition(item);
1654			// enqueue
1655			position.item = item;
1656			position.isInstant = isInstant || item.isLayoutInstant;
1657			queue.push(position);
1658		}, this);
1659
1660		this._processLayoutQueue(queue);
1661	};
1662
1663	/**
1664	 * get item layout position
1665	 * @param {Outlayer.Item} item
1666	 * @returns {Object} x and y position
1667	 */
1668	proto._getItemLayoutPosition = function (/* item */) {
1669		return {
1670			x: 0,
1671			y: 0
1672		};
1673	};
1674
1675	/**
1676	 * iterate over array and position each item
1677	 * Reason being - separating this logic prevents 'layout invalidation'
1678	 * thx @paul_irish
1679	 * @param {Array} queue
1680	 */
1681	proto._processLayoutQueue = function (queue) {
1682		this.updateStagger();
1683		queue.forEach(function (obj, i) {
1684			this._positionItem(obj.item, obj.x, obj.y, obj.isInstant, i);
1685		}, this);
1686	};
1687
1688// set stagger from option in milliseconds number
1689	proto.updateStagger = function () {
1690		var stagger = this.options.stagger;
1691		if (stagger === null || stagger === undefined) {
1692			this.stagger = 0;
1693			return;
1694		}
1695		this.stagger = getMilliseconds(stagger);
1696		return this.stagger;
1697	};
1698
1699	/**
1700	 * Sets position of item in DOM
1701	 * @param {Outlayer.Item} item
1702	 * @param {Number} x - horizontal position
1703	 * @param {Number} y - vertical position
1704	 * @param {Boolean} isInstant - disables transitions
1705	 */
1706	proto._positionItem = function (item, x, y, isInstant, i) {
1707		if (isInstant) {
1708			// if not transition, just set CSS
1709			item.goTo(x, y);
1710		} else {
1711			item.stagger(i * this.stagger);
1712			item.moveTo(x, y);
1713		}
1714	};
1715
1716	/**
1717	 * Any logic you want to do after each layout,
1718	 * i.e. size the container
1719	 */
1720	proto._postLayout = function () {
1721		this.resizeContainer();
1722	};
1723
1724	proto.resizeContainer = function () {
1725		var isResizingContainer = this._getOption('resizeContainer');
1726		if (!isResizingContainer) {
1727			return;
1728		}
1729		var size = this._getContainerSize();
1730		if (size) {
1731			this._setContainerMeasure(size.width, true);
1732			this._setContainerMeasure(size.height, false);
1733		}
1734	};
1735
1736	/**
1737	 * Sets width or height of container if returned
1738	 * @returns {Object} size
1739	 *   @param {Number} width
1740	 *   @param {Number} height
1741	 */
1742	proto._getContainerSize = noop;
1743
1744	/**
1745	 * @param {Number} measure - size of width or height
1746	 * @param {Boolean} isWidth
1747	 */
1748	proto._setContainerMeasure = function (measure, isWidth) {
1749		if (measure === undefined) {
1750			return;
1751		}
1752
1753		var elemSize = this.size;
1754		// add padding and border width if border box
1755		if (elemSize.isBorderBox) {
1756			measure += isWidth ? elemSize.paddingLeft + elemSize.paddingRight +
1757				elemSize.borderLeftWidth + elemSize.borderRightWidth :
1758				elemSize.paddingBottom + elemSize.paddingTop +
1759				elemSize.borderTopWidth + elemSize.borderBottomWidth;
1760		}
1761
1762		measure = Math.max(measure, 0);
1763		this.element.style[isWidth ? 'width' : 'height'] = measure + 'px';
1764	};
1765
1766	/**
1767	 * emit eventComplete on a collection of items events
1768	 * @param {String} eventName
1769	 * @param {Array} items - Outlayer.Items
1770	 */
1771	proto._emitCompleteOnItems = function (eventName, items) {
1772		var _this = this;
1773
1774		function onComplete() {
1775			_this.dispatchEvent(eventName + 'Complete', null, [items]);
1776		}
1777
1778		var count = items.length;
1779		if (!items || !count) {
1780			onComplete();
1781			return;
1782		}
1783
1784		var doneCount = 0;
1785
1786		function tick() {
1787			doneCount++;
1788			if (doneCount == count) {
1789				onComplete();
1790			}
1791		}
1792
1793		// bind callback
1794		items.forEach(function (item) {
1795			item.once(eventName, tick);
1796		});
1797	};
1798
1799	/**
1800	 * emits events via EvEmitter and jQuery events
1801	 * @param {String} type - name of event
1802	 * @param {Event} event - original event
1803	 * @param {Array} args - extra arguments
1804	 */
1805	proto.dispatchEvent = function (type, event, args) {
1806		// add original event to arguments
1807		var emitArgs = event ? [event].concat(args) : args;
1808		this.emitEvent(type, emitArgs);
1809
1810		if (jQuery) {
1811			// set this.$element
1812			this.$element = this.$element || jQuery(this.element);
1813			if (event) {
1814				// create jQuery event
1815				var $event = jQuery.Event(event);
1816				$event.type = type;
1817				this.$element.trigger($event, args);
1818			} else {
1819				// just trigger with type if no event available
1820				this.$element.trigger(type, args);
1821			}
1822		}
1823	};
1824
1825// -------------------------- ignore & stamps -------------------------- //
1826
1827
1828	/**
1829	 * keep item in collection, but do not lay it out
1830	 * ignored items do not get skipped in layout
1831	 * @param {Element} elem
1832	 */
1833	proto.ignore = function (elem) {
1834		var item = this.getItem(elem);
1835		if (item) {
1836			item.isIgnored = true;
1837		}
1838	};
1839
1840	/**
1841	 * return item to layout collection
1842	 * @param {Element} elem
1843	 */
1844	proto.unignore = function (elem) {
1845		var item = this.getItem(elem);
1846		if (item) {
1847			delete item.isIgnored;
1848		}
1849	};
1850
1851	/**
1852	 * adds elements to stamps
1853	 * @param {NodeList, Array, Element, or String} elems
1854	 */
1855	proto.stamp = function (elems) {
1856		elems = this._find(elems);
1857		if (!elems) {
1858			return;
1859		}
1860
1861		this.stamps = this.stamps.concat(elems);
1862		// ignore
1863		elems.forEach(this.ignore, this);
1864	};
1865
1866	/**
1867	 * removes elements to stamps
1868	 * @param {NodeList, Array, or Element} elems
1869	 */
1870	proto.unstamp = function (elems) {
1871		elems = this._find(elems);
1872		if (!elems) {
1873			return;
1874		}
1875
1876		elems.forEach(function (elem) {
1877			// filter out removed stamp elements
1878			utils.removeFrom(this.stamps, elem);
1879			this.unignore(elem);
1880		}, this);
1881	};
1882
1883	/**
1884	 * finds child elements
1885	 * @param {NodeList, Array, Element, or String} elems
1886	 * @returns {Array} elems
1887	 */
1888	proto._find = function (elems) {
1889		if (!elems) {
1890			return;
1891		}
1892		// if string, use argument as selector string
1893		if (typeof elems == 'string') {
1894			elems = this.element.querySelectorAll(elems);
1895		}
1896		elems = utils.makeArray(elems);
1897		return elems;
1898	};
1899
1900	proto._manageStamps = function () {
1901		if (!this.stamps || !this.stamps.length) {
1902			return;
1903		}
1904
1905		this._getBoundingRect();
1906
1907		this.stamps.forEach(this._manageStamp, this);
1908	};
1909
1910// update boundingLeft / Top
1911	proto._getBoundingRect = function () {
1912		// get bounding rect for container element
1913		var boundingRect = this.element.getBoundingClientRect();
1914		var size = this.size;
1915		this._boundingRect = {
1916			left  : boundingRect.left + size.paddingLeft + size.borderLeftWidth,
1917			top   : boundingRect.top + size.paddingTop + size.borderTopWidth,
1918			right : boundingRect.right - (size.paddingRight + size.borderRightWidth),
1919			bottom: boundingRect.bottom - (size.paddingBottom + size.borderBottomWidth)
1920		};
1921	};
1922
1923	/**
1924	 * @param {Element} stamp
1925	 **/
1926	proto._manageStamp = noop;
1927
1928	/**
1929	 * get x/y position of element relative to container element
1930	 * @param {Element} elem
1931	 * @returns {Object} offset - has left, top, right, bottom
1932	 */
1933	proto._getElementOffset = function (elem) {
1934		var boundingRect = elem.getBoundingClientRect();
1935		var thisRect = this._boundingRect;
1936		var size = getSize(elem);
1937		var offset = {
1938			left  : boundingRect.left - thisRect.left - size.marginLeft,
1939			top   : boundingRect.top - thisRect.top - size.marginTop,
1940			right : thisRect.right - boundingRect.right - size.marginRight,
1941			bottom: thisRect.bottom - boundingRect.bottom - size.marginBottom
1942		};
1943		return offset;
1944	};
1945
1946// -------------------------- resize -------------------------- //
1947
1948// enable event handlers for listeners
1949// i.e. resize -> onresize
1950	proto.handleEvent = utils.handleEvent;
1951
1952	/**
1953	 * Bind layout to window resizing
1954	 */
1955	proto.bindResize = function () {
1956		window.addEventListener('resize', this);
1957		this.isResizeBound = true;
1958	};
1959
1960	/**
1961	 * Unbind layout to window resizing
1962	 */
1963	proto.unbindResize = function () {
1964		window.removeEventListener('resize', this);
1965		this.isResizeBound = false;
1966	};
1967
1968	proto.onresize = function () {
1969		this.resize();
1970	};
1971
1972	utils.debounceMethod(Outlayer, 'onresize', 100);
1973
1974	proto.resize = function () {
1975		// don't trigger if size did not change
1976		// or if resize was unbound. See #9
1977		if (!this.isResizeBound || !this.needsResizeLayout()) {
1978			return;
1979		}
1980
1981		this.layout();
1982	};
1983
1984	/**
1985	 * check if layout is needed post layout
1986	 * @returns Boolean
1987	 */
1988	proto.needsResizeLayout = function () {
1989		var size = getSize(this.element);
1990		// check that this.size and size are there
1991		// IE8 triggers resize on body size change, so they might not be
1992		var hasSizes = this.size && size;
1993		return hasSizes && size.innerWidth !== this.size.innerWidth;
1994	};
1995
1996// -------------------------- methods -------------------------- //
1997
1998	/**
1999	 * add items to Outlayer instance
2000	 * @param {Array or NodeList or Element} elems
2001	 * @returns {Array} items - Outlayer.Items
2002	 **/
2003	proto.addItems = function (elems) {
2004		var items = this._itemize(elems);
2005		// add items to collection
2006		if (items.length) {
2007			this.items = this.items.concat(items);
2008		}
2009		return items;
2010	};
2011
2012	/**
2013	 * Layout newly-appended item elements
2014	 * @param {Array or NodeList or Element} elems
2015	 */
2016	proto.appended = function (elems) {
2017		var items = this.addItems(elems);
2018		if (!items.length) {
2019			return;
2020		}
2021		// layout and reveal just the new items
2022		this.layoutItems(items, true);
2023		this.reveal(items);
2024	};
2025
2026	/**
2027	 * Layout prepended elements
2028	 * @param {Array or NodeList or Element} elems
2029	 */
2030	proto.prepended = function (elems) {
2031		var items = this._itemize(elems);
2032		if (!items.length) {
2033			return;
2034		}
2035		// add items to beginning of collection
2036		var previousItems = this.items.slice(0);
2037		this.items = items.concat(previousItems);
2038		// start new layout
2039		this._resetLayout();
2040		this._manageStamps();
2041		// layout new stuff without transition
2042		this.layoutItems(items, true);
2043		this.reveal(items);
2044		// layout previous items
2045		this.layoutItems(previousItems);
2046	};
2047
2048	/**
2049	 * reveal a collection of items
2050	 * @param {Array of Outlayer.Items} items
2051	 */
2052	proto.reveal = function (items) {
2053		this._emitCompleteOnItems('reveal', items);
2054		if (!items || !items.length) {
2055			return;
2056		}
2057		var stagger = this.updateStagger();
2058		items.forEach(function (item, i) {
2059			item.stagger(i * stagger);
2060			item.reveal();
2061		});
2062	};
2063
2064	/**
2065	 * hide a collection of items
2066	 * @param {Array of Outlayer.Items} items
2067	 */
2068	proto.hide = function (items) {
2069		this._emitCompleteOnItems('hide', items);
2070		if (!items || !items.length) {
2071			return;
2072		}
2073		var stagger = this.updateStagger();
2074		items.forEach(function (item, i) {
2075			item.stagger(i * stagger);
2076			item.hide();
2077		});
2078	};
2079
2080	/**
2081	 * reveal item elements
2082	 * @param {Array}, {Element}, {NodeList} items
2083	 */
2084	proto.revealItemElements = function (elems) {
2085		var items = this.getItems(elems);
2086		this.reveal(items);
2087	};
2088
2089	/**
2090	 * hide item elements
2091	 * @param {Array}, {Element}, {NodeList} items
2092	 */
2093	proto.hideItemElements = function (elems) {
2094		var items = this.getItems(elems);
2095		this.hide(items);
2096	};
2097
2098	/**
2099	 * get Outlayer.Item, given an Element
2100	 * @param {Element} elem
2101	 * @param {Function} callback
2102	 * @returns {Outlayer.Item} item
2103	 */
2104	proto.getItem = function (elem) {
2105		// loop through items to get the one that matches
2106		for (var i = 0; i < this.items.length; i++) {
2107			var item = this.items[i];
2108			if (item.element == elem) {
2109				// return item
2110				return item;
2111			}
2112		}
2113	};
2114
2115	/**
2116	 * get collection of Outlayer.Items, given Elements
2117	 * @param {Array} elems
2118	 * @returns {Array} items - Outlayer.Items
2119	 */
2120	proto.getItems = function (elems) {
2121		elems = utils.makeArray(elems);
2122		var items = [];
2123		elems.forEach(function (elem) {
2124			var item = this.getItem(elem);
2125			if (item) {
2126				items.push(item);
2127			}
2128		}, this);
2129
2130		return items;
2131	};
2132
2133	/**
2134	 * remove element(s) from instance and DOM
2135	 * @param {Array or NodeList or Element} elems
2136	 */
2137	proto.remove = function (elems) {
2138		var removeItems = this.getItems(elems);
2139
2140		this._emitCompleteOnItems('remove', removeItems);
2141
2142		// bail if no items to remove
2143		if (!removeItems || !removeItems.length) {
2144			return;
2145		}
2146
vendor: 24,063 bytes, lines 2147-3126
2147		removeItems.forEach(function (item) {
2148			item.remove();
2149			// remove item from collection
2150			utils.removeFrom(this.items, item);
2151		}, this);
2152	};
2153
2154// ----- destroy ----- //
2155
2156// remove and disable Outlayer instance
2157	proto.destroy = function () {
2158		// clean up dynamic styles
2159		var style = this.element.style;
2160		style.height = '';
2161		style.position = '';
2162		style.width = '';
2163		// destroy items
2164		this.items.forEach(function (item) {
2165			item.destroy();
2166		});
2167
2168		this.unbindResize();
2169
2170		var id = this.element.outlayerGUID;
2171		delete instances[id]; // remove reference to instance by id
2172		delete this.element.outlayerGUID;
2173		// remove data for jQuery
2174		if (jQuery) {
2175			jQuery.removeData(this.element, this.constructor.namespace);
2176		}
2177
2178	};
2179
2180// -------------------------- data -------------------------- //
2181
2182	/**
2183	 * get Outlayer instance from element
2184	 * @param {Element} elem
2185	 * @returns {Outlayer}
2186	 */
2187	Outlayer.data = function (elem) {
2188		elem = utils.getQueryElement(elem);
2189		var id = elem && elem.outlayerGUID;
2190		return id && instances[id];
2191	};
2192
2193
2194// -------------------------- create Outlayer class -------------------------- //
2195
2196	/**
2197	 * create a layout class
2198	 * @param {String} namespace
2199	 */
2200	Outlayer.create = function (namespace, options) {
2201		// sub-class Outlayer
2202		var Layout = subclass(Outlayer);
2203		// apply new options and compatOptions
2204		Layout.defaults = utils.extend({}, Outlayer.defaults);
2205		utils.extend(Layout.defaults, options);
2206		Layout.compatOptions = utils.extend({}, Outlayer.compatOptions);
2207
2208		Layout.namespace = namespace;
2209
2210		Layout.data = Outlayer.data;
2211
2212		// sub-class Item
2213		Layout.Item = subclass(Item);
2214
2215		// -------------------------- declarative -------------------------- //
2216
2217		utils.htmlInit(Layout, namespace);
2218
2219		// -------------------------- jQuery bridge -------------------------- //
2220
2221		// make into jQuery plugin
2222		if (jQuery && jQuery.bridget) {
2223			jQuery.bridget(namespace, Layout);
2224		}
2225
2226		return Layout;
2227	};
2228
2229	function subclass(Parent) {
2230		function SubClass() {
2231			Parent.apply(this, arguments);
2232		}
2233
2234		SubClass.prototype = Object.create(Parent.prototype);
2235		SubClass.prototype.constructor = SubClass;
2236
2237		return SubClass;
2238	}
2239
2240// ----- helpers ----- //
2241
2242// how many milliseconds are in each unit
2243	var msUnits = {
2244		ms: 1,
2245		s : 1000
2246	};
2247
2248// munge time-like parameter into millisecond number
2249// '0.4s' -> 40
2250	function getMilliseconds(time) {
2251		if (typeof time == 'number') {
2252			return time;
2253		}
2254		var matches = time.match(/(^\d*\.?\d*)(\w*)/);
2255		var num = matches && matches[1];
2256		var unit = matches && matches[2];
2257		if (!num.length) {
2258			return 0;
2259		}
2260		num = parseFloat(num);
2261		var mult = msUnits[unit] || 1;
2262		return num * mult;
2263	}
2264
2265// ----- fin ----- //
2266
2267// back in global
2268	Outlayer.Item = Item;
2269
2270	return Outlayer;
2271
2272}));
2273
2274/**
2275 * Isotope Item
2276 **/
2277
2278(function (window, factory) {
2279	// universal module definition
2280	/* jshint strict: false */
2281	/*globals define, module, require */
2282	if (typeof define == 'function' && define.amd) {
2283		// AMD
2284		define('isotope-layout/js/item', [
2285				'outlayer/outlayer'
2286			],
2287			factory);
2288	} else if (typeof module == 'object' && module.exports) {
2289		// CommonJS
2290		module.exports = factory(
2291			require('outlayer')
2292		);
2293	} else {
2294		// browser global
2295		window.Isotope = window.Isotope || {};
2296		window.Isotope.Item = factory(
2297			window.Outlayer
2298		);
2299	}
2300
2301}(window, function factory(Outlayer) {
2302	'use strict';
2303
2304// -------------------------- Item -------------------------- //
2305
2306// sub-class Outlayer Item
2307	function Item() {
2308		Outlayer.Item.apply(this, arguments);
2309	}
2310
2311	var proto = Item.prototype = Object.create(Outlayer.Item.prototype);
2312
2313	var _create = proto._create;
2314	proto._create = function () {
2315		// assign id, used for original-order sorting
2316		this.id = this.layout.itemGUID++;
2317		_create.call(this);
2318		this.sortData = {};
2319	};
2320
2321	proto.updateSortData = function () {
2322		if (this.isIgnored) {
2323			return;
2324		}
2325		// default sorters
2326		this.sortData.id = this.id;
2327		// for backward compatibility
2328		this.sortData['original-order'] = this.id;
2329		this.sortData.random = Math.random();
2330		// go thru getSortData obj and apply the sorters
2331		var getSortData = this.layout.options.getSortData;
2332		var sorters = this.layout._sorters;
2333		for (var key in getSortData) {
2334			var sorter = sorters[key];
2335			this.sortData[key] = sorter(this.element, this);
2336		}
2337	};
2338
2339	var _destroy = proto.destroy;
2340	proto.destroy = function () {
2341		// call super
2342		_destroy.apply(this, arguments);
2343		// reset display, #741
2344		this.css({
2345			display: ''
2346		});
2347	};
2348
2349	return Item;
2350
2351}));
2352
2353/**
2354 * Isotope LayoutMode
2355 */
2356
2357(function (window, factory) {
2358	// universal module definition
2359	/* jshint strict: false */
2360	/*globals define, module, require */
2361	if (typeof define == 'function' && define.amd) {
2362		// AMD
2363		define('isotope-layout/js/layout-mode', [
2364				'get-size/get-size',
2365				'outlayer/outlayer'
2366			],
2367			factory);
2368	} else if (typeof module == 'object' && module.exports) {
2369		// CommonJS
2370		module.exports = factory(
2371			require('get-size'),
2372			require('outlayer')
2373		);
2374	} else {
2375		// browser global
2376		window.Isotope = window.Isotope || {};
2377		window.Isotope.LayoutMode = factory(
2378			window.getSize,
2379			window.Outlayer
2380		);
2381	}
2382
2383}(window, function factory(getSize, Outlayer) {
2384	'use strict';
2385
2386	// layout mode class
2387	function LayoutMode(isotope) {
2388		this.isotope = isotope;
2389		// link properties
2390		if (isotope) {
2391			this.options = isotope.options[this.namespace];
2392			this.element = isotope.element;
2393			this.items = isotope.filteredItems;
2394			this.size = isotope.size;
2395		}
2396	}
2397
2398	var proto = LayoutMode.prototype;
2399
2400	/**
2401	 * some methods should just defer to default Outlayer method
2402	 * and reference the Isotope instance as `this`
2403	 **/
2404	var facadeMethods = [
2405		'_resetLayout',
2406		'_getItemLayoutPosition',
2407		'_manageStamp',
2408		'_getContainerSize',
2409		'_getElementOffset',
2410		'needsResizeLayout',
2411		'_getOption'
2412	];
2413
2414	facadeMethods.forEach(function (methodName) {
2415		proto[methodName] = function () {
2416			return Outlayer.prototype[methodName].apply(this.isotope, arguments);
2417		};
2418	});
2419
2420	// -----  ----- //
2421
2422	// for horizontal layout modes, check vertical size
2423	proto.needsVerticalResizeLayout = function () {
2424		// don't trigger if size did not change
2425		var size = getSize(this.isotope.element);
2426		// check that this.size and size are there
2427		// IE8 triggers resize on body size change, so they might not be
2428		var hasSizes = this.isotope.size && size;
2429		return hasSizes && size.innerHeight != this.isotope.size.innerHeight;
2430	};
2431
2432	// ----- measurements ----- //
2433
2434	proto._getMeasurement = function () {
2435		this.isotope._getMeasurement.apply(this, arguments);
2436	};
2437
2438	proto.getColumnWidth = function () {
2439		this.getSegmentSize('column', 'Width');
2440	};
2441
2442	proto.getRowHeight = function () {
2443		this.getSegmentSize('row', 'Height');
2444	};
2445
2446	/**
2447	 * get columnWidth or rowHeight
2448	 * segment: 'column' or 'row'
2449	 * size 'Width' or 'Height'
2450	 **/
2451	proto.getSegmentSize = function (segment, size) {
2452		var segmentName = segment + size;
2453		var outerSize = 'outer' + size;
2454		// columnWidth / outerWidth // rowHeight / outerHeight
2455		this._getMeasurement(segmentName, outerSize);
2456		// got rowHeight or columnWidth, we can chill
2457		if (this[segmentName]) {
2458			return;
2459		}
2460		// fall back to item of first element
2461		var firstItemSize = this.getFirstItemSize();
2462		this[segmentName] = firstItemSize && firstItemSize[outerSize] ||
2463			// or size of container
2464			this.isotope.size['inner' + size];
2465	};
2466
2467	proto.getFirstItemSize = function () {
2468		var firstItem = this.isotope.filteredItems[0];
2469		return firstItem && firstItem.element && getSize(firstItem.element);
2470	};
2471
2472	// ----- methods that should reference isotope ----- //
2473
2474	proto.layout = function () {
2475		this.isotope.layout.apply(this.isotope, arguments);
2476	};
2477
2478	proto.getSize = function () {
2479		this.isotope.getSize();
2480		this.size = this.isotope.size;
2481	};
2482
2483	// -------------------------- create -------------------------- //
2484
2485	LayoutMode.modes = {};
2486
2487	LayoutMode.create = function (namespace, options) {
2488
2489		function Mode() {
2490			LayoutMode.apply(this, arguments);
2491		}
2492
2493		Mode.prototype = Object.create(proto);
2494		Mode.prototype.constructor = Mode;
2495
2496		// default options
2497		if (options) {
2498			Mode.options = options;
2499		}
2500
2501		Mode.prototype.namespace = namespace;
2502		// register in Isotope
2503		LayoutMode.modes[namespace] = Mode;
2504
2505		return Mode;
2506	};
2507
2508	return LayoutMode;
2509
2510}));
2511
2512/*!
2513 * Masonry v4.2.1
2514 * Cascading grid layout library
2515 * https://masonry.desandro.com
2516 * MIT License
2517 * by David DeSandro
2518 */
2519
2520(function (window, factory) {
2521	// universal module definition
2522	/* jshint strict: false */
2523	/*globals define, module, require */
2524	if (typeof define == 'function' && define.amd) {
2525		// AMD
2526		define('masonry-layout/masonry', [
2527				'outlayer/outlayer',
2528				'get-size/get-size'
2529			],
2530			factory);
2531	} else if (typeof module == 'object' && module.exports) {
2532		// CommonJS
2533		module.exports = factory(
2534			require('outlayer'),
2535			require('get-size')
2536		);
2537	} else {
2538		// browser global
2539		window.Masonry = factory(
2540			window.Outlayer,
2541			window.getSize
2542		);
2543	}
2544
2545}(window, function factory(Outlayer, getSize) {
2546
2547
2548
2549// -------------------------- masonryDefinition -------------------------- //
2550
2551	// create an Outlayer layout class
2552	var Masonry = Outlayer.create('masonry');
2553	// isFitWidth -> fitWidth
2554	Masonry.compatOptions.fitWidth = 'isFitWidth';
2555
2556	var proto = Masonry.prototype;
2557
2558	proto._resetLayout = function () {
2559		this.getSize();
2560		this._getMeasurement('columnWidth', 'outerWidth');
2561		this._getMeasurement('gutter', 'outerWidth');
2562		this.measureColumns();
2563
2564		// reset column Y
2565		this.colYs = [];
2566		for (var i = 0; i < this.cols; i++) {
2567			this.colYs.push(0);
2568		}
2569
2570		this.maxY = 0;
2571		this.horizontalColIndex = 0;
2572	};
2573
2574	proto.measureColumns = function () {
2575		this.getContainerWidth();
2576		// if columnWidth is 0, default to outerWidth of first item
2577		if (!this.columnWidth) {
2578			var firstItem = this.items[0];
2579			var firstItemElem = firstItem && firstItem.element;
2580			// columnWidth fall back to item of first element
2581			this.columnWidth = firstItemElem && getSize(firstItemElem).outerWidth ||
2582				// if first elem has no width, default to size of container
2583				this.containerWidth;
2584		}
2585
2586		var columnWidth = this.columnWidth += this.gutter;
2587
2588		// calculate columns
2589		var containerWidth = this.containerWidth + this.gutter;
2590		var cols = containerWidth / columnWidth;
2591		// fix rounding errors, typically with gutters
2592		var excess = columnWidth - containerWidth % columnWidth;
2593		// if overshoot is less than a pixel, round up, otherwise floor it
2594		var mathMethod = excess && excess < 1 ? 'round' : 'floor';
2595		cols = Math[mathMethod](cols);
2596		this.cols = Math.max(cols, 1);
2597	};
2598
2599	proto.getContainerWidth = function () {
2600		// container is parent if fit width
2601		var isFitWidth = this._getOption('fitWidth');
2602		var container = isFitWidth ? this.element.parentNode : this.element;
2603		// check that this.size and size are there
2604		// IE8 triggers resize on body size change, so they might not be
2605		var size = getSize(container);
2606		this.containerWidth = size && size.innerWidth;
2607	};
2608
2609	proto._getItemLayoutPosition = function (item) {
2610		item.getSize();
2611		// how many columns does this brick span
2612		var remainder = item.size.outerWidth % this.columnWidth;
2613		var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
2614		// round if off by 1 pixel, otherwise use ceil
2615		var colSpan = Math[mathMethod](item.size.outerWidth / this.columnWidth);
2616		colSpan = Math.min(colSpan, this.cols);
2617		// use horizontal or top column position
2618		var colPosMethod = this.options.horizontalOrder ?
2619			'_getHorizontalColPosition' : '_getTopColPosition';
2620		var colPosition = this[colPosMethod](colSpan, item);
2621		// position the brick
2622		var position = {
2623			x: this.columnWidth * colPosition.col,
2624			y: colPosition.y
2625		};
2626		// apply setHeight to necessary columns
2627		var setHeight = colPosition.y + item.size.outerHeight;
2628		var setMax = colSpan + colPosition.col;
2629		for (var i = colPosition.col; i < setMax; i++) {
2630			this.colYs[i] = setHeight;
2631		}
2632
2633		return position;
2634	};
2635
2636	proto._getTopColPosition = function (colSpan) {
2637		var colGroup = this._getTopColGroup(colSpan);
2638		// get the minimum Y value from the columns
2639		var minimumY = Math.min.apply(Math, colGroup);
2640
2641		return {
2642			col: colGroup.indexOf(minimumY),
2643			y  : minimumY,
2644		};
2645	};
2646
2647	/**
2648	 * @param {Number} colSpan - number of columns the element spans
2649	 * @returns {Array} colGroup
2650	 */
2651	proto._getTopColGroup = function (colSpan) {
2652		if (colSpan < 2) {
2653			// if brick spans only one column, use all the column Ys
2654			return this.colYs;
2655		}
2656
2657		var colGroup = [];
2658		// how many different places could this brick fit horizontally
2659		var groupCount = this.cols + 1 - colSpan;
2660		// for each group potential horizontal position
2661		for (var i = 0; i < groupCount; i++) {
2662			colGroup[i] = this._getColGroupY(i, colSpan);
2663		}
2664		return colGroup;
2665	};
2666
2667	proto._getColGroupY = function (col, colSpan) {
2668		if (colSpan < 2) {
2669			return this.colYs[col];
2670		}
2671		// make an array of colY values for that one group
2672		var groupColYs = this.colYs.slice(col, col + colSpan);
2673		// and get the max value of the array
2674		return Math.max.apply(Math, groupColYs);
2675	};
2676
2677	// get column position based on horizontal index. #873
2678	proto._getHorizontalColPosition = function (colSpan, item) {
2679		var col = this.horizontalColIndex % this.cols;
2680		var isOver = colSpan > 1 && col + colSpan > this.cols;
2681		// shift to next row if item can't fit on current row
2682		col = isOver ? 0 : col;
2683		// don't let zero-size items take up space
2684		var hasSize = item.size.outerWidth && item.size.outerHeight;
2685		this.horizontalColIndex = hasSize ? col + colSpan : this.horizontalColIndex;
2686
2687		return {
2688			col: col,
2689			y  : this._getColGroupY(col, colSpan),
2690		};
2691	};
2692
2693	proto._manageStamp = function (stamp) {
2694		var stampSize = getSize(stamp);
2695		var offset = this._getElementOffset(stamp);
2696		// get the columns that this stamp affects
2697		var isOriginLeft = this._getOption('originLeft');
2698		var firstX = isOriginLeft ? offset.left : offset.right;
2699		var lastX = firstX + stampSize.outerWidth;
2700		var firstCol = Math.floor(firstX / this.columnWidth);
2701		firstCol = Math.max(0, firstCol);
2702		var lastCol = Math.floor(lastX / this.columnWidth);
2703		// lastCol should not go over if multiple of columnWidth #425
2704		lastCol -= lastX % this.columnWidth ? 0 : 1;
2705		lastCol = Math.min(this.cols - 1, lastCol);
2706		// set colYs to bottom of the stamp
2707
2708		var isOriginTop = this._getOption('originTop');
2709		var stampMaxY = (isOriginTop ? offset.top : offset.bottom) +
2710			stampSize.outerHeight;
2711		for (var i = firstCol; i <= lastCol; i++) {
2712			this.colYs[i] = Math.max(stampMaxY, this.colYs[i]);
2713		}
2714	};
2715
2716	proto._getContainerSize = function () {
2717		this.maxY = Math.max.apply(Math, this.colYs);
2718		var size = {
2719			height: this.maxY
2720		};
2721
2722		if (this._getOption('fitWidth')) {
2723			size.width = this._getContainerFitWidth();
2724		}
2725
2726		return size;
2727	};
2728
2729	proto._getContainerFitWidth = function () {
2730		var unusedCols = 0;
2731		// count unused columns
2732		var i = this.cols;
2733		while (--i) {
2734			if (this.colYs[i] !== 0) {
2735				break;
2736			}
2737			unusedCols++;
2738		}
2739		// fit container to columns that have been used
2740		return (this.cols - unusedCols) * this.columnWidth - this.gutter;
2741	};
2742
2743	proto.needsResizeLayout = function () {
2744		var previousWidth = this.containerWidth;
2745		this.getContainerWidth();
2746		return previousWidth != this.containerWidth;
2747	};
2748
2749	return Masonry;
2750
2751}));
2752
2753/*!
2754 * Masonry layout mode
2755 * sub-classes Masonry
2756 * https://masonry.desandro.com
2757 */
2758
2759(function (window, factory) {
2760	// universal module definition
2761	/* jshint strict: false */
2762	/*globals define, module, require */
2763	if (typeof define == 'function' && define.amd) {
2764		// AMD
2765		define('isotope-layout/js/layout-modes/masonry', [
2766				'../layout-mode',
2767				'masonry-layout/masonry'
2768			],
2769			factory);
2770	} else if (typeof module == 'object' && module.exports) {
2771		// CommonJS
2772		module.exports = factory(
2773			require('../layout-mode'),
2774			require('masonry-layout')
2775		);
2776	} else {
2777		// browser global
2778		factory(
2779			window.Isotope.LayoutMode,
2780			window.Masonry
2781		);
2782	}
2783
2784}(window, function factory(LayoutMode, Masonry) {
2785	'use strict';
2786
2787// -------------------------- masonryDefinition -------------------------- //
2788
2789	// create an Outlayer layout class
2790	var MasonryMode = LayoutMode.create('masonry');
2791
2792	var proto = MasonryMode.prototype;
2793
2794	var keepModeMethods = {
2795		_getElementOffset: true,
2796		layout           : true,
2797		_getMeasurement  : true
2798	};
2799
2800	// inherit Masonry prototype
2801	for (var method in Masonry.prototype) {
2802		// do not inherit mode methods
2803		if (!keepModeMethods[method]) {
2804			proto[method] = Masonry.prototype[method];
2805		}
2806	}
2807
2808	var measureColumns = proto.measureColumns;
2809	proto.measureColumns = function () {
2810		// set items, used if measuring first item
2811		this.items = this.isotope.filteredItems;
2812		measureColumns.call(this);
2813	};
2814
2815	// point to mode options for fitWidth
2816	var _getOption = proto._getOption;
2817	proto._getOption = function (option) {
2818		if (option == 'fitWidth') {
2819			return this.options.isFitWidth !== undefined ?
2820				this.options.isFitWidth : this.options.fitWidth;
2821		}
2822		return _getOption.apply(this.isotope, arguments);
2823	};
2824
2825	return MasonryMode;
2826
2827}));
2828
2829/**
2830 * fitRows layout mode
2831 */
2832
2833(function (window, factory) {
2834	// universal module definition
2835	/* jshint strict: false */
2836	/*globals define, module, require */
2837	if (typeof define == 'function' && define.amd) {
2838		// AMD
2839		define('isotope-layout/js/layout-modes/fit-rows', [
2840				'../layout-mode'
2841			],
2842			factory);
2843	} else if (typeof exports == 'object') {
2844		// CommonJS
2845		module.exports = factory(
2846			require('../layout-mode')
2847		);
2848	} else {
2849		// browser global
2850		factory(
2851			window.Isotope.LayoutMode
2852		);
2853	}
2854
2855}(window, function factory(LayoutMode) {
2856	'use strict';
2857
2858	var FitRows = LayoutMode.create('fitRows');
2859
2860	var proto = FitRows.prototype;
2861
2862	proto._resetLayout = function () {
2863		this.x = 0;
2864		this.y = 0;
2865		this.maxY = 0;
2866		this._getMeasurement('gutter', 'outerWidth');
2867	};
2868
2869	proto._getItemLayoutPosition = function (item) {
2870		item.getSize();
2871
2872		var itemWidth = item.size.outerWidth + this.gutter;
2873		// if this element cannot fit in the current row
2874		var containerWidth = this.isotope.size.innerWidth + this.gutter;
2875		if (this.x !== 0 && itemWidth + this.x > containerWidth) {
2876			this.x = 0;
2877			this.y = this.maxY;
2878		}
2879
2880		var position = {
2881			x: this.x,
2882			y: this.y
2883		};
2884
2885		this.maxY = Math.max(this.maxY, this.y + item.size.outerHeight);
2886		this.x += itemWidth;
2887
2888		return position;
2889	};
2890
2891	proto._getContainerSize = function () {
2892		return {height: this.maxY};
2893	};
2894
2895	return FitRows;
2896
2897}));
2898
2899/**
2900 * vertical layout mode
2901 */
2902
2903(function (window, factory) {
2904	// universal module definition
2905	/* jshint strict: false */
2906	/*globals define, module, require */
2907	if (typeof define == 'function' && define.amd) {
2908		// AMD
2909		define('isotope-layout/js/layout-modes/vertical', [
2910				'../layout-mode'
2911			],
2912			factory);
2913	} else if (typeof module == 'object' && module.exports) {
2914		// CommonJS
2915		module.exports = factory(
2916			require('../layout-mode')
2917		);
2918	} else {
2919		// browser global
2920		factory(
2921			window.Isotope.LayoutMode
2922		);
2923	}
2924
2925}(window, function factory(LayoutMode) {
2926	'use strict';
2927
2928	var Vertical = LayoutMode.create('vertical', {
2929		horizontalAlignment: 0
2930	});
2931
2932	var proto = Vertical.prototype;
2933
2934	proto._resetLayout = function () {
2935		this.y = 0;
2936	};
2937
2938	proto._getItemLayoutPosition = function (item) {
2939		item.getSize();
2940		var x = (this.isotope.size.innerWidth - item.size.outerWidth) *
2941			this.options.horizontalAlignment;
2942		var y = this.y;
2943		this.y += item.size.outerHeight;
2944		return {x: x, y: y};
2945	};
2946
2947	proto._getContainerSize = function () {
2948		return {height: this.y};
2949	};
2950
2951	return Vertical;
2952
2953}));
2954
2955/*!
2956 * Isotope v3.0.5
2957 *
2958 * Licensed GPLv3 for open source use
2959 * or Isotope Commercial License for commercial use
2960 *
2961 * https://isotope.metafizzy.co
2962 * Copyright 2017 Metafizzy
2963 */
2964
2965(function (window, factory) {
2966	// universal module definition
2967	/* jshint strict: false */
2968	/*globals define, module, require */
2969	if (typeof define == 'function' && define.amd) {
2970		// AMD
2971		define([
2972				'outlayer/outlayer',
2973				'get-size/get-size',
2974				'desandro-matches-selector/matches-selector',
2975				'fizzy-ui-utils/utils',
2976				'isotope-layout/js/item',
2977				'isotope-layout/js/layout-mode',
2978				// include default layout modes
2979				'isotope-layout/js/layout-modes/masonry',
2980				'isotope-layout/js/layout-modes/fit-rows',
2981				'isotope-layout/js/layout-modes/vertical'
2982			],
2983			function (Outlayer, getSize, matchesSelector, utils, Item, LayoutMode) {
2984				return factory(window, Outlayer, getSize, matchesSelector, utils, Item, LayoutMode);
2985			});
2986	} else if (typeof module == 'object' && module.exports) {
2987		// CommonJS
2988		module.exports = factory(
2989			window,
2990			require('outlayer'),
2991			require('get-size'),
2992			require('desandro-matches-selector'),
2993			require('fizzy-ui-utils'),
2994			require('isotope-layout/js/item'),
2995			require('isotope-layout/js/layout-mode'),
2996			// include default layout modes
2997			require('isotope-layout/js/layout-modes/masonry'),
2998			require('isotope-layout/js/layout-modes/fit-rows'),
2999			require('isotope-layout/js/layout-modes/vertical')
3000		);
3001	} else {
3002		// browser global
3003		window.Isotope = factory(
3004			window,
3005			window.Outlayer,
3006			window.getSize,
3007			window.matchesSelector,
3008			window.fizzyUIUtils,
3009			window.Isotope.Item,
3010			window.Isotope.LayoutMode
3011		);
3012	}
3013
3014}(window, function factory(window, Outlayer, getSize, matchesSelector, utils,
3015                           Item, LayoutMode) {
3016
3017
3018
3019// -------------------------- vars -------------------------- //
3020
3021	var jQuery = window.jQuery;
3022
3023// -------------------------- helpers -------------------------- //
3024
3025	var trim = String.prototype.trim ?
3026		function (str) {
3027			return str.trim();
3028		} :
3029		function (str) {
3030			return str.replace(/^\s+|\s+$/g, '');
3031		};
3032
3033// -------------------------- isotopeDefinition -------------------------- //
3034
3035	// create an Outlayer layout class
3036	var Isotope = Outlayer.create('isotope', {
3037		layoutMode       : 'masonry',
3038		isJQueryFiltering: true,
3039		sortAscending    : true
3040	});
3041
3042	Isotope.Item = Item;
3043	Isotope.LayoutMode = LayoutMode;
3044
3045	var proto = Isotope.prototype;
3046
3047	proto._create = function () {
3048		this.itemGUID = 0;
3049		// functions that sort items
3050		this._sorters = {};
3051		this._getSorters();
3052		// call super
3053		Outlayer.prototype._create.call(this);
3054
3055		// create layout modes
3056		this.modes = {};
3057		// start filteredItems with all items
3058		this.filteredItems = this.items;
3059		// keep of track of sortBys
3060		this.sortHistory = ['original-order'];
3061		// create from registered layout modes
3062		for (var name in LayoutMode.modes) {
3063			this._initLayoutMode(name);
3064		}
3065	};
3066
3067	proto.reloadItems = function () {
3068		// reset item ID counter
3069		this.itemGUID = 0;
3070		// call super
3071		Outlayer.prototype.reloadItems.call(this);
3072	};
3073
3074	proto._itemize = function () {
3075		var items = Outlayer.prototype._itemize.apply(this, arguments);
3076		// assign ID for original-order
3077		for (var i = 0; i < items.length; i++) {
3078			var item = items[i];
3079			item.id = this.itemGUID++;
3080		}
3081		this._updateItemsSortData(items);
3082		return items;
3083	};
3084
3085
3086	// -------------------------- layout -------------------------- //
3087
3088	proto._initLayoutMode = function (name) {
3089		var Mode = LayoutMode.modes[name];
3090		// set mode options
3091		// HACK extend initial options, back-fill in default options
3092		var initialOpts = this.options[name] || {};
3093		this.options[name] = Mode.options ?
3094			utils.extend(Mode.options, initialOpts) : initialOpts;
3095		// init layout mode instance
3096		this.modes[name] = new Mode(this);
3097	};
3098
3099
3100	proto.layout = function () {
3101		// if first time doing layout, do all magic
3102		if (!this._isLayoutInited && this._getOption('initLayout')) {
3103			this.arrange();
3104			return;
3105		}
3106		this._layout();
3107	};
3108
3109	// private method to be used in layout() & magic()
3110	proto._layout = function () {
3111		// don't animate first layout
3112		var isInstant = this._getIsInstant();
3113		// layout flow
3114		this._resetLayout();
3115		this._manageStamps();
3116		this.layoutItems(this.filteredItems, isInstant);
3117
3118		// flag for initalized
3119		this._isLayoutInited = true;
3120	};
3121
3122	// filter + sort + layout
3123	proto.arrange = function (opts) {
3124		// set any options pass
3125		this.option(opts);
3126		this._getIsInstant();
vendor: 11,869 bytes, lines 3127-3578
3127		// filter, sort, and layout
3128
3129		// filter
3130		var filtered = this._filter(this.items);
3131		this.filteredItems = filtered.matches;
3132
3133		this._bindArrangeComplete();
3134
3135		if (this._isInstant) {
3136			this._noTransition(this._hideReveal, [filtered]);
3137		} else {
3138			this._hideReveal(filtered);
3139		}
3140
3141		this._sort();
3142		this._layout();
3143	};
3144	// alias to _init for main plugin method
3145	proto._init = proto.arrange;
3146
3147	proto._hideReveal = function (filtered) {
3148		this.reveal(filtered.needReveal);
3149		this.hide(filtered.needHide);
3150	};
3151
3152	// HACK
3153	// Don't animate/transition first layout
3154	// Or don't animate/transition other layouts
3155	proto._getIsInstant = function () {
3156		var isLayoutInstant = this._getOption('layoutInstant');
3157		var isInstant = isLayoutInstant !== undefined ? isLayoutInstant :
3158			!this._isLayoutInited;
3159		this._isInstant = isInstant;
3160		return isInstant;
3161	};
3162
3163	// listen for layoutComplete, hideComplete and revealComplete
3164	// to trigger arrangeComplete
3165	proto._bindArrangeComplete = function () {
3166		// listen for 3 events to trigger arrangeComplete
3167		var isLayoutComplete, isHideComplete, isRevealComplete;
3168		var _this = this;
3169
3170		function arrangeParallelCallback() {
3171			if (isLayoutComplete && isHideComplete && isRevealComplete) {
3172				_this.dispatchEvent('arrangeComplete', null, [_this.filteredItems]);
3173			}
3174		}
3175
3176		this.once('layoutComplete', function () {
3177			isLayoutComplete = true;
3178			arrangeParallelCallback();
3179		});
3180		this.once('hideComplete', function () {
3181			isHideComplete = true;
3182			arrangeParallelCallback();
3183		});
3184		this.once('revealComplete', function () {
3185			isRevealComplete = true;
3186			arrangeParallelCallback();
3187		});
3188	};
3189
3190	// -------------------------- filter -------------------------- //
3191
3192	proto._filter = function (items) {
3193		var filter = this.options.filter;
3194		filter = filter || '*';
3195		var matches = [];
3196		var hiddenMatched = [];
3197		var visibleUnmatched = [];
3198
3199		var test = this._getFilterTest(filter);
3200
3201		// test each item
3202		for (var i = 0; i < items.length; i++) {
3203			var item = items[i];
3204			if (item.isIgnored) {
3205				continue;
3206			}
3207			// add item to either matched or unmatched group
3208			var isMatched = test(item);
3209			// item.isFilterMatched = isMatched;
3210			// add to matches if its a match
3211			if (isMatched) {
3212				matches.push(item);
3213			}
3214			// add to additional group if item needs to be hidden or revealed
3215			if (isMatched && item.isHidden) {
3216				hiddenMatched.push(item);
3217			} else if (!isMatched && !item.isHidden) {
3218				visibleUnmatched.push(item);
3219			}
3220		}
3221
3222		// return collections of items to be manipulated
3223		return {
3224			matches   : matches,
3225			needReveal: hiddenMatched,
3226			needHide  : visibleUnmatched
3227		};
3228	};
3229
3230	// get a jQuery, function, or a matchesSelector test given the filter
3231	proto._getFilterTest = function (filter) {
3232		if (jQuery && this.options.isJQueryFiltering) {
3233			// use jQuery
3234			return function (item) {
3235				return jQuery(item.element).is(filter);
3236			};
3237		}
3238		if (typeof filter == 'function') {
3239			// use filter as function
3240			return function (item) {
3241				return filter(item.element);
3242			};
3243		}
3244		// default, use filter as selector string
3245		return function (item) {
3246			return matchesSelector(item.element, filter);
3247		};
3248	};
3249
3250	// -------------------------- sorting -------------------------- //
3251
3252	/**
3253	 * @params {Array} elems
3254	 * @public
3255	 */
3256	proto.updateSortData = function (elems) {
3257		// get items
3258		var items;
3259		if (elems) {
3260			elems = utils.makeArray(elems);
3261			items = this.getItems(elems);
3262		} else {
3263			// update all items if no elems provided
3264			items = this.items;
3265		}
3266
3267		this._getSorters();
3268		this._updateItemsSortData(items);
3269	};
3270
3271	proto._getSorters = function () {
3272		var getSortData = this.options.getSortData;
3273		for (var key in getSortData) {
3274			var sorter = getSortData[key];
3275			this._sorters[key] = mungeSorter(sorter);
3276		}
3277	};
3278
3279	/**
3280	 * @params {Array} items - of Isotope.Items
3281	 * @private
3282	 */
3283	proto._updateItemsSortData = function (items) {
3284		// do not update if no items
3285		var len = items && items.length;
3286
3287		for (var i = 0; len && i < len; i++) {
3288			var item = items[i];
3289			item.updateSortData();
3290		}
3291	};
3292
3293	// ----- munge sorter ----- //
3294
3295	// encapsulate this, as we just need mungeSorter
3296	// other functions in here are just for munging
3297	var mungeSorter = (function () {
3298		// add a magic layer to sorters for convienent shorthands
3299		// `.foo-bar` will use the text of .foo-bar querySelector
3300		// `[foo-bar]` will use attribute
3301		// you can also add parser
3302		// `.foo-bar parseInt` will parse that as a number
3303		function mungeSorter(sorter) {
3304			// if not a string, return function or whatever it is
3305			if (typeof sorter != 'string') {
3306				return sorter;
3307			}
3308			// parse the sorter string
3309			var args = trim(sorter).split(' ');
3310			var query = args[0];
3311			// check if query looks like [an-attribute]
3312			var attrMatch = query.match(/^\[(.+)\]$/);
3313			var attr = attrMatch && attrMatch[1];
3314			var getValue = getValueGetter(attr, query);
3315			// use second argument as a parser
3316			var parser = Isotope.sortDataParsers[args[1]];
3317			// parse the value, if there was a parser
3318			sorter = parser ? function (elem) {
3319					return elem && parser(getValue(elem));
3320				} :
3321				// otherwise just return value
3322				function (elem) {
3323					return elem && getValue(elem);
3324				};
3325
3326			return sorter;
3327		}
3328
3329		// get an attribute getter, or get text of the querySelector
3330		function getValueGetter(attr, query) {
3331			// if query looks like [foo-bar], get attribute
3332			if (attr) {
3333				return function getAttribute(elem) {
3334					return elem.getAttribute(attr);
3335				};
3336			}
3337
3338			// otherwise, assume its a querySelector, and get its text
3339			return function getChildText(elem) {
3340				var child = elem.querySelector(query);
3341				return child && child.textContent;
3342			};
3343		}
3344
3345		return mungeSorter;
3346	})();
3347
3348	// parsers used in getSortData shortcut strings
3349	Isotope.sortDataParsers = {
3350		'parseInt'  : function (val) {
3351			return parseInt(val, 10);
3352		},
3353		'parseFloat': function (val) {
3354			return parseFloat(val);
3355		}
3356	};
3357
3358	// ----- sort method ----- //
3359
3360	// sort filteredItem order
3361	proto._sort = function () {
3362		if (!this.options.sortBy) {
3363			return;
3364		}
3365		// keep track of sortBy History
3366		var sortBys = utils.makeArray(this.options.sortBy);
3367		if (!this._getIsSameSortBy(sortBys)) {
3368			// concat all sortBy and sortHistory, add to front, oldest goes in last
3369			this.sortHistory = sortBys.concat(this.sortHistory);
3370		}
3371		// sort magic
3372		var itemSorter = getItemSorter(this.sortHistory, this.options.sortAscending);
3373		this.filteredItems.sort(itemSorter);
3374	};
3375
3376	// check if sortBys is same as start of sortHistory
3377	proto._getIsSameSortBy = function (sortBys) {
3378		for (var i = 0; i < sortBys.length; i++) {
3379			if (sortBys[i] != this.sortHistory[i]) {
3380				return false;
3381			}
3382		}
3383		return true;
3384	};
3385
3386	// returns a function used for sorting
3387	function getItemSorter(sortBys, sortAsc) {
3388		return function sorter(itemA, itemB) {
3389			// cycle through all sortKeys
3390			for (var i = 0; i < sortBys.length; i++) {
3391				var sortBy = sortBys[i];
3392				var a = itemA.sortData[sortBy];
3393				var b = itemB.sortData[sortBy];
3394				if (a > b || a < b) {
3395					// if sortAsc is an object, use the value given the sortBy key
3396					var isAscending = sortAsc[sortBy] !== undefined ? sortAsc[sortBy] : sortAsc;
3397					var direction = isAscending ? 1 : -1;
3398					return (a > b ? 1 : -1) * direction;
3399				}
3400			}
3401			return 0;
3402		};
3403	}
3404
3405	// -------------------------- methods -------------------------- //
3406
3407	// get layout mode
3408	proto._mode = function () {
3409		var layoutMode = this.options.layoutMode;
3410		var mode = this.modes[layoutMode];
3411		if (!mode) {
3412			// TODO console.error
3413			throw new Error('No layout mode: ' + layoutMode);
3414		}
3415		// HACK sync mode's options
3416		// any options set after init for layout mode need to be synced
3417		mode.options = this.options[layoutMode];
3418		return mode;
3419	};
3420
3421	proto._resetLayout = function () {
3422		// trigger original reset layout
3423		Outlayer.prototype._resetLayout.call(this);
3424		this._mode()._resetLayout();
3425	};
3426
3427	proto._getItemLayoutPosition = function (item) {
3428		return this._mode()._getItemLayoutPosition(item);
3429	};
3430
3431	proto._manageStamp = function (stamp) {
3432		this._mode()._manageStamp(stamp);
3433	};
3434
3435	proto._getContainerSize = function () {
3436		return this._mode()._getContainerSize();
3437	};
3438
3439	proto.needsResizeLayout = function () {
3440		return this._mode().needsResizeLayout();
3441	};
3442
3443	// -------------------------- adding & removing -------------------------- //
3444
3445	// HEADS UP overwrites default Outlayer appended
3446	proto.appended = function (elems) {
3447		var items = this.addItems(elems);
3448		if (!items.length) {
3449			return;
3450		}
3451		// filter, layout, reveal new items
3452		var filteredItems = this._filterRevealAdded(items);
3453		// add to filteredItems
3454		this.filteredItems = this.filteredItems.concat(filteredItems);
3455	};
3456
3457	// HEADS UP overwrites default Outlayer prepended
3458	proto.prepended = function (elems) {
3459		var items = this._itemize(elems);
3460		if (!items.length) {
3461			return;
3462		}
3463		// start new layout
3464		this._resetLayout();
3465		this._manageStamps();
3466		// filter, layout, reveal new items
3467		var filteredItems = this._filterRevealAdded(items);
3468		// layout previous items
3469		this.layoutItems(this.filteredItems);
3470		// add to items and filteredItems
3471		this.filteredItems = filteredItems.concat(this.filteredItems);
3472		this.items = items.concat(this.items);
3473	};
3474
3475	proto._filterRevealAdded = function (items) {
3476		var filtered = this._filter(items);
3477		this.hide(filtered.needHide);
3478		// reveal all new items
3479		this.reveal(filtered.matches);
3480		// layout new items, no transition
3481		this.layoutItems(filtered.matches, true);
3482		return filtered.matches;
3483	};
3484
3485	/**
3486	 * Filter, sort, and layout newly-appended item elements
3487	 * @param {Array or NodeList or Element} elems
3488	 */
3489	proto.insert = function (elems) {
3490		var items = this.addItems(elems);
3491		if (!items.length) {
3492			return;
3493		}
3494		// append item elements
3495		var i, item;
3496		var len = items.length;
3497		for (i = 0; i < len; i++) {
3498			item = items[i];
3499			this.element.appendChild(item.element);
3500		}
3501		// filter new stuff
3502		var filteredInsertItems = this._filter(items).matches;
3503		// set flag
3504		for (i = 0; i < len; i++) {
3505			items[i].isLayoutInstant = true;
3506		}
3507		this.arrange();
3508		// reset flag
3509		for (i = 0; i < len; i++) {
3510			delete items[i].isLayoutInstant;
3511		}
3512		this.reveal(filteredInsertItems);
3513	};
3514
3515	var _remove = proto.remove;
3516	proto.remove = function (elems) {
3517		elems = utils.makeArray(elems);
3518		var removeItems = this.getItems(elems);
3519		// do regular thing
3520		_remove.call(this, elems);
3521		// bail if no items to remove
3522		var len = removeItems && removeItems.length;
3523		// remove elems from filteredItems
3524		for (var i = 0; len && i < len; i++) {
3525			var item = removeItems[i];
3526			// remove item from collection
3527			utils.removeFrom(this.filteredItems, item);
3528		}
3529	};
3530
3531	proto.shuffle = function () {
3532		// update random sortData
3533		for (var i = 0; i < this.items.length; i++) {
3534			var item = this.items[i];
3535			item.sortData.random = Math.random();
3536		}
3537		this.options.sortBy = 'random';
3538		this._sort();
3539		this._layout();
3540	};
3541
3542	/**
3543	 * trigger fn without transition
3544	 * kind of hacky to have this in the first place
3545	 * @param {Function} fn
3546	 * @param {Array} args
3547	 * @returns ret
3548	 * @private
3549	 */
3550	proto._noTransition = function (fn, args) {
3551		// save transitionDuration before disabling
3552		var transitionDuration = this.options.transitionDuration;
3553		// disable transition
3554		this.options.transitionDuration = 0;
3555		// do it
3556		var returnValue = fn.apply(this, args);
3557		// re-enable transition for reveal
3558		this.options.transitionDuration = transitionDuration;
3559		return returnValue;
3560	};
3561
3562	// ----- helper methods ----- //
3563
3564	/**
3565	 * getter method for getting filtered item elements
3566	 * @returns {Array} elems - collection of item elements
3567	 */
3568	proto.getFilteredItemElements = function () {
3569		return this.filteredItems.map(function (item) {
3570			return item.element;
3571		});
3572	};
3573
3574	// -----  ----- //
3575
3576	return Isotope;
3577
3578}));

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.